TerraformXXIII · Policy as CodeProduction Terraform
Policy Tools: Sentinel, OPA, Trivy, Checkov, tfsec
What you'll learn
- Distinguish the three layers: plan-time, static, and IaC scanning
- Compare Sentinel, OPA / Conftest, Trivy, Checkov, tfsec on cost, lock-in, and language
- Pick the right primary tool for a given team profile
- Configure each tool on a representative project
Prerequisites
None — start here.
Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-13
Five tools show up in 2026 conversations about Terraform policy: HashiCorp Sentinel, Open Policy Agent (OPA) with Conftest, Aqua tfsec, Bridgecrew / Checkov, and Trivy. They look similar from a distance — all of them can stop a bad plan — and they disagree about almost everything else: where they run, what they evaluate against, what language the rules are written in, and how they ship. Picking the wrong primary tool is expensive to undo. Picking the right one is mostly a matter of asking the right questions.
Three layers, not five tools
The five names collapse into three layers of evaluation:
Layer Evaluates Tools
--------------------------------------------------
Plan-time The plan JSON / Sentinel, OPA / Conftest
Sentinel import
Static The HCL on disk tfsec, Checkov
IaC scan The HCL plus the Trivy
provider schema
A mature policy stack uses tools at more than one layer. Plan-time catches what the plan would do; static catches what the developer wrote before the plan is even run; IaC scanning adds vulnerability databases and provider-schema awareness on top of static analysis. The two layers are not redundant. Static can be wrong about what the plan will do (because the plan involves variable interpolation that static cannot see); plan-time cannot run on a 200-resource PR in a sensible time. The defence is in the depth.
HashiCorp Sentinel
Sentinel is HashiCorp’s policy-as-code language. It runs inside
Terraform Cloud (and Terraform Enterprise). Rules are written
in a Java-like syntax, imported against a typed view of the
plan (tfplan/v2), and gated by the run workflow.
# Inside the Terraform Cloud workspace
sentinel test
PASS - aws-region-whitelist.sentinel
PASS - required-tags.sentinel
PASS - 2 policies, 0 failures
Where it wins. It is the only tool that runs inside the managed apply pipeline with a typed view of the plan and a first-class enforcement point. If the shop is on Terraform Cloud, Sentinel is zero infrastructure to run and zero glue to maintain.
Where it loses. Lock-in: the rule set does not move to local Terraform or OpenTofu without rewriting. The syntax is its own language, and the rule set is not portable to OPA. Sentinel is also managed-only in the form that hooks into the apply; community forks exist for local runs but are not production-grade.
Open Policy Agent (OPA) and Conftest
OPA is the open-source policy engine; Conftest is the wrapper that runs OPA rules against structured configuration files (JSON, YAML, HCL via a shim). Rules are written in Rego.
package terraform.encryption
deny[msg] {
rc := input.resource_changes[_]
rc.type == "aws_s3_bucket"
not rc.change.after.server_side_encryption_configuration
msg := sprintf("%s has no server-side encryption", [rc.address])
}
terraform show -json plan.tfplan > plan.json
conftest test plan.json --policy policy/
FAIL - plan.json - aws_s3_bucket.web has no server-side encryption
3 tests, 2 passed, 1 failure
Where it wins. Open source, runs anywhere, and integrates into CI pipelines with a single binary. Rego is documented and stable. Rules written in Rego apply to Kubernetes, Terraform plans, Dockerfile, and every other structured config the team touches. The same rule runs against Kubernetes admission control without rewriting.
Where it loses. The “plan as JSON” workflow requires
terraform show -json plumbing in CI. The rule set has to
be written and maintained by the team — there is no
managed library of policies. Rego’s learning curve is real,
particularly for engineers whose background is imperative
languages.
Aqua tfsec
tfsec runs static analysis against the HCL on disk. It does not see the plan; it sees the configuration.
tfsec .
Result #1 ID: AWS002
[aws_s3_bucket] Bucket is missing encryption configuration
Location: main.tf: 12-18
1 | resource "aws_s3_bucket" "web" {
...
Where it wins. Fast. Runs in pre-commit. The rule set is broad and updated frequently. Catches obvious misconfigurations before the plan is generated.
Where it loses. As of 2024 Aqua announced tfsec was moving into Trivy; new investment is in Trivy’s IaC scanner. Tools that depend on tfsec’s rule catalogue will see the migration happen regardless of whether the team chooses to ride along. Static-only — does not see plan interpolation. False positives on dynamic constructs (variables, conditionals).
Checkov
Bridgecrew’s Checkov is a static analyser with a heavy
emphasis on the CIS and CIS-equivalent benchmark rulesets. It
also has a plan-time mode (--framework terraform_plan).
checkov -d .
Check: CKV_AWS_18: "Ensure the S3 bucket has access logging"
FAILED for resource: aws_s3_bucket.web
Check: CKV_AWS_19: "Ensure the S3 bucket has encryption"
PASSED
Passed: 14, Failed: 3
Where it wins. The rule set is benchmark-mapped. For regulated workloads (PCI, HIPAA, ISO 27001) the rules are auditable against the source standard. Checkov’s graph-based analysis catches some property-graph issues that line-by-line tools miss.
Where it loses. Larger dependency tree than tfsec; the
first-run experience downloads several frameworks. Some
checks produce noise in pure-IaC scans (e.g. checks
designed for Kubernetes that incidentally trip on Terraform
kubernetes resources). Heavier than tfsec.
Trivy (mis Trivy IaC)
Trivy is the vulnerability scanner that broadened into IaC. The IaC layer covers Terraform plan output and the HCL on disk.
trivy config .
aws_s3_bucket.web (main.tf:12)
Severity: HIGH
ID: AVD-AWS-0088
Description: S3 encryption not enabled
Recommendation: Enable server-side encryption
Where it wins. Single tool for image scanning, filesystem scanning, and IaC scanning. CI integration is one binary call. The rule catalogue absorbs tfsec over time, which reduces the number of tools the team maintains.
Where it loses. Plan-time enforcement requires the IaC mode against a rendered plan. Rego-style custom policy is not the focus; new rules come from the catalogue, not from in-house authorship. For custom organisational policy the team still needs Sentinel or OPA.
Comparison matrix
| Tool | Layer | Language | OSS | Plan-time gate | Best for |
|---|---|---|---|---|---|
| Sentinel | Plan | Sentinel | No (BSL) | Yes (TFC) | HashiCorp-managed shops |
| OPA / Conftest | Plan | Rego | Yes | Yes (CI) | Multi-tool policy surface |
| tfsec | Static | Rego (rules) | Yes | No | Pre-commit, fast feedback |
| Checkov | Static | Python (rules) | Yes | Yes (plan mode) | Regulated workloads |
| Trivy | IaC | Go (rules) | Yes | Yes (IaC mode) | Consolidated security CI |
The right choice per team profile
A few real choices a sysadmin team faces in 2026:
Team A: 5 engineers, 3 workspaces, Terraform Cloud already bought. Use Sentinel. The decision to use plan-time policy has already been made; the language choice is forced. The team writes the rule set, which is small (under 50 rules for most shops). Custom rules are written as needed.
Team B: 25 engineers, 12 workspaces, self-hosted CI, no TFC. Use OPA / Conftest for plan-time policy plus tfsec (or the Trivy IaC scanner) in pre-commit. The rules live in the same repository as the infrastructure code. Conftest runs in the CI step that gates the merge.
Team C: regulated workload, 50 engineers, multiple clouds. Use Checkov as the static baseline (benchmarks map to the auditor’s checklist) plus OPA / Conftest for organisational custom rules. Trivy is added if the team does not already have an image scanner.
Team D: 80 engineers, Kubernetes plus Terraform. Use OPA / Conftest for both. The same Rego bundle runs against Terraform plans in CI and against Kubernetes admission controllers via Gatekeeper. The rule authoring is in one language. The team runs Trivy separately for the rest of the scanner workload.
Validation
The validation is different per tool, but the principle is the same: a passing run for a known-good plan, and a failing run for a known-bad plan.
conftest test plan.json --policy policy/
5 tests, 5 passed, 0 warnings, 0 failures
tfsec .
OK - no issues detected
2 files scanned
For Sentinel inside Terraform Cloud the validation appears in
the run output and in the policy results panel. A failing
policy produces a “Policy check: Hard mandatory” with a
result of false.
Production failure modes
The five failure modes to recognise:
- Double-up rule catalogues. A team runs Sentinel and Checkov against the same plan. The Sentinel rule says “S3 must have encryption”; Checkov has the equivalent. The rule fails twice in CI. Engineers fix the warning twice. One catalogue must win for any given check; the other catalogues complement, not duplicate.
- Static-only as the gate. The team runs
tfsecin CI and treats the result as the policy check. A variable likeencrypt = var.encryptmakes the static check ambiguous. The plan-time gate sees the resolved value; static does not. Plan-time is the gate; static is the fast feedback loop. - Migrating tool, stale rules. A shop standardises on tfsec, then Aqua announces Trivy as the destination. The rule set stops receiving updates. Mitigation: treat the migration as a project, not a side-quest; update the rule catalogue as part of the change.
- Custom rules in a different language per tool. Sentinel for Terraform, Cedar for IAM, OPA for K8s. Three rule sets; three authors; three review paths. Where possible, consolidate on OPA / Rego.
- Pre-commit as the gate. Engineers can run
git commit --no-verify. A pre-commit hook that passes is not a control; it is a hint. The actual gate is in the CI pipeline or in Terraform Cloud.
Security and performance
Each tool carries different surface. Sentinel runs inside Terraform Cloud; the rule source comes from a policy set linked to the workspace, with version pinning. OPA / Conftest runs as a CI binary; rule files are version-controlled. tfsec, Checkov, and Trivy each pull rule definitions from their respective distributions on every run; an air-gapped environment should pin the rule set to a specific version and vendor the tarball.
Performance is rarely the limiting factor for any of these
tools on a 200-resource plan. The Rego parser is the slowest
of the three, but the run time is dominated by terraform plan itself, not by Conftest. The bottleneck shifts to
plan generation at a few hundred resources; for larger
fleets, plan caching and incremental plans address the
plan side, not the policy side.
What comes next
Tools are the substrate. The next lesson is about the rules themselves: how to write them well, the right abstraction level, and the test-driven authoring workflow that keeps a rule set maintainable.
Verification
conftest --version
tfsec --version
checkov --version
trivy --version
conftest version 0.55.0
tfsec version 1.28.7 (built 2024-08-12)
checkov 3.0.50
trivy 0.51.0
A representation across the stack:
conftest test plan.json --policy policy/ && tfsec . && \
checkov -d . --quiet && trivy config --quiet .
5 tests, 5 passed
OK - 14 files scanned, no issues
Passed: 14, Failed: 0
No trivy-iac security issues found
All four exit with status 0 on a clean project. Any non-zero exit is a policy violation; the CI job is configured to fail on any non-zero exit.
Knowledge check · 7 questions
Q1. Which layer is the only one that can gate the apply?
Q2. A team of 25 engineers runs Terraform via self-hosted CI and does not use Terraform Cloud. Which tool stack is most defensible?
Q3. tfsec is the destination for the static-analysis rule set; it is no longer being developed.
Q4. Which tool is best suited for a regulated workload where auditor checklists must map to rule IDs?
Q5. Which statements are true of Open Policy Agent? (Select all that apply.)
Q6. A custom rule needs to verify that S3 buckets created by Terraform have SSE-KMS encryption with a specific CMK. Which toolset is best?
Q7. A CI pipeline runs tfsec and Checkov, both fail with the same rule (CKV / AVD variant: 'S3 must have encryption'). Engineers fix the warning twice in the same PR. What is the fix?
Passing score: 75%. Answers are checked in this browser.