How-to

How to Detect Terraform Drift

Detect Terraform drift by refreshing state, saving a plan, and classifying the diff — then add cloud inventory for resources Terraform does not manage. A practical scan loop you can run in CI.

Detect Terraform drift · reference

Detecting Terraform drift means answering one question on a schedule: does live infrastructure still match what this workspace declares?

You do not need a new product to start. You need a refreshed view of state, a saved plan, and a rule for what to do with the diff. What infrastructure drift is is the vocabulary. This page is the scan.

1. Refresh before you compare

A plan against stale state lies.

terraform plan -refresh-only -out=refresh.tfplan
terraform show -json refresh.tfplan

-refresh-only updates Terraform's view of remote objects without proposing configuration changes. If this step fails (permissions, state lock, provider error), stop. A “clean” plan after a failed refresh is not a clean bill of health.

OpenTofu accepts the same flags. Pin the CLI in CI so local laptops are not the detector of record.

2. Save a normal plan as the artefact

terraform plan -out=drift.tfplan
terraform show -no-color drift.tfplan

The plan file — not a screenshot of the terminal — is what you store, diff over time, and attach to a ticket. terraform show -json is what policy engines and custom classifiers should read.

Watch for:

  • in-place updates on security groups, IAM, and encryption flags,
  • destroy/recreate on resources with poor for_each keys (see for_each vs count),
  • noise from tags and computed fields you have already accepted.

3. Classify before anyone “fixes” it

A raw plan is not a drift program. Use a coarse rubric:

Signal in the planTreat as
Ingress, IAM trust, public access, encryption offSecurity-critical
DNS, load balancers, database parametersReliability-critical
Tags, names, sizes within policyHygiene
Known autoscaling / vendor fieldsExpected — do not page

The drift triage playbook covers import vs reconcile vs accept once you have this label.

4. Look for what Terraform cannot see

terraform plan only reasons about addresses in state.

Add a second pass: list security groups, buckets, or IAM roles from the cloud API and subtract objects that have a state address. Leftovers are unmanaged resources — often the most dangerous drift because the next apply will not touch them until someone imports or deletes them.

You do not need to inventory the entire account on day one. Start with the resource types that have burned you.

5. Put the scan on a clock

  • Run refresh + plan on a schedule against the production workspace.
  • Fail the job on provider errors, not only on “changes present.”
  • Open one issue per classified finding, not one issue per resource attribute.
  • Never auto-apply a drift plan unless the change is in an allow-listed, low-risk class.

CI structure for the validate/plan half lives in IaC validation pipelines.

When more than one team shares the account

You still classify, then import, reconcile, or accept. You also need one report and an apply that cannot skip policy. Drift detection and approvals are that loop without a pile of one-off scripts.

FAQ

Is terraform plan enough to detect drift?

A refreshed plan is the right first detector for managed resources. It will miss unmanaged console resources and some computed attributes. Pair it with inventory comparison if those matter.

How often should we scan?

Critical production: often enough that a console change is found before the next human apply — hourly is common. Non-prod can be daily. Continuous is better than a quarterly audit.

Should we auto-apply to fix drift?

Not by default. Auto-apply can undo a deliberate break-glass fix or fight another controller. Classify first, then reconcile through the same approval path you use for normal changes.

Platform evaluation

See OrchesTerra on your infrastructure

Request access to generate architecture from a repository, review the plan, and run governed reconciliation across AWS, Azure, GCP, and OCI.