Skip to main content
Introduction to AWS IAM, S3, and DynamoDB for Terraform

Introduction to AWS IAM, S3, and DynamoDB for Terraform

Key Takeaway

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

Table of Contents

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.

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.