In this article we are going to cover Preventing Terraform Drift & Manual Changes in Terraform State File.
Terraform drift is one of the most common challenges faced in Infrastructure as Code (IaC) workflows. It occurs when the actual infrastructure differs from the expected state defined in Terraform configuration files. The most common cause? Manual changes made through the cloud console, CLI, or SDKs.
In this article, we’ll explore how to detect drift, gain insights from your Terraform state, and most importantly—prevent manual changes using IAM policies.
Table of Contents
Why Terraform Drift is Dangerous
- Breaks reproducibility
- Causes errors during future
terraform apply
- Makes debugging harder
- Can open up security vulnerabilities
Tips to Prevent & Detect Drift in Terraform State File
#1.Run terraform plan Frequently
terraform plan
shows what changes Terraform will make. Running it often (in CI/CD or manually) helps catch drift early.
terraform plan

This lets you compare the current infrastructure with your Terraform code.
#2.Use terraform state list & terraform state show
List All Resources Terraform Manages:
terraform state list

Show Details of a Specific Resource:
terraform state show <resource_type>.<resource_name>

This command displays the state of a resource as Terraform understands it. It’s great for debugging drift and reviewing infrastructure metadata.
#3.Enforce IAM Policies to Block Manual Changes
The best way to prevent drift? Block manual changes altogether—using IAM policies.
Step #1:Create a Terraform-Only IAM Role
Allow only this role to manage S3 buckets via Terraform
Instructions:
- Go to IAM > Roles in AWS Console.
- Click Create role.
- Choose AWS service > EC2 / Lambda / CodeBuild (depending on Terraform runner).
- Attach
AmazonS3FullAccess
(or custom limited policy). - Name it
terraform-role
.

Step #2:Create a Deny Policy for Manual S3 Changes
This IAM policy explicitly denies S3 changes unless the caller is terraform-role
.
Deny Policy JSON:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyS3ChangesOutsideTerraformRole",
"Effect": "Deny",
"Action": [
"s3:PutBucketPolicy",
"s3:DeleteBucket",
"s3:PutBucketAcl",
"s3:PutEncryptionConfiguration",
"s3:PutLifecycleConfiguration",
"s3:PutBucketVersioning",
"s3:PutBucketLogging",
"s3:PutBucketPublicAccessBlock"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "<arn of the terraform-role>"
}
}
}
]
}
You can add/remove actions as needed to suit your security requirements.
Step #3:Attach the Deny Policy to IAM Users/Groups
Apply this deny policy to:
- All IAM users with Console/CLI access
- IAM groups (e.g., developers, admins)
- Service accounts (if applicable)
How to:
- Go to IAM > Policies → Create Policy → JSON tab → paste the deny policy.
- Name it something like
DenyS3ManualChanges
. - Attach it to:
- All IAM users/groups except Terraform
- You can also use an IAM Permission Boundary

Step #4:Test It
- Log in as a user not assuming the Terraform role.
- Try to delete or change an S3 bucket (via console or CLI).
- You should get an AccessDenied error.

Bonus Tips
- Tag resources with
ManagedBy = Terraform
and restrict changes via tag-based IAM conditions. - Use AWS Organizations Service Control Policies (SCPs) for org-wide enforcement.
- Rotate and secure Terraform IAM credentials.
- Use
terraform-provider-aws
with assume-role setups for more secure deployments.
Conclusion:
Preventing drift is essential for maintaining stable, predictable infrastructure. By combining regular Terraform checks (plan
, state show
), visibility tools, and strict IAM policies, you can safeguard your cloud environments from unauthorized manual changes.
Related Articles:
Terraform State File Corruption Recovery
Reference:
terraform State Restoration Overview
Sharing is Caring: