Skip to content

Store Terraform state in S3

When you finish, every terraform apply for your AWS cluster reads and writes its state in a versioned, encrypted S3 bucket that blocks public access.

S3 locks state with use_lockfile, so you need no DynamoDB table.

Before you start

  • AWS credentials that can create and configure the bucket
  • Terraform 1.11 or later

1. Create a versioned bucket

aws s3 mb s3://my-terraform-state-bucket --region us-east-1

aws s3api put-bucket-versioning \
  --bucket my-terraform-state-bucket \
  --versioning-configuration Status=Enabled

The first command prints make_bucket: my-terraform-state-bucket, and the bucket keeps every prior revision of your state.

2. Point Terraform at the bucket

terraform {
  backend "s3" {
    bucket       = "my-terraform-state-bucket" # <-- Replace with your bucket name
    key          = "qumulo/aws/prod.tfstate"   # <-- Replace with your path in the bucket
    region       = "us-east-1"                 # <-- Replace with your bucket region
    use_lockfile = true
    encrypt      = true
  }
}

Run terraform init -upgrade. If local state already exists, Terraform offers to migrate it into the bucket.

The output ends with Successfully configured the backend "s3"!

3. Lock down the bucket

Encrypt everything in the bucket with SSE-S3.

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

Block every form of public access.

aws s3api put-public-access-block \
  --bucket my-terraform-state-bucket \
  --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

Confirm that versioning is on.

aws s3api get-bucket-versioning --bucket my-terraform-state-bucket

The output includes "Status": "Enabled".

Next

Deploy your cluster with the basic AWS cluster example. When you need another backend option, see the Terraform s3 backend reference.