Sanchit Dilip Jain/How to set up a secure Terraform backend using Amazon S3 + DynamoDB? 🛡️

Created Fri, 21 Jul 2023 12:00:00 +0000 Modified Thu, 08 Feb 2024 05:55:04 +0000
623 Words 3 min

How to set up a secure Terraform backend using Amazon S3 + DynamoDB

Introduction

  • Managing infrastructure as code is crucial for modern DevOps practices, and Terraform has emerged as a powerful tool for achieving this. In this technical guide, we will delve into the best practices for configuring a Terraform backend using Amazon Web Services’ S3 bucket and associated resources.
  • Our aim is to equip you with the skills needed to establish a production-ready environment with sensible defaults.

Prerequisites and Setup

  • Installing Terraform and Managing Versions

    • Terraform versions can be efficiently managed using tfenv. This tool allows for the installation of multiple versions and can automatically install a specified version using a .terraform-version file.

    • Alternatively, you can download Terraform directly from the official website. After downloading, unzip the file and place the binary in your system’s path.

    • To verify your Terraform installation, use the command:

      $ terraform version
      
  • Authenticating with AWS

    Before diving into Terraform, ensure you have AWS credentials configured. You can set up your credentials using the AWS CLI with:

    $ aws configure
    
  • Terraform Configuration

    • File Structure

      Organize your Terraform code with logical separations in different .tf files. This enhances clarity and maintainability.

    • Provider Configuration (main.tf)

      Define the AWS provider and its version in a main.tf file. Specify the desired region for resource provisioning.

      terraform {
        required_providers {
          aws = {
            source  = "hashicorp/aws"
            version = "~> 3.0"
          }
        }
      }
      
      provider "aws" {
        region = "us-east-1"
      }
      
    • Setting Up the Backend

      • State Resources Configuration (state.tf)

        • KMS Key and Alias

          Create a KMS key and an alias for encryption purposes. This ensures the security of your Terraform state.

          resource "aws_kms_key" "terraform-bucket-key" {
            description             = "This key is used to encrypt bucket objects"
            deletion_window_in_days = 10
            enable_key_rotation     = true
          }
          
          resource "aws_kms_alias" "key-alias" {
            name          = "alias/terraform-bucket-key"
            target_key_id = aws_kms_key.terraform-bucket-key.key_id
          }
          
        • S3 Bucket

          Set up a secure S3 bucket for storing the Terraform state file. Enable versioning and server-side encryption using the KMS key created earlier.

          resource "aws_s3_bucket" "terraform-state" {
            bucket = "<BUCKET_NAME>"
            acl    = "private"
          
            versioning {
              enabled = true
            }
          
            server_side_encryption_configuration {
              rule {
                apply_server_side_encryption_by_default {
                  kms_master_key_id = aws_kms_key.terraform-bucket-key.arn
                  sse_algorithm     = "aws:kms"
                }
              }
            }
          }
          
        • S3 Bucket Public Access Block

          Prevent public access to the S3 bucket using a public access block.

          resource "aws_s3_bucket_public_access_block" "block" {
            bucket = aws_s3_bucket.terraform-state.id
          
            block_public_acls       = true
            block_public_policy     = true
            ignore_public_acls      = true
            restrict_public_buckets = true
          }
          
        • DynamoDB Table

          Implement a DynamoDB table for state locking to prevent concurrent writes.

          resource "aws_dynamodb_table" "terraform-state" {
            name           = "terraform-state"
            read_capacity  = 20
            write_capacity = 20
            hash_key       = "LockID"
          
            attribute {
              name = "LockID"
              type = "S"
            }
          }
          
      • Backend Configuration (state.tf)

        • Configuring the S3 Backend

          Specify the S3 bucket as the backend for Terraform state storage. Include the necessary configurations, such as encryption and DynamoDB table.

          terraform {
            backend "s3" {
              bucket         = "<BUCKET_NAME>"
              key            = "state/terraform.tfstate"
              region         = "us-east-1"
              encrypt        = true
              kms_key_id     = "alias/terraform-bucket-key"
              dynamodb_table = "terraform-state"
            }
          }
          
    • Applying Terraform Configuration

      • Initializing and Applying Resources

        After configuring the backend, initialize and apply your Terraform configuration.

        $ terraform init
        $ terraform apply
        

        Review the output to ensure you’re comfortable with the planned changes.

    • Migrating to the S3 Backend

      • Updating the Backend

        With your state resources in place, migrate to the S3 backend.

        $ terraform init
        

        Terraform will prompt you to copy the existing state to the new backend. Respond with “yes” to complete the migration.

      • Validating Changes

        After the migration, verify your resources using:

        $ terraform plan
        

Conclusion

  • By following these best practices, you have successfully configured a production-ready Terraform backend using AWS S3 and associated resources.
  • This approach ensures secure state management, robust locking, and efficient infrastructure provisioning.
  • You are now equipped to manage your infrastructure with confidence and maintain optimal DevOps practices.