Skip to main content

Command Palette

Search for a command to run...

Setup S3 backend for Terraform

Updated
3 min read
Setup S3 backend for Terraform

It may happen that you starting working on a Terraform project in a team and local state file doesn’t work for you anymore. Time to a remote backed. It’s not going to be complete documentation. Or better than others. But maybe I’ll manage to hit your needs. If you want more comprehensive documentation - please take a look at “Links” section.

We’re going to use:

  • S3 bucket with versioning and encryption.

  • DynamoDB table for locking.

  • Separate user for backend access.

  • Separate user backend user for each project.

To follow the the guide you gonna need:

  • AWS account. Root or enough privileges to manage users and create resources.

  • aws cli installed.

  • Terraform installed.

You also need to know:

  • The project name.

  • The bucket name. They need to be unique globally. It would be useful to find your favorite name and add a random suffix. Like string generated with the command openssl rand -hex 3. Or - you can read guide mentioned in links.

Creating AWS resources

First - login to you AWS admin account. You can create your bucket now. Adjust your bucket name and region.

aws s3api create-bucket \
  --bucket tf-state-xxxx \
  --region eu-central-1 \
  --create-bucket-configuration LocationConstraint=eu-central-1

Enable bucket versioning.

aws s3api put-bucket-versioning \
  --bucket tf-state-xxxx \
  --versioning-configuration Status=Enabled

Then encryption.

aws s3api put-bucket-encryption \
  --bucket  tf-state-xxxx\
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "AES256"
      }
    }]
  }'

Create DynamoDB table:

aws dynamodb create-table \
  --table-name terraform-locks \
  --attribute-definitions AttributeName=LockID,AttributeType=S \
  --key-schema AttributeName=LockID,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

Create user

Please create a file from following template, replacing bucket name, project name, client id and region. The name used in the example is. projectA-policy.json. Feel free to adjust.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3StateAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::<bucket-name>/<project-name>/*"
    },
    {
      "Sid": "AllowS3ListPrefix",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::<bucket-name>",
      "Condition": {
        "StringLike": {
          "s3:prefix": "<project-name>/*"
        }
      }
    },
    {
      "Sid": "AllowDynamoDBLocking",
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:DeleteItem",
        "dynamodb:UpdateItem"
      ],
      "Resource": "arn:aws:dynamodb:eu-central-1:<client-id>:table/terraform-locks"
    }
  ]
}

create the user:

aws iam create-user --user-name projectA-tfstate

Attach the policy.

aws iam put-user-policy \
  --user-name projectA-tfstate \
  --policy-name projectA-tfstate-policy \
  --policy-document file://projectA-policy.json

Create access key:

aws iam create-access-key --user-name projectA-terraform

Create an aws cli profile.

aws sonfigure --profile projectA-terraform

Start using it

Create a Terraform file. For example backend.tf.

terraform {
  backend "s3" {
    bucket         = "tf-state-xxxx"
    key            = "projectA-terraform/terraform.tfstate"
    region         = "eu-central-1"
    profile        = "projectA-terraform"
    use_lockfile   = true
    encrypt        = true
  }
}

If you’re lucky - you can run terraform init without errors now.

Links

https://developer.hashicorp.com/terraform/language/backend/s3

https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli

https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html

Setup S3 backend for Terraform