DEV Community

Cover image for Terraform State File Management with AWS S3 | Remote Backend
Adarsh Gupta
Adarsh Gupta

Posted on • Edited on

Terraform State File Management with AWS S3 | Remote Backend

Managing Terraform state securely is a critical part of Infrastructure as Code. When working in teams or managing multiple environments, storing state locally becomes unreliable, unsafe, and difficult to collaborate on. AWS S3 provides a durable, secure, and highly available backend for storing Terraform state files, and with recent updates, Terraform now supports native S3 state locking without DynamoDB.

This guide explains how Terraform state works, why remote backends are necessary, how S3 state locking works, and how to configure an S3 bucket with versioning and encryption to store Terraform state files.

How Terraform Updates Infrastructure

Terraform maintains a state file called terraform.tfstate. This file represents the current state of all resources managed by Terraform. Every terraform plan or terraform apply compares:

• The desired state defined in your configuration
• The actual state stored in the state file

Terraform updates only the resources whose configurations have changed.

Terraform State File Details

The state file contains:

• Resource metadata and attributes
• Provider configurations
• Resource dependencies
• Output values
• Sensitive resource details

Because of the sensitive data stored inside it, state files must be handled carefully.

State File Best Practices

• Never edit the state file manually
• Store state in a remote backend
• Enable state locking
• Regularly back up state files
• Use separate state files for dev, test, and prod
• Restrict access to state storage
• Enable encryption

Why Remote Backends Matter

Remote backends such as Amazon S3 offer:

• Collaboration with shared state
• State locking to prevent simultaneous changes
• Encryption for security
• Versioning for backups
• High availability and durability

Local state files cannot provide these features.

AWS S3 as a Remote Backend

Terraform supports S3 as a backend for storing state files. The backend configuration lives inside the terraform block and instructs Terraform where to store the state.

Backend example:

terraform {
  backend "s3" {
    bucket       = "adarsh-s3-statefile-bucket-1"
    key          = "dev/terraform.tfstate"
    region       = "ap-south-1"
    encrypt      = true
    use_lockfile = true
  }
}
Enter fullscreen mode Exit fullscreen mode

Important note: The backend block cannot create the S3 bucket. It must already exist before terraform init is executed.

S3 Native State Locking

Terraform 1.10 introduced native state locking using S3 itself, removing the need for DynamoDB tables. S3 uses conditional writes to create a lock file (.tflock). If the file exists, Terraform blocks concurrent operations.

This reduces complexity, saves cost, and simplifies backend setup.

Testing S3 State Locking

Terminal 1:

terraform apply
Enter fullscreen mode Exit fullscreen mode

Terminal 2:

terraform plan
Enter fullscreen mode Exit fullscreen mode

Expected output:

Error acquiring the state lock.
StatusCode: 412

A .tflock object appears in the S3 bucket and is removed when the operation completes.

Complete Terraform Configuration

Below is the Terraform configuration used to deploy a VPC and an S3 bucket, while storing the Terraform state file in an S3 backend.

terraform {
  backend "s3" {
    bucket       = "adarsh-s3-statefile-bucket-1"
    key          = "dev/terraform.tfstate"
    region       = "ap-south-1"
    encrypt      = true
    use_lockfile = true
  }

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

provider "aws" {
  region = "ap-south-1"
}

resource "aws_vpc" "main_vpc" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name        = "main_vpc"
    Environment = "Dev"
  }
}

resource "aws_s3_bucket" "bucket1" {
  bucket = "bucket12345-${aws_vpc.main_vpc.id}"

  tags = {
    Name        = "bucket1"
    VpcLinkedTo = aws_vpc.main_vpc.id
  }
}

output "resource_ids" {
  value = {
    vpc_id       = aws_vpc.main_vpc.id
    s3_bucket_id = aws_s3_bucket.bucket1.id
  }
}
Enter fullscreen mode Exit fullscreen mode

This configuration demonstrates:

• A remote backend for Terraform state
• S3 native state locking
• A VPC resource
• An S3 bucket with an implicit dependency on the VPC

Useful State Commands

List resources:

terraform state list
Enter fullscreen mode Exit fullscreen mode

View resource state:

terraform state show <resource>
Enter fullscreen mode Exit fullscreen mode

Remove from state:

terraform state rm <resource>
Enter fullscreen mode Exit fullscreen mode

Move resources:

terraform state mv <source> <destination>
Enter fullscreen mode Exit fullscreen mode

Pull raw state:

terraform state pull
Enter fullscreen mode Exit fullscreen mode

Verifying S3 Configuration

Check versioning:

aws s3api get-bucket-versioning --bucket your-bucket
Enter fullscreen mode Exit fullscreen mode

Check encryption:

aws s3api get-bucket-encryption --bucket your-bucket
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Terraform state management is a foundational skill for any Infrastructure as Code workflow. Using AWS S3 for storing state provides a secure, collaborative, and resilient backend. With the arrival of S3 native state locking, the process is simpler and more efficient than ever.

Reference Video


@piyushsachdeva

Top comments (0)