Policy as Code for Terraform: OPA/Conftest vs Sentinel vs Checkov & tfsec

Quick answer
Checkov ships thousands of security rules out of the box, OPA/Conftest lets you write portable org governance in Rego, and Sentinel is HashiCorp's proprietary gate inside HCP Terraform. They solve different problems — here's how to pick, and why a mature stack usually runs two of them.
- Category 1: Security scanners with built-in rules
- Category 2: General-purpose policy engines (OPA + Conftest)
- Category 3: Integrated proprietary gates (Sentinel)
- Where each one runs
- The comparison
12 min read · DevOps & Platform
Once your Terraform is bigger than one person's laptop, "the review will catch it" stops being a control. Someone will merge a public S3 bucket, an oversized instance in the wrong region, or an untagged resource that nobody can attribute in the cost report. Policy as code is how you turn those review-time hopes into pipeline-time gates that fail the build.
The tooling gets lumped together, but there are really three categories doing different jobs:
- Security scanners with built-in rules — Checkov and tfsec (now Trivy). Thousands of maintained security/compliance checks, near-zero setup. Best for instant coverage.
- General-purpose policy engines — OPA + Rego, driven against Terraform plans with Conftest. Vendor-neutral, portable, and the same engine you already run for Kubernetes admission. Best for your org-specific governance.
- Integrated proprietary gates — HashiCorp Sentinel, embedded in HCP Terraform / Terraform Enterprise with enforcement levels wired into the run pipeline. Tight integration, but paid and locked-in.
They are not mutually exclusive. The most common mature setup runs a scanner and a policy engine. This post covers what each category actually does, where in the pipeline it runs, and a segmented decision rule.
Category 1: Security scanners with built-in rules
The fastest path to value. A scanner ships with a large, maintained library of rules encoding known misconfigurations — public buckets, unencrypted volumes, wide-open security groups, missing logging — and you point it at your code. You get hundreds of findings on day one without writing a single policy.
Checkov
Checkov (from Prisma Cloud / Bridgecrew, now Palo Alto) is the heavyweight here. It statically analyzes Terraform HCL — and optionally the plan JSON — against thousands of built-in policies mapped to CIS, PCI, SOC 2, and HIPAA benchmarks. Running it is genuinely a one-liner:
1# Scan a directory of HCL
2checkov -d .
3
4# Or scan a plan for context the static parse can't see
5terraform plan -out=tfplan.bin
6terraform show -json tfplan.bin > tfplan.json
7checkov -f tfplan.jsonWhen the built-ins aren't enough, Checkov supports custom policies in three flavors: a declarative YAML attribute/connection DSL, full Python, and a graph-based query for relationships between resources. A YAML custom policy — say, "every S3 bucket must carry a DataClassification tag" — looks like this:
1metadata:
2 id: "CKV_ORG_1"
3 name: "S3 buckets must have a DataClassification tag"
4 category: "GENERAL_SECURITY"
5definition:
6 cond_type: "attribute"
7 resource_types:
8 - "aws_s3_bucket"
9 attribute: "tags.DataClassification"
10 operator: "exists"That's the appeal: you get the entire security corpus for free, and the escape hatch to encode a few org rules without leaving the tool. Checkov also does more than Terraform — CloudFormation, Kubernetes, Dockerfiles, ARM, Helm — so one scanner covers a lot of your IaC surface.
tfsec — deprecated, use Trivy
tfsec was the other popular Terraform-native scanner. Be clear about its status: tfsec is deprecated. Aqua Security folded its capabilities into Trivy, and the tfsec repo now points there. If you're greenfield, don't adopt tfsec — reach for Trivy's misconfiguration scanning instead, which inherited the rule set and is actively maintained:
# Trivy is the going-forward path for tfsec-style checks
trivy config .Both Checkov and Trivy are open source and run anywhere — pre-commit hook, CI job, or a container step. They analyze HCL directly (fast, no cloud creds needed) and can optionally consume plan JSON for values that only exist after interpolation. The tradeoff is that they enforce known security patterns, not your business rules. "No public buckets" is built in. "All prod resources must be in eu-west-1 and tagged with a cost center" is not — that's the next category's job.
Category 2: General-purpose policy engines (OPA + Conftest)
Open Policy Agent is not a Terraform tool at all — it's a general-purpose policy engine that evaluates JSON against rules written in Rego. That generality is the whole point: the same engine and the same language enforce Kubernetes admission control, API authorization, and Terraform governance. If you already run OPA/Gatekeeper for Kubernetes admission webhooks, extending it to Terraform means reusing skills your team already has instead of learning a proprietary DSL.
For Terraform you feed OPA the plan as JSON, and Conftest is the ergonomic wrapper that makes this pleasant:
terraform plan -out=tfplan.bin
terraform show -json tfplan.bin > tfplan.json
conftest test tfplan.json --policy ./policyA Rego policy that denies any resource created outside an approved region:
1package main
2
3import future.keywords.in
4
5allowed_regions := {"eu-west-1", "eu-central-1"}
6
7# Look at every resource change in the plan
8deny contains msg if {
9 resource := input.resource_changes[_]
10 region := resource.change.after.region
11 not region in allowed_regions
12 msg := sprintf(
13 "%s uses disallowed region %q (allowed: %v)",
14 [resource.address, region, allowed_regions],
15 )
16}
17
18# Require a cost-center tag on every taggable resource
19deny contains msg if {
20 resource := input.resource_changes[_]
21 startswith(resource.type, "aws_")
22 tags := object.get(resource.change.after, "tags", {})
23 not tags["cost-center"]
24 msg := sprintf("%s is missing the required cost-center tag", [resource.address])
25}This is what scanners can't give you: rules that encode your organization's naming conventions, allowed instance types, tagging standards, region allowlists, and cost guardrails. Because it evaluates the plan JSON, it sees the final, interpolated, provider-resolved values — not just the static HCL — so it catches things a pure HCL parse misses.
The cost is real: Rego has a learning curve. Its set/document model is unlike anything else, and non-trivial policies take practice to write and debug. But it's the open, portable choice — no vendor, no license, and it runs identically in a pre-commit hook, a CI job, or a server-side Atlantis/Spacelift gate. Critically, it is the practical path on OpenTofu, because — as we'll see — Sentinel is not.
Terraform Day-2 Operations Checklist
State hygiene, drift, imports, policy checks, and upgrade routines — everything after `terraform apply` works. Plain Markdown, commit it to your repo.
Free. Instant download. You'll also get the occasional deep-dive from the newsletter — unsubscribe anytime.
Category 3: Integrated proprietary gates (Sentinel)
Sentinel is HashiCorp's own policy-as-code framework, and its differentiator is integration, not the language. It's embedded directly in HCP Terraform and Terraform Enterprise, sitting in the run pipeline between plan and apply. Policies get enforcement levels that map cleanly onto how organizations actually govern:
- advisory — logs a warning, never blocks.
- soft-mandatory — blocks, but an admin can override with a documented reason.
- hard-mandatory — blocks, no override, full stop.
A Sentinel policy restricting instance types reads about how you'd expect:
1import "tfplan/v2" as tfplan
2
3allowed_types = ["t3.micro", "t3.small", "t3.medium"]
4
5ec2_instances = filter tfplan.resource_changes as _, rc {
6 rc.type is "aws_instance" and
7 rc.mode is "managed" and
8 (rc.change.actions contains "create" or rc.change.actions contains "update")
9}
10
11main = rule {
12 all ec2_instances as _, instance {
13 instance.change.after.instance_type in allowed_types
14 }
15}The upside is that enforcement is native: no glue to wire a scanner into your VCS pipeline, no separate policy CI job, and the results surface right in the Terraform run UI with override workflows and audit trails. For a team already standardized on HCP Terraform, that integration is genuinely nice.
The downsides are the obvious ones. Sentinel is proprietary and paid — it's a feature of HCP Terraform's paid tiers and Terraform Enterprise, not something you run standalone against arbitrary CI. And it's lock-in: policies written in Sentinel only run inside HashiCorp's platform.
One hard constraint you must not miss: Sentinel does not work on OpenTofu. If you've moved to or are evaluating the open-source fork — see OpenTofu vs Terraform — Sentinel is off the table entirely, and OPA/Conftest becomes your governance engine by default. This is one of the more consequential practical differences between the two, not a footnote.
Where each one runs
Policy tools differ not just in what they check but where they sit in the flow, and that shapes how much protection you actually get:
- Scanners (Checkov / Trivy) run on HCL as a pre-commit hook and in CI — feedback in seconds, before a plan even exists. They can also consume plan JSON for post-interpolation values.
- OPA/Conftest runs against plan JSON, so it needs a
terraform planfirst. Put it in CI, or better, server-side in an Atlantis/Spacelift workflow so it can't be skipped locally. - Sentinel runs as a native gate in the HCP Terraform run pipeline, between plan and apply, with no extra CI wiring.
The general principle: local/pre-commit checks are fast and developer-friendly but skippable; server-side gates (Sentinel, or OPA/scanner steps enforced in Atlantis/Spacelift/a protected CI branch) are the ones that actually can't be bypassed. Run scanners early for fast feedback and enforce the important policies server-side.
The comparison
| Dimension | Checkov / Trivy (tfsec) | OPA + Conftest | Sentinel |
|---|---|---|---|
| What it is | Security scanner with built-in rules | General-purpose policy engine | Proprietary policy framework |
| Rule language | Built-ins + YAML/Python/graph | Rego | Sentinel language |
| Built-in rules? | Yes — thousands (CIS/PCI/SOC2) | No — you write them | No — you write them |
| Evaluates HCL or plan? | HCL (and optionally plan JSON) | Plan JSON | Plan JSON (native) |
| Where it runs | Pre-commit, CI, container | CI, Atlantis/Spacelift, server | HCP Terraform / TFE run pipeline |
| Open or proprietary? | Open source | Open source | Proprietary, paid |
| Works on OpenTofu? | Yes | Yes | No |
| Best at | Instant security coverage | Custom org governance, portability | Native gating on HCP Terraform |
The one-line framing:
- Checkov/Trivy is a corpus of known bad patterns you get for free.
- OPA/Conftest is a blank policy engine you teach your rules — portable everywhere.
- Sentinel is a built-in gate you get if (and only if) you pay for HCP Terraform.
Which should you use?
This is genuinely segmented — the right answer depends on where you are.
-
Just want security coverage today? Start with Checkov (or Trivy) in CI. This is the default and the highest ROI per hour spent. You get thousands of maintained security and compliance checks immediately, with no policy authoring. If you do one thing this quarter, do this. Add it as a pre-commit hook and a required CI check.
-
Need org-specific governance, or you're on OpenTofu? Add OPA/Conftest. Once "no public buckets" is handled by the scanner, your real gaps are the rules only your organization has — naming, tagging, allowed regions and instance types, cost guardrails. Write those in Rego against the plan JSON. This is also your only real option for pipeline governance if you've moved to OpenTofu, since Sentinel won't run there. Bonus: if you already run OPA for Kubernetes admission, you're reusing one engine and one language across both.
-
Already on HCP Terraform / Enterprise and want native gating? Use Sentinel. If you've paid for the platform, Sentinel's enforcement levels and in-run-UI overrides are a clean, well-integrated way to gate applies without standing up extra CI plumbing. But don't adopt HCP Terraform just to get Sentinel — OPA gives you the same governance, portably, for free.
The mature default is a combination: a scanner (Checkov or Trivy) for the security corpus, plus OPA/Conftest for custom org policy. That pairing covers "known-bad security patterns" and "our specific rules" with two open-source tools and no lock-in. Reach for Sentinel only when the platform integration outweighs the portability you give up.
See also
Frequently Asked Questions
Should I use Checkov or OPA/Conftest for Terraform?
Both, ideally — they solve different problems. Checkov ships thousands of built-in security and compliance checks with almost no setup, catching misconfigurations like public buckets or unencrypted volumes fast. OPA/Conftest ships with no rules; you write your own in Rego for org-specific governance (naming, tagging, regions, cost guardrails) against the plan JSON. Start with Checkov for instant coverage, then add OPA for custom policy — the common mature stack runs both.
Is tfsec deprecated?
Yes. Aqua Security has deprecated tfsec and folded its misconfiguration checks into Trivy, which is actively maintained. Existing tfsec setups still function, but new projects should use Trivy's trivy config scanning instead of adopting tfsec. The rule coverage carried over, so it's a low-friction switch. For the broader picture on scanning artifacts and dependencies, see container image security and the software supply chain.
Does HashiCorp Sentinel work with OpenTofu?
No. Sentinel is proprietary to HashiCorp and only runs inside HCP Terraform and Terraform Enterprise; it does not work with OpenTofu at all. If you've adopted or are evaluating OpenTofu — see OpenTofu vs Terraform — your policy-as-code path is OPA/Conftest (or a scanner like Checkov/Trivy), not Sentinel. This is one of the more consequential day-to-day differences between the two projects.
Should policy checks run on HCL or the Terraform plan?
It depends what you're checking. Scanning HCL directly (Checkov, Trivy) is fast, needs no cloud credentials, and works pre-commit — good for catching static misconfigurations early. But HCL can't show values that only exist after interpolation and provider resolution. For those, evaluate the plan JSON (terraform show -json), which is what OPA/Conftest and Sentinel consume. Scan HCL early for fast feedback, then enforce the important rules against the plan server-side.
Can I reuse my Kubernetes OPA policies for Terraform?
You reuse the engine and language, not the exact rules. OPA and Rego are the same whether you're doing Kubernetes admission control or Terraform governance, so your team's Rego skills and testing patterns carry over directly. The input documents differ — a Kubernetes AdmissionReview versus a Terraform plan JSON — so policy bodies aren't identical, but the mental model is shared. That reuse is one of OPA's biggest advantages over a Terraform-only tool like Sentinel.
Policy as code is one layer of a defense-in-depth posture — pair it with supply-chain security tooling for Kubernetes and CIS benchmark hardening so misconfigurations are caught in code, in the pipeline, and at runtime. And if you're bringing existing infrastructure under Terraform's control before you can gate it, importing existing infrastructure is the prerequisite step most teams underestimate.
Not sure where templating ends and enforcement should begin in your Terraform pipeline? Talk to us at Coding Protocols — we help platform teams design policy-as-code gates that catch real problems without slowing every merge to a crawl.
Was this article helpful?
Be the first to rate this article
Related Topics
Found this useful? Share it.


