100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
HCL

Plan Review and Policy as Code

Explore how teams review `terraform plan` output for correctness and safety, and how policy-as-code tools like Sentinel and OPA automatically enforce organizational rules on every plan.

Testing & QualityAdvanced10 min readJul 9, 2026
Analogies

Plan Review and Policy as Code

terraform plan produces a human-readable and machine-readable preview of every action Terraform intends to take: resources to create, update in place, or destroy. Reviewing that plan — either by a human reading the diff in a pull request, or by an automated policy engine — is the last checkpoint before infrastructure actually changes. As teams scale, manual review alone doesn't catch every risky change, so organizations layer policy-as-code on top: machine-enforced rules that inspect the plan (or the resulting plan JSON) and block an apply if it violates a defined guardrail, such as 'never allow a public S3 bucket' or 'require a specific tag on every resource'.

🏏

Cricket analogy: terraform plan is like a third umpire's review screen showing exactly what the decision will change before it's finalized; policy-as-code is like the DRS protocol automatically overturning any review that violates a fixed rule, no human debate needed.

Reading a plan diff

Plan output uses symbols to summarize intent: a + prefix means create, - means destroy, ~ means update in place, and -/+ means the resource must be destroyed and recreated because a change requires replacement (for example, changing an EC2 instance's AMI in some configurations). The summary line at the end — 'Plan: 2 to add, 1 to change, 1 to destroy' — is the fastest signal for reviewers, but the detail above it is what actually needs scrutiny, especially any unexpected -/+ replacement of a stateful resource like a database.

🏏

Cricket analogy: Plan symbols like + and -/+ are like scorecard notations: a run scored is +, a wicket is -, and a batter retired hurt then returning to bat again is -/+, requiring scrutiny beyond just the final score summary.

bash
Terraform will perform the following actions:

  # aws_db_instance.primary must be replaced
-/+ resource "aws_db_instance" "primary" {
      ~ engine_version         = "14.9" -> "15.4" # forces replacement
        identifier             = "prod-primary-db"
    }

  # aws_s3_bucket_policy.public will be created
  + resource "aws_s3_bucket_policy" "public" {
      + bucket = "acme-reports"
      + policy = jsonencode({...})
    }

Plan: 1 to add, 0 to change, 0 to destroy, 1 to replace.

Policy as code with Sentinel and OPA

HashiCorp's Sentinel (used in Terraform Cloud/Enterprise) and Open Policy Agent's Rego (used via conftest or custom tooling) both let teams write rules against the structured plan JSON output (terraform show -json). Policies typically run in one of three enforcement levels: advisory (warn only), soft-mandatory (can be overridden by an authorized approver), or hard-mandatory (blocks the apply unconditionally). A common policy set enforces tagging standards, restricts instance types to an approved list, forbids 0.0.0.0/0 ingress rules on security groups, and requires encryption on storage resources.

🏏

Cricket analogy: Sentinel's advisory, soft-mandatory, and hard-mandatory levels are like an umpire's warning, a captain's review override, and an automatic no-ball call — three escalating tiers of enforcement against a fixed set of match rules.

hcl
import "tfplan/v2" as tfplan

mandatory_tags = ["Owner", "Environment", "CostCenter"]

required_tags_present = rule {
  all tfplan.resource_changes as _, rc {
    rc.type is not "aws_instance" or
    all mandatory_tags as tag {
      rc.change.after.tags contains tag
    }
  }
}

main = rule {
  required_tags_present
}

Policy as code turns tribal knowledge ('we always require an Owner tag') into an executable, testable artifact that runs identically for every engineer and every pipeline run, rather than relying on a human reviewer to remember and catch it.

A -/+ (destroy-and-recreate) on a stateful resource like a database or a persistent volume is one of the most dangerous lines in any plan — always confirm whether create_before_destroy or a moved block could avoid data loss before approving it.

  • Plan symbols +, -, ~, and -/+ indicate create, destroy, in-place update, and destroy-then-recreate respectively.
  • The plan summary line is a quick signal, but replacement actions on stateful resources need close manual scrutiny.
  • Policy as code (Sentinel, OPA/Rego) evaluates the structured plan JSON against organizational rules automatically.
  • Enforcement levels range from advisory (warn) to soft-mandatory (overridable) to hard-mandatory (blocking).
  • Common policies restrict public network access, enforce mandatory tags, and require encryption on storage resources.
  • Policy as code makes governance consistent and auditable instead of dependent on manual reviewer memory.

Practice what you learned

Was this page helpful?

Topics covered

#HCL#TerraformInfrastructureAsCodeStudyNotes#DevOps#PlanReviewAndPolicyAsCode#Plan#Review#Policy#Code#StudyNotes#SkillVeris