Terraform Backend State Infrastructure

Complete AWS infrastructure setup for storing Terraform state files remotely using S3 with versioning, encryption, and file-based locking

Project Banner

Project Overview

This directory contains Terraform configuration to provision the AWS infrastructure needed to store Terraform state files remotely. This includes an S3 bucket for state storage with file-based locking.

What Gets Created

Key Features

Prerequisites

Required Accounts and Services

GitHub Repository Configuration

Required Secrets

Configure these at: Repository → Settings → Secrets and variables → Actions → Secrets

Required Variables

Configure these at: Repository → Settings → Secrets and variables → Actions → Variables

Terraform Variables

Configure these required variables in variables.tfvars before running:

Variable Type Description Example
env string Deployment environment identifier "prod", "dev", "staging"
region string AWS region for resource deployment "us-east-1", "us-west-2"
prefix string Prefix added to all resource names for identification "mycompany-tf", "project-name"

Configuration

AWS IAM Setup

Step 1: Create OIDC Identity Provider

  1. Navigate to AWS IAM Console → Identity providers (left sidebar)
  2. Click Add provider
  3. Select OpenID Connect
  4. Provider URL: https://token.actions.githubusercontent.com
  5. Click Get thumbprint (AWS will automatically fetch GitHub's certificate thumbprint)
  6. Audience: sts.amazonaws.com
  7. Click Add provider

Step 2: Create IAM Role

  1. Navigate to AWS IAM Console → Roles (left sidebar)
  2. Click Create role
  3. Under Trusted entity type, select Web identity
  4. Under Web identity, select the Identity Provider: token.actions.githubusercontent.com
  5. Audience: Select sts.amazonaws.com from the dropdown
  6. Click Add condition to restrict which repositories can assume this role:
    • Condition key: token.actions.githubusercontent.com:sub
    • Operator: StringLike
    • Value: repo:YOUR_ORG/YOUR_REPO:* (replace with your GitHub organization and repository name)
  7. Add permissions: Create or attach a policy with S3 permissions for the state bucket
  8. Name the role: github-actions-state-role (or your preferred name)
  9. Click Create role
  10. Copy the Role ARN and set it as AWS_STATE_ACCOUNT_ROLE_ARN GitHub secret

Step 3: S3 Bucket Policy (Automatic)

The bucket policy in main.tf automatically uses the current caller's ARN via data.aws_caller_identity.current.arn. No configuration needed!

Local Execution Prerequisites

For local development or testing, ensure you have:

Getting Started

Option 1: GitHub Actions (Recommended)

This is the recommended approach as it handles state file upload automatically.

⚠️ Note: GitHub Actions workflows retrieve the role ARN directly from GitHub repository secrets (AWS_STATE_ACCOUNT_ROLE_ARN). This differs from local script execution, which uses AWS Secrets Manager.

Provisioning (Create Infrastructure)

Step 1: Configure Variables

Edit variables.tfvars with your values:

env    = "prod"
region = "us-east-1"
prefix = "mycompany-tf"

Commit and push the changes.

Step 2: Run the Workflow

  1. Go to GitHub → Actions tab
  2. Select "TF Backend State Provisioning" workflow
  3. Click "Run workflow""Run workflow"

The workflow will:

  • Validate Terraform configuration
  • Create the S3 bucket
  • Save the bucket name as a repository variable
  • Upload the state file to S3

Destroying (Remove Infrastructure)

  1. Go to GitHub → Actions tab
  2. Select "TF Backend State Destroying" workflow
  3. Click "Run workflow""Run workflow"

⚠️ Warning: This permanently deletes the S3 bucket.

Option 2: Local Execution

For local development or testing, use the provided automation scripts. These scripts handle role assumption, Terraform operations, state file management, and repository variable updates automatically.

⚠️ IMPORTANT:

Provisioning (Create Infrastructure)

Use the set-state.sh script to provision infrastructure and upload the state file:

cd tf_backend_state
./set-state.sh

What the script does automatically:

  1. Retrieves AWS_STATE_ACCOUNT_ROLE_ARN from AWS Secrets Manager (secret 'github-role', key 'AWS_STATE_ACCOUNT_ROLE_ARN')
  2. Retrieves AWS_REGION from GitHub repository variables (defaults to us-east-1)
  3. Retrieves BACKEND_PREFIX from GitHub repository variables
  4. Assumes the IAM role with temporary credentials
  5. Checks if infrastructure already exists:
    • If not exists: Runs terraform init, validate, plan, and apply
    • If exists: Downloads existing state file from S3 (if available)
  6. Saves bucket name to GitHub repository variable BACKEND_BUCKET_NAME
  7. Uploads terraform.tfstate to S3 (only if infrastructure was just provisioned)

Downloading Existing State File

If you need to download the state file from S3 (e.g., after running via GitHub Actions), use the get-state.sh script:

cd tf_backend_state
./get-state.sh

What the script does automatically:

  1. Retrieves AWS_STATE_ACCOUNT_ROLE_ARN from AWS Secrets Manager (secret 'github-role', key 'AWS_STATE_ACCOUNT_ROLE_ARN')
  2. Retrieves AWS_REGION from GitHub repository variables (defaults to us-east-1)
  3. Assumes the IAM role with temporary credentials
  4. Retrieves BACKEND_BUCKET_NAME and BACKEND_PREFIX from GitHub repository variables
  5. Downloads terraform.tfstate from S3 if it exists

Destroying Infrastructure

To destroy the infrastructure, use Terraform directly (after downloading the state file if needed):

cd tf_backend_state

# Download state file if needed
./get-state.sh

# Destroy infrastructure
terraform plan -var-file="variables.tfvars" -destroy -out terraform.tfplan
terraform apply -auto-approve terraform.tfplan

⚠️ Warning: This permanently deletes the S3 bucket and all resources.

Architecture

State File Management

After Provisioning

State File Location

Resource Naming

Security Architecture

Authentication Flow

Access Control

Security Considerations

Key Security Features

Best Practices

Important Notes

Troubleshooting

Common Issues

"Resource not accessible by integration" error

"Access Denied" when accessing S3

OIDC Authentication Issues

AWS Secrets Manager Issues (Local Scripts)

Bucket name conflicts

State file not found during destroy

Support & Resources

Documentation

README

Complete project documentation with setup instructions and usage guide

CHANGELOG

All notable changes to the project, organized by version

Quick Reference

Action Command/Workflow
Provision infrastructure (GitHub Actions) Run "TF Backend State Provisioning" workflow
Provision infrastructure (Local) ./set-state.sh
Download state file ./get-state.sh
Destroy infrastructure (GitHub Actions) Run "TF Backend State Destroying" workflow
Destroy infrastructure (Local) terraform plan -destroy then terraform apply
View current AWS identity aws sts get-caller-identity

Repository

GitHub Repository: talorlik/tf_backend_state

License

This project is licensed under the MIT License.

See the LICENSE file for details.