Stage 4 · Provision
Terraform State Operations
Remote Backends & Locking
S3, Azure Storage, GCS, Terraform Cloud, DynamoDB locks, and lease recovery — the infrastructure behind Terraform state.
Backend Overview
A backend determines where Terraform stores state and how it handles locking. The choice of backend affects performance, security, and team collaboration. Every remote backend provides state storage, versioning, and encryption.
| Backend | Locking | Versioning | Encryption |
|---|---|---|---|
| S3 | DynamoDB | Versioning | SSE or KMS |
| Azure Storage | Blob Leases | Blob versioning | Azure encryption |
| GCS | Native | Object versioning | Google encryption |
| Terraform Cloud | Native | Built-in | Built-in |
S3 Backend
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/vpc/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
kms_key_id = "alias/terraform-state"
}
}The S3 backend stores state in an S3 bucket with server-side encryption. The dynamodb_table provides state locking. The kms_key_id specifies a custom KMS key for encryption. The key parameter defines the state file path.
resource "aws_s3_bucket" "terraform_state" {
bucket = "my-terraform-state"
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.terraform.arn
}
}
}
resource "aws_s3_bucket_public_access_block" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}The S3 bucket has versioning enabled for state file history, KMS encryption for security, and public access blocked. These settings are essential for a secure state backend.
Azure Storage Backend
terraform {
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "tfstate"
container_name = "tfstate"
key = "prod/vpc/terraform.tfstate"
use_azuread_auth = true
}
}
# Storage account setup
resource "azurerm_storage_account" "tfstate" {
name = "tfstate"
resource_group_name = azurerm_resource_group.tfstate.name
location = azurerm_resource_group.tfstate.location
account_tier = "Standard"
account_replication_type = "GRS"
blob_properties {
versioning_enabled = true
}
}The Azure Storage backend stores state in a Blob Storage container. use_azuread_auth uses Azure AD for authentication instead of access keys. Blob versioning provides state file history.
GCS Backend
terraform {
backend "gcs" {
bucket = "my-terraform-state"
prefix = "prod/vpc"
}
}
# GCS bucket setup
resource "google_storage_bucket" "terraform_state" {
name = "my-terraform-state"
location = "US"
versioning {
enabled = true
}
encryption {
default_kms_key_name = google_kms_crypto_key.terraform.id
}
}The GCS backend stores state in a Google Cloud Storage bucket. The prefix parameter provides a path-like namespace. Versioning and encryption are configured on the bucket.
Terraform Cloud
terraform {
cloud {
organization = "my-org"
workspaces {
name = "my-app-prod"
}
}
}
# Or use the traditional backend
terraform {
backend "remote" {
hostname = "app.terraform.io"
organization = "my-org"
workspaces {
name = "my-app-prod"
}
}
}Terraform Cloud manages state, locking, and run history. The workspace name maps to a specific state file. Terraform Cloud provides a UI for viewing state, run history, and policy results.
Locking Mechanisms
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
point_in_time_recovery {
enabled = true
}
}DynamoDB provides locking for the S3 backend. PAY_PER_REQUEST avoids capacity planning. The LockID attribute stores the lock information. Point-in-time recovery provides backup for the lock table.
$ terraform force-unlock LOCK_ID
# Find the lock ID from the error message
# Error: Error acquiring the state lock
# Error message: ConditionalCheckFailedException
# Lock Info:
# ID: abc-123-def
# Path: s3://my-terraform-state/prod/vpc/terraform.tfstate
# Operation: OperationTypeApply
# Who: user@machine
# Version: 1.5.0
# Created: 2024-01-15 10:00:00 +0000 UTCThe error message shows the lock ID, who acquired it, and when. Only use force-unlock when you are certain no other process is running. The lock info helps you verify the lock is stale before unlocking.
S3 versioning, Azure blob versioning, and GCS versioning provide rollback capability for state files. If a state file is corrupted, you can restore from a previous version. Always enable versioning on state storage.
Deleting a state file is irreversible. Use versioning and backups instead. If you need to remove a state file, use terraform state rm to remove resources from state without deleting the file.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.