How to Detect Drift Between Terraform Code and Your Cloud Account
Terraform only describes reality if nobody changes things behind its back. In practice, someone raises a quota in the console during an incident, a teammate edits a security group while debugging, and a GPU node pool gets resized by hand. The code and the account drift apart, and the next terraform apply either reverts those changes unexpectedly or fails.
Checking for drift regularly keeps the surprises small.
Step 1: Run a scheduled plan
With -detailed-exitcode, a plan returns 0 when nothing differs, 2 when there are differences and 1 on errors:
terraform init -input=false
terraform plan -detailed-exitcode -lock=false -input=false -out=drift.plan
status=$?
if [ "$status" -eq 2 ]; then
terraform show -no-color drift.plan > drift.txt
./notify-drift.sh drift.txt
fi
Run it nightly from CI for every environment and layer, with a read-only role.
Step 2: Separate drift from pending code changes
terraform plan -refresh-only shows what changed in the cloud compared with the state file, without mixing in code changes that haven't been applied yet. It's useful when pull requests are open and you want to tell the two apart.
Step 3: Send reports to owners
Route drift reports to the team that owns the layer rather than a general channel. Include the resource names and the attributes that changed.
Step 4: Decide what to do with each difference
For every drifted resource, pick one:
- Update the code when the manual change was right, such as a quota increase that should stay.
- Revert the change by applying the code, when the manual change was a temporary experiment.
- Ignore the attribute with
lifecycle { ignore_changes = [...] }when another system legitimately manages it, such as an autoscaler adjusting node counts.
Step 5: Reduce manual changes
Drift is a symptom. Restrict console write access in production accounts, offer a fast pipeline for urgent changes and document a break-glass process for real emergencies.
Things to watch
- Noise. A few attributes that always differ teach people to ignore the report. Fix them or ignore them explicitly.
- Unmanaged resources. A plan can't see resources Terraform never created. Now and then, compare tagged resources in the account with what Terraform knows about.
- Permissions. The drift job only needs read access. Don't give it permission to apply.
Set up the nightly plan for production first, and aim for a clean report with zero differences within a month.