Terraform Fundamentals - Backends
Learn how to configure and use Terraform backends such as S3 and DynamoDB with encryption and state locking enabled.
One of the most important aspects of working with Terraform is understanding where and how the Terraform state is stored. This is the job of a backend.
In simple terms, a backend in Terraform is the mechanism that determines where the state file is located and how it is loaded. Every Terraform project uses a backend by default, many don't realize it because Terraform silently uses the local backend unless another is specified. That means the state file is saved to local machine as terraform.tfstate
. This works fine for learning and small experiments, but it quickly becomes risky and unmanageable in real-world or team-based infrastructure deployments.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.
Backends are configured using a dedicated block within the terraform
configuration. For example, to use AWS S3 as a backend, a typical configuration would look like this:
terraform {
backend "s3" {
bucket = "redteam-terraform-state"
key = "global/s3/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "redteam-terraform-locks"
encrypt = true
}
}
Note: Terraform must already have access to the backend resources such as S3, DynamoDB etc. when it initializes. These can be setup manually or via Terraform as a separate project.
After declaring this configuration, it must be initialized with terraform init
, which connects Terraform to the specified backend and migrates any existing state if necessary. Once this is done, Terraform will read and write state to that remote location, ensuring that every change is recorded and accessible from anywhere—an essential feature for team collaboration and consistency.
Note: When using a remote backend like S3, Terraform will create a file named
.terraform/terraform.tfstate
locally — but this is not the real state file. Instead, it stores metadata about the backend configuration (such as the S3 bucket, region, key, and lock table). The actual state of the infrastructure — including all deployed resources — is stored in the remote S3 location defined in your backend block.
If you notice in the above example, I have also used dynamodb_table
. This is because remote backends also introduce the concept of state locking.
State locking is a mechanism that prevents multiple people or processes from making changes to the same Terraform state file at the same time. When someone runs a Terraform command like apply
, the state is locked, meaning no one else can run conflicting operations until it's finished. Without state locking, if two users try to update the infrastructure simultaneously, they could overwrite each other's changes or corrupt the state file — which can break the entire environment.
We can use DynamoDB for locking when configured with a remote backend like S3. It creates a temporary lock entry before making changes and deletes it afterward. This simple safety check ensures that changes to infrastructure are made one at a time, reducing the risk of conflicts or outages. Without this, we could end up with race conditions or corrupted state files.
The choice of backend also impacts security. When using local state, anyone with access to the machine can view or modify the state file, which can contain sensitive data like passwords, cloud credentials, or generated secrets. Remote backends like S3 offer encryption at rest and access control via IAM, which means only authorized users and services can view or modify the state. It's good practice to enable server-side encryption (encrypt = true
), use private buckets, and apply least-privilege IAM policies.
Note: Setting
encrypt = true
in backend configuration enables server-side encryption (SSE-S3) for the Terraform state file in S3. However, when viewing the file in the S3 console or downloading it, you may still see the contents in plain text. This is expected — AWS automatically decrypts the file for authorized users. If stricter controls are needed, consider enabling SSE-KMS with a custom KMS key for fine-grained access and audit logging.
From a red team perspective, backends are a double-edged sword. On one hand, using a remote backend like S3 with locking makes operations safer, more secure, and auditable. On the other hand, if the backend itself is misconfigured or compromised, it becomes a single point of failure—or opportunity. For example, if an attacker gains access to an unprotected S3 bucket containing state files, they might extract credentials or environment structure details that could aid in lateral movement or privilege escalation. Similarly, a misconfigured DynamoDB lock table could allow for simultaneous execution, breaking the expected behavior of the infrastructure deployment.
For red team operators building and tearing down cloud infrastructure for operations, using remote backends is often the right balance of scalability, safety, and control. It allows for multiple campaign environments to be managed reliably. When paired with Terraform workspaces, remote backends allow for environment-specific state management without duplicating code.
Here is the Terraform Hello World project configured to use AWS S3 and DynamoDB. This project also includes a separate Terraform project (bootstrap-backend) to provision the required backend services, S3 and DynamoDB.
Following permissions need to be added to the
TerraformEC2Access
IAM policy before using the above mentioned projects:
s3:PutBucketTagging
dynamodb:CreateTable
s3:PutBucketVersioning
dynamodb:TagResource
dynamodb:DescribeTable
s3:PutEncryptionConfiguration
dynamodb:DescribeTimeToLive
dynamodb:DescribeContinuousBackups
dynamodb:ListTagsOfResource
dynamodb:DeleteTable
dynamodb:PutItem
dynamodb:GetItem
dynamodb:DeleteItem
TL;DR
- Terraform backends determine where and how Terraform stores its state file. - - By default, Terraform uses a local backend, but for team collaboration and long-term infrastructure reliability, remote backends like AWS S3 are recommended.
- Remote backends support features like encryption, access control, and state locking via DynamoDB.
- State locking is a mechanism that prevents multiple people or processes from making changes to the same Terraform state file at the same time.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.