Terraform Drift Detection

A boat tied to a dock slowly drifts when the wind pushes it and nobody notices. Infrastructure drifts in a similar way. Someone changes a firewall rule in the cloud console during an urgent fix. Nobody updates the Terraform code. The real world no longer matches the plan on paper. That gap is called drift. Finding drift early prevents confusing outages and surprise changes.

What Causes Drift

  • A teammate edits a resource in the cloud console.
  • A script or another tool changes a setting.
  • The cloud provider adjusts a value automatically.
  • An emergency fix never reaches the code afterward.

The Three-Way Comparison

Terraform tracks three versions of the truth. Drift appears when they disagree.

Diagram: Three Sources of Truth

+----------------+     +----------------+     +------------------+
| 1. Your Code   |     | 2. State File  |     | 3. Real Cloud    |
| (what you want)|     | (what Terraform|     | (what exists now)|
|                |     |  remembers)    |     |                  |
+-------+--------+     +--------+-------+     +---------+--------+
        |                       |                       |
        +-----------+-----------+-----------+-----------+
                    |                       |
              compare all three during terraform plan
                    |
            Differences = drift

How a Normal Plan Reveals Drift

Every terraform plan refreshes the state first. Terraform asks the cloud for the current value of each resource and compares the answer with the code. A mismatch appears in the output.

aws_security_group.web has changed outside of Terraform

  ~ ingress {
      ~ cidr_blocks = ["10.0.0.0/16"] -> ["0.0.0.0/0"]
    }

The message tells you exactly which setting changed and who needs a conversation.

Refresh-Only Mode

Sometimes you want to see drift without proposing infrastructure changes. Refresh-only mode does exactly that.

terraform plan -refresh-only

The output lists differences between the state and the real cloud and says nothing about your code. Approve the update with:

terraform apply -refresh-only

This command records the real values in the state file. It changes no cloud resources.

Choosing a Response to Drift

Every drift needs a decision. Two paths exist.

Path A: Undo the Drift

The manual change was a mistake. Run a normal terraform apply. Terraform pushes the real resource back to match the code.

Path B: Accept the Drift

The manual change was correct and should stay. Update the code to match the real value. Run terraform plan and confirm it shows no changes.

Diagram: Decision Flow

        Drift found
            |
            v
   Was the change intended?
      /              \
    No                Yes
     |                 |
     v                 v
terraform apply    Edit the code
(restores code     to match reality,
 settings)         then run plan
     |                 |
     +--------+--------+
              |
              v
   Plan shows zero changes

Automated Drift Checks

Manual checks get forgotten. A scheduled pipeline can run a plan every night and report differences. The -detailed-exitcode flag makes the result easy for a script to read.

terraform plan -detailed-exitcode
Exit CodeMeaning
0No changes. Everything matches.
1An error occurred.
2Changes found. Drift or new code exists.

A nightly job that sends a message on exit code 2 gives the team a daily health check.

Ignoring Expected Changes

Some values change on purpose outside Terraform, such as tags added by a cost tool. Tell Terraform to ignore those attributes with a lifecycle rule.

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  lifecycle {
    ignore_changes = [tags]
  }
}

Use this sparingly. Ignored attributes stay invisible, so a real problem could hide there.

Preventing Drift

  • Limit console write access. Give most people read-only permissions.
  • Route every change through Git and a pipeline.
  • Run scheduled plans and review the results.
  • Document emergency fixes and copy them into code the same day.

Key Points

  • Drift means the real cloud no longer matches the Terraform code and state.
  • Every plan refreshes state and exposes drift automatically.
  • terraform plan -refresh-only shows drift without proposing code changes.
  • Undo drift with apply, or accept it by updating the code.
  • -detailed-exitcode enables scheduled drift checks in pipelines.
  • Restricted console access prevents most drift at the source.