A long while ago I wrote about how to configure centralised State Locking for Terraform using Dynamo DB. This configuration has become battle tested and fairly low cost solution for anyone using Terraform in AWS and scales well with pretty advanced configurations but it isn’t without it’s drawbacks. DynamoDB can be a bit confusing to navigate if you’re unfamiliar with it and releasing state locks can be a similarly scary experience so it isn’t uncommon to find a Terraform implementation where state locking has just been neglected (which you really shouldn’t do).
Since the release of Terraform Version 1.10 experimental support for state locking natively inside S3 has been quietly added, with the threat that DynamoDB support is going to be dropped at some point in the future. So let’s have a quick look at how it works.
How Does It Work?
Roughly the same as state locking with DynamoDB. When you perform a plan or apply operation a lock file is created within the same path as your State File with the same name as your State File, suffixed with .tflock. While this file is present no other operations can be made that make any changes to the state, exactly the same as when using DynamoDB.
Configuring Terraform
Configuring Terraform is straight forward and means only a couple of changes to the terraform block as below:
terraform { required_version = "~> 1.10" #--Minimum version 1.10 required_providers { aws = { source = "hashicorp/aws" version = ">= 5.84.0" } } backend "s3" { bucket = "test-states-bucket-tfc" #--S3 Bucket Name key = "example-state.tfstate" #--State file name region = "eu-west-2" encrypt = true use_lockfile = true #--Use native lock file } }
Now when performing a plan or apply operation, a lock file will appear within S3:
In the event that you discover a lock in place and you need to determine who holds the lock, you will need to open the .tflock and investigate it’s contents. The contents are a JSON record of whoever initiated the lock in the same format that you are used to seeing in DynamoDB:
{ "ID": "6b156785-aaaf-3c11-fc54-d0df6154de44", "Operation": "OperationTypeApply", "Info": "", "Who": "welsh@test-box", "Version": "1.10.5", "Created": "2025-01-30T13:14:29.102922Z", "Path": "test-states-bucket-tfc/example-state.tfstate" }
Pesky IAM Permissions
The Account or Role interacting with S3 will need a minimum set of permissions to read and write objects in order to apply the lock. The Terraform documentation does not cover this for S3 State Locking the same as it does for DynamoDB (presumably because S3 permissions can get pretty complicated depending on your configuration) but since it’s a bridge you will probably have to cross here the baseline permissions you will need (assuming you are working inside a single AWS account using regular SSE (Server Side Encryption) or no encryption):
{ "Statement": [ { "Sid": "S3StateLocks" "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Effect": "Allow", "Resource": "arn:aws:s3:::test-states-bucket-tfc/*" } ], "Version": "2012-10-17" }
Simple!