CoursesInfrastructure as Code & automationAdvanced · Policy & scanning

Policy-as-code: OPA, Conftest & Sentinel

Enforce rules on infrastructure.

Advanced14 min · lesson 17 of 23

IaC makes infrastructure fast to change, which makes it fast to change wrongly — a public S3 bucket, an open security group, a missing tag — so mature teams add automated guardrails. Policy-as-code expresses your rules as code that runs in the pipeline and fails a plan that violates them, before anything is applied. It is the same shift-left idea from CI/CD: instead of a human reviewer remembering "no public buckets," a policy enforces it mechanically on every change, consistently and unskippably.

Where policy-as-code sits
1write IaC
terraform code
2plan
terraform plan -> JSON
3policy check
OPA/Conftest/Sentinel evaluate
4pass or fail
violation blocks the apply
Policy runs against the plan, so it judges what WOULD change — catching a bad config before it reaches the cloud.

OPA and Conftest

Open Policy Agent (OPA) is the general-purpose policy engine, using a language called Rego to express rules; Conftest wraps OPA specifically to test configuration files (a Terraform plan, a Kubernetes manifest, a Dockerfile) against Rego policies. You write policies like "deny any security group open to 0.0.0.0/0 on port 22" or "require an Environment tag," export the Terraform plan as JSON, and Conftest fails the build if any policy is violated. Because OPA is used across Kubernetes admission, CI, and APIs, the same policy skills transfer widely.

policy/deny_public_ssh.rego + CI
package main
deny[msg] {
r := input.resource_changes[_]
r.type == "aws_security_group_rule"
r.change.after.from_port == 22
r.change.after.cidr_blocks[_] == "0.0.0.0/0"
msg := sprintf("SSH open to the world in %s", [r.address])
}
# in CI:
# terraform plan -out=tf.plan && terraform show -json tf.plan > plan.json
# conftest test plan.json # exits non-zero (fails the build) on any deny

Sentinel and where to enforce

HashiCorp Sentinel is the policy engine built into Terraform Cloud/Enterprise, enforcing policies at plan time within HashiCorp’s workflow (a paid, integrated option). OPA/Conftest is the open, tool-agnostic alternative you run yourself in CI. Either way, the key decision is enforcement point: run policy in CI to give developers fast feedback on their pull request, and — for defense in depth — also at the apply gate so nothing bypasses it. Policy that only warns gets ignored; policy wired to fail the build, and block the apply, is what actually holds.

Policy-as-code is only a control if it blocks
The failure mode is policy theater — rules that run and report violations but do not fail the build, so developers merge past them and the guardrail enforces nothing. Wire policies to a non-zero exit that blocks the merge or the apply, start with a small set of high-value rules everyone agrees on (no public storage, required tags, no wildcard IAM), tune out false positives so the checks stay trusted, and grow coverage from there. A policy that only warns is documentation; a policy that blocks is a control.