Chapter 27Lesson 03~195 minutes

Infrastructure as Code, Terraform Plans, Policy Checks, and Deployment Workflows: Configuration, Design Patterns, and Trade-Offs

Choose plan/apply boundaries, saved-plan handling, state partitioning, OIDC, and GitOps patterns from explicit trust and evidence requirements.

Design choicesOIDCState partitioningGitOpsTrade-offs

Learning objectives

  • Choose plan-on-PR versus apply-on-main/manual boundaries from trust and state requirements.
  • Compare saved-plan promotion with re-planning and state the evidence trade-off.
  • Design one backend/state partition per environment or blast-radius boundary.
  • Prefer OIDC to static cloud secrets and distinguish push deployment from GitOps handoff.
  • Use a decision table to justify an IaC workflow architecture.

1. IaC workflow design is a set of boundary choices

There is no single correct Terraform workflow. A small team may manually dispatch an apply from a reviewed commit; a regulated platform may require a saved-plan digest, environment approval and short-lived cloud federation; a GitOps system may prohibit GitHub Actions from directly applying infrastructure at all. The design test is whether source, state, authority and evidence remain independently observable.

2. Plan on pull request; apply only from trusted revision

PR planning gives fast feedback on proposed infrastructure change, but fork or untrusted PR code must not receive privileged cloud credentials. For public contribution models, either use a no-credential validation path or a carefully designed read-only planning service. Mutation belongs after merge/approval from a trusted base-repository revision.

Do not assume “merged to main” proves that the exact reviewed plan is still current. Main may advance, state may change externally, or another deployment may win the race. Bind apply to one source SHA and one plan/state context.

3. Saved plan versus re-plan at apply time

Choice Strength Risk / requirement Evidence expectation
Apply saved plan Mutation executes the exact reviewed plan bytes Plan is sensitive and state can become stale; compatible tool/provider/backend context required plan digest, tool/provider lock, backend/workspace, stale check
Re-plan in apply job Fresh against current state and simpler artifact handling Reviewer did not approve those exact new plan bytes unless a new gate reviews them new plan digest + explicit second review/policy decision
Plan text only Easy human review Text is not executable identity and may omit/sanitize details never claim text hash proves applied binary plan

4. One state boundary per environment/blast radius

State is an authority boundary because whoever can update it can often drive infrastructure mutation. Separate production from staging rather than selecting both through an unvalidated variable against one broad credential. Backend keys/workspaces can partition state, but naming alone is not enough: bind credentials, environment rules and concurrency to the same target identity.

State locking protects concurrent writers where the backend supports it. It is not a global deployment scheduler and it is not evidence that the human reviewed the current plan. Use GitHub concurrency to reduce overlapping workflow intent and backend locking to protect the state write itself.

5. OIDC versus static cloud secret

Static cloud access keys in repository secrets create long-lived credential rotation and exfiltration risk. OIDC lets the apply job request a short-lived token and lets the cloud provider decide whether repository/workflow/environment claims are trusted. Keep id-token: write only on the jobs that exchange it, and scope the provider role to the exact backend/resources required.

OIDC is an authentication mechanism, not a Terraform policy engine. A correctly federated role can still be over-privileged, and a least-privilege role can still apply a destructive plan if governance fails.

6. Direct apply versus downstream GitOps handoff

Direct push deployment means GitHub Actions authenticates to the backend/provider and performs apply. It gives immediate run-to-change linkage but places mutation credentials/identity at the CI boundary. A GitOps handoff instead updates an authorized desired-state repository or change record and lets a dedicated reconciler perform the mutation.

GitOps does not remove the need for plan evidence. It changes which system owns apply authority and target health. Record the handoff commit/change ID and the reconciler outcome separately from the GitHub Actions check.

7. Setup action versus preinstalled CLI

As verified September 10, 2026, hashicorp/setup-terraform v4.0.1 uses the Node 24 action runtime and can install an exact Terraform version. The mandatory lab pins the action by full commit SHA and requests Terraform 1.16.1. Relying on whichever Terraform binary happens to exist in a runner image makes evidence weaker and can produce incompatible plan behavior after image updates.

8. Plan portability cautions

A saved Terraform plan is designed for a later apply in the same configuration/state context, not as a vendor-neutral serialized change request. Record Terraform version and provider lock, and avoid moving binary plans across arbitrary operating systems, architectures or long version gaps. If a plan must cross a job boundary, keep runner/tooling assumptions explicit and verify the digest before apply.

OpenTofu can implement a similar operating model, but do not assume a Terraform plan binary is interchangeable with OpenTofu or vice versa. Pick one CLI for a workflow run, pin it, and generate/apply plans with that tool.

9. Decision table

Scenario Recommended pattern Prerequisites Observable proof
Public repo PR fmt/validate + no-secret simulation; privileged plan after trusted handoff if needed hosted runner, read-only token source SHA + validation result
Small internal service PR plan + saved digest; manual/environment-gated apply remote backend, committed lock, narrow role plan digest + state target + approval + apply result
Multi-env platform separate backend/role/environment/concurrency per target target inventory and federated identities environment→role→backend mapping
GitOps organization policy-reviewed plan; publish desired-state change, reconciler applies trusted GitOps controller plan evidence + handoff commit + reconciler status
No cloud training local provider + local backend fixture free runner/local machine lock hash + plan hash + file/state result

10. Lesson summary

Architecture should make stale state, privilege boundaries and evidence ownership visible. Whether you save plans, re-plan, use OIDC or hand off to GitOps, never collapse review, authorization and mutation into one opaque job.

Next lesson

Infrastructure as Code, Terraform Plans, Policy Checks, and Deployment Workflows: Diagnostics, Failure Modes, and Production Practices

Continue with the next lesson to build on the current concepts, evidence, security boundaries, and operational practices.

Knowledge check

What is the main benefit of applying a saved plan?

Why might a team deliberately re-plan after approval?

Does GitHub concurrency replace Terraform backend locking?

What changes in a GitOps model?

Can Terraform and OpenTofu share a saved plan binary by assumption?

Official references and version notes

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.