Skip to main content

Module: tfstate-backend

Terraform module to provision an S3 bucket to store terraform.tfstate file and a DynamoDB table to lock the state file to prevent concurrent modifications and state corruption.

The module supports the following:

  1. Forced server-side encryption at rest for the S3 bucket
  2. S3 bucket versioning to allow for Terraform state recovery in the case of accidental deletions and human errors
  3. State locking and consistency checking via DynamoDB table to prevent concurrent operations
  4. DynamoDB server-side encryption

https://www.terraform.io/docs/backends/types/s3.html

NOTE: The operators of the module (IAM Users) must have permissions to create S3 buckets and DynamoDB tables when performing terraform plan and terraform apply

NOTE: This module cannot be used to apply changes to the mfa_delete feature of the bucket. Changes regarding mfa_delete can only be made manually using the root credentials with MFA of the AWS Account where the bucket resides. Please see: https://github.com/terraform-providers/terraform-provider-aws/issues/629

Usage

Create

Follow this procedure just once to create your deployment.

  1. Add the terraform_state_backend module to your main.tf file. The comment will help you remember to follow this procedure in the future:

    # You cannot create a new backend by simply defining this and then
    # immediately proceeding to "terraform apply". The S3 backend must
    # be bootstrapped according to the simple yet essential procedure in
    # https://github.com/cloudposse/terraform-aws-tfstate-backend#usage
    module "terraform_state_backend" {
    source = "cloudposse/tfstate-backend/aws"
    # Cloud Posse recommends pinning every module to a specific version
    # version = "x.x.x"
    namespace = "eg"
    stage = "test"
    name = "terraform"
    attributes = ["state"]

    terraform_backend_config_file_path = "."
    terraform_backend_config_file_name = "backend.tf"
    force_destroy = false
    }

    # Your Terraform configuration
    module "another_module" {
    source = "....."
    }

    Module inputs terraform_backend_config_file_path and terraform_backend_config_file_name control the name of the backend definition file. Note that when terraform_backend_config_file_path is empty (the default), no file is created.

  2. terraform init. This downloads Terraform modules and providers.

  3. terraform apply -auto-approve. This creates the state bucket and DynamoDB locking table, along with anything else you have defined in your *.tf file(s). At this point, the Terraform state is still stored locally.

    Module terraform_state_backend also creates a new backend.tf file that defines the S3 state backend. For example:

    backend "s3" {
    region = "us-east-1"
    bucket = "< the name of the S3 state bucket >"
    key = "terraform.tfstate"
    dynamodb_table = "< the name of the DynamoDB locking table >"
    profile = ""
    role_arn = ""
    encrypt = true
    }

    Henceforth, Terraform will also read this newly-created backend definition file.

  4. terraform init -force-copy. Terraform detects that you want to move your Terraform state to the S3 backend, and it does so per -auto-approve. Now the state is stored in the S3 bucket, and the DynamoDB table will be used to lock the state to prevent concurrent modification.

This concludes the one-time preparation. Now you can extend and modify your Terraform configuration as usual.

Destroy

Follow this procedure to delete your deployment.

  1. In main.tf, change the terraform_state_backend module arguments as follows:
     module "terraform_state_backend" {
    # ...
    terraform_backend_config_file_path = ""
    force_destroy = true
    }
  2. terraform apply -target module.terraform_state_backend -auto-approve. This implements the above modifications by deleting the backend.tf file and enabling deletion of the S3 state bucket.
  3. terraform init -force-copy. Terraform detects that you want to move your Terraform state from the S3 backend to local files, and it does so per -auto-approve. Now the state is once again stored locally and the S3 state bucket can be safely deleted.
  4. terraform destroy. This deletes all resources in your deployment.
  5. Examine local state file terraform.tfstate to verify that it contains no resources.

s3-bucket-with-terraform-state

Bucket Replication (Disaster Recovery)

To enable S3 bucket replication in this module, set s3_replication_enabled to true and populate s3_replica_bucket_arn with the ARN of an existing bucket.

module "terraform_state_backend" {
source = "cloudposse/tfstate-backend/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
namespace = "eg"
stage = "test"
name = "terraform"
attributes = ["state"]

terraform_backend_config_file_path = "."
terraform_backend_config_file_name = "backend.tf"
force_destroy = false

s3_replication_enabled = true
s3_replica_bucket_arn = "arn:aws:s3:::eg-test-terraform-tfstate-replica"
}