TerraformPilot

Terraform

Introduction to AWS IAM, S3, and DynamoDB for Terraform

Learn the AWS services essential for Terraform — IAM for authentication, S3 for state storage, DynamoDB for state locking. Complete setup guide.

LLuca Berton1 min read

Quick Answer

#

Every Terraform AWS project needs three services: IAM (who can do what), S3 (store state files), and DynamoDB (lock state for team safety). This guide shows how to set up all three.

AWS IAM for Terraform

#

IAM controls who can create, modify, and delete AWS resources.

Create a Terraform IAM User

#
# Create user
aws iam create-user --user-name terraform
 
# Create access keys
aws iam create-access-key --user-name terraform
 
# Attach administrator policy (for dev/learning)
aws iam attach-user-policy \
  --user-name terraform \
  --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

Least-Privilege Policy (Production)

#
data "aws_iam_policy_document" "terraform" {
  # S3 state bucket access
  statement {
    effect = "Allow"
    actions = [
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject",
      "s3:ListBucket",
    ]
    resources = [
      "arn:aws:s3:::my-terraform-state",
      "arn:aws:s3:::my-terraform-state/*",
    ]
  }
 
  # DynamoDB locking
  statement {
    effect = "Allow"
    actions = [
      "dynamodb:GetItem",
      "dynamodb:PutItem",
      "dynamodb:DeleteItem",
    ]
    resources = ["arn:aws:dynamodb:*:*:table/terraform-locks"]
  }
 
  # EC2, VPC, etc. — add per project needs
  statement {
    effect    = "Allow"
    actions   = ["ec2:*", "vpc:*"]
    resources = ["*"]
    condition {
      test     = "StringEquals"
      variable = "aws:RequestedRegion"
      values   = ["us-east-1"]
    }
  }
}

Use IAM Roles (Best Practice)

#
# For CI/CD — use OIDC instead of access keys
resource "aws_iam_role" "terraform_ci" {
  name = "terraform-ci"
 
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = {
        Federated = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/token.actions.githubusercontent.com"
      }
      Action = "sts:AssumeRoleWithWebIdentity"
      Condition = {
        StringEquals = {
          "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
        }
      }
    }]
  })
}

S3 for Terraform State

#

S3 stores your Terraform state file remotely so teams can collaborate.

Create the State Bucket

#
resource "aws_s3_bucket" "state" {
  bucket = "mycompany-terraform-state"
 
  lifecycle {
    prevent_destroy = true
  }
}
 
resource "aws_s3_bucket_versioning" "state" {
  bucket = aws_s3_bucket.state.id
  versioning_configuration {
    status = "Enabled"  # Recover from bad applies
  }
}
 
resource "aws_s3_bucket_server_side_encryption_configuration" "state" {
  bucket = aws_s3_bucket.state.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "aws:kms"
    }
  }
}
 
resource "aws_s3_bucket_public_access_block" "state" {
  bucket                  = aws_s3_bucket.state.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

DynamoDB for State Locking

#

Prevents two people from applying at the same time.

resource "aws_dynamodb_table" "locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"  # No capacity planning needed
  hash_key     = "LockID"
 
  attribute {
    name = "LockID"
    type = "S"
  }
}

Configure the Backend

#
terraform {
  backend "s3" {
    bucket         = "mycompany-terraform-state"
    key            = "production/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

Summary

#
ServicePurposeTerraform Use
IAMAuthentication & authorizationWho can run Terraform
S3Object storageRemote state file storage
DynamoDBKey-value databaseState locking for teams
#

Conclusion

#

Set up IAM with least-privilege policies (not AdministratorAccess), S3 with versioning and encryption for state, and DynamoDB for locking. Use IAM roles with OIDC for CI/CD instead of access keys. This foundation supports safe, team-friendly Terraform workflows.

#Terraform#AWS#Infrastructure as Code#DevOps#IAM

Share this article