how/cicd
Save tfplan to a file, show it to a human, apply exactly that file, and stop a different diff from sneaking through by accident. The canonical CI pattern for Terraform.
If your team has more than one person on it, or you just want to sleep at night, you have the same question: how do you make apply apply exactly what you reviewed.
The simple sequence terraform plan → "looks good" → terraform apply does not give you that guarantee. When you run apply with no arguments, it builds a new plan, runs a refresh, and if someone changed something in the cloud during those 30 seconds, the diff will be different. What you read on the screenshot and what actually got applied are two different things.
Press ▶ to see how the tfplan file closes this window of uncertainty.
Locally, on your own machine:
$ terraform plan
# you look at the output, all good
$ terraform apply
# you type yes, off it goes
What the second apply actually does: it builds the plan again,
runs a refresh, and applies. Between the two plans, changes in the cloud,
a provider update, or a race with another engineer could have happened.
In 99% of cases the diff does not change. In 1% it changes, and you find
out about it afterward. That is the window of uncertainty.
recap
Key things to remember:
terraform plan -out=tfplan saves the plan to a binary file.
Inside it: the diff, a state snapshot, and metadata. You cannot read it by eye.terraform show -json tfplan > plan.json or
terraform show -no-color tfplan turns the binary into a
readable form. For a PR comment, usually plain text;
for a policy engine, JSON (see tf-policy-gate).terraform apply tfplan does not run another refresh and
does not recompute the plan. It just executes exactly what was
recorded. If tfplan has gone "stale", apply fails with
Saved plan is stale, and you need to generate a new one.plan (runs on every
PR, the artifact is saved) and apply (runs on merge to the
main branch or manually, downloads the artifact). See
tf-plan-apply-ci.plan -out must run against the same
backend as apply. Otherwise tfplan will hold the
state snapshot of one database while apply tries to write to another.tfplan contains decrypted sensitive values.
Store it as an artifact only in protected storage (Actions
artifacts with retention, S3 with SSE-KMS). Do not push it to git.Next: tf-oidc-aws on how CI gets access to AWS without long-lived keys.