Policy as code transforms compliance and governance rules from documents into executable, testable artifacts that can be enforced automatically across infrastructure. According to the HashiCorp State of Cloud Strategy 2023, 76% of organizations have experienced cloud infrastructure policy violations, and manually reviewing policies is cited as the top compliance challenge. According to a study by Gartner, organizations using policy as code tools reduce policy violation incidents by up to 60% compared to manual policy enforcement. OPA (Open Policy Agent) and Sentinel (HashiCorp) are the two dominant policy as code frameworks, each with distinct strengths: OPA uses Rego for general-purpose policy evaluation, while Sentinel integrates natively with Terraform and other HashiCorp tools.
TL;DR
- OPA is your go-to for multi-platform policy enforcement (Kubernetes, Terraform, APIs); Sentinel excels within the HashiCorp ecosystem
- Policy tests are code — write them before the policy itself using OPA’s built-in test framework
- The #1 mistake: treating policies as documentation instead of tested, versioned code
Best for: Teams managing infrastructure across multiple clouds or platforms needing unified governance
Skip if: You’re 100% in Terraform Cloud/Enterprise and never touch Kubernetes
Read time: 11 minutes
Your Terraform plan passed all tests. CI is green. You merge and deploy. Three hours later, someone provisions a publicly accessible S3 bucket with no encryption. Your security team is furious.
The problem isn’t your tests — it’s that you’re testing the wrong layer. Infrastructure tests verify what gets deployed. Policy tests verify what’s allowed to be deployed. In 2026, with AI tools generating Terraform configs faster than ever, this distinction is critical.
The Real Problem
Most teams approach policy as code backwards. They write policies after incidents, store them in a wiki, and hope developers read them. This is policy as documentation, not policy as code.
Real policy as code means:
- Policies are versioned in Git alongside infrastructure
- Policies have unit tests that run in CI
- Policies block deployments automatically, not via code review comments
- Policy violations produce actionable error messages, not cryptic failures
The shift from “guidelines” to “guardrails” requires a mental model change. You’re not writing rules for humans to follow — you’re writing executable constraints that machines enforce.
“Policy as code is quality assurance for your infrastructure rules. The same test-driven development discipline you apply to application code — write the test, watch it fail, write the policy, watch it pass — applies equally to security and compliance policies.” — Yuri Kan, Senior QA Lead
OPA vs Sentinel: The 2026 Reality
Open Policy Agent (OPA) v1.9.0 and HashiCorp Sentinel both solve policy enforcement, but their scopes differ dramatically.
| Aspect | OPA | Sentinel |
|---|---|---|
| Ecosystem | Platform-agnostic (K8s, Terraform, APIs, CI/CD) | HashiCorp stack (Terraform, Vault, Nomad, Consul) |
| Language | Rego (declarative, JSON-native) | HSL (HashiCorp Sentinel Language) |
| Testing | Built-in opa test command | CLI with sentinel test |
| Data Input | Any JSON (requires terraform show -json) | Native Terraform plan imports |
| Governance | DIY enforcement via CI gates | Built-in advisory/soft/hard enforcement levels |
| Cost | Open source, free | Requires Terraform Cloud/Enterprise |
My recommendation: Start with OPA if you work across multiple platforms or value portability. Choose Sentinel if you’re deeply invested in HashiCorp Cloud Platform and want tight integration with zero transformation steps.
Writing Testable OPA Policies
The key insight is that policies should be written test-first. Before coding the policy, define what should pass and what should fail.
package terraform.aws.s3
import rego.v1
# Deny S3 buckets without encryption
deny contains msg if {
resource := input.planned_values.root_module.resources[_]
resource.type == "aws_s3_bucket"
not has_encryption(resource)
msg := sprintf("S3 bucket '%s' must have server-side encryption enabled", [resource.name])
}
has_encryption(bucket) if {
bucket.values.server_side_encryption_configuration[_].rule[_].apply_server_side_encryption_by_default[_].sse_algorithm
}
Notice the import rego.v1 — this is the modern syntax as of OPA v1.x. The contains keyword and if guards are Rego v1 conventions that replace the older implicit set generation.
Testing Your Policies
OPA’s testing framework lets you verify policy behavior before deployment. Create a test file alongside your policy:
package terraform.aws.s3_test
import data.terraform.aws.s3
# Test: Encrypted bucket should be allowed
test_encrypted_bucket_allowed if {
count(s3.deny) == 0 with input as {
"planned_values": {
"root_module": {
"resources": [{
"type": "aws_s3_bucket",
"name": "secure_bucket",
"values": {
"server_side_encryption_configuration": [{
"rule": [{
"apply_server_side_encryption_by_default": [{
"sse_algorithm": "AES256"
}]
}]
}]
}
}]
}
}
}
}
# Test: Unencrypted bucket should be denied
test_unencrypted_bucket_denied if {
count(s3.deny) > 0 with input as {
"planned_values": {
"root_module": {
"resources": [{
"type": "aws_s3_bucket",
"name": "insecure_bucket",
"values": {}
}]
}
}
}
}
Run tests with opa test . -v to see detailed output. The -v flag shows which tests passed and any that failed with reasons.
CI/CD Integration
The workflow for Terraform + OPA in your pipeline:
# 1. Generate plan
terraform plan -out=tfplan.binary
# 2. Convert to JSON for OPA
terraform show -json tfplan.binary > tfplan.json
# 3. Evaluate policies
opa exec --decision terraform/aws/s3/deny --bundle policies/ tfplan.json
# 4. Fail if violations exist
if [ $(opa eval -d policies/ -i tfplan.json 'data.terraform.aws.s3.deny' | jq '.result[0].expressions[0].value | length') -gt 0 ]; then
echo "Policy violations detected!"
exit 1
fi
For Conftest (OPA’s dedicated config file testing tool), the syntax is simpler:
conftest test tfplan.json --policy policies/
Conftest automatically looks for deny rules and exits non-zero if any fire.
Sentinel for Terraform Cloud
If you’re using Terraform Cloud or Enterprise, Sentinel offers tighter integration. The equivalent S3 encryption policy:
import "tfplan/v2" as tfplan
s3_buckets = filter tfplan.resource_changes as _, rc {
rc.type is "aws_s3_bucket" and
rc.mode is "managed" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
encryption_required = rule {
all s3_buckets as _, bucket {
bucket.change.after.server_side_encryption_configuration is not null
}
}
main = rule {
encryption_required
}
Sentinel’s tfplan/v2 import gives you native access to Terraform’s plan structure without JSON conversion. The enforcement levels (advisory, soft-mandatory, hard-mandatory) let you roll out policies gradually.
AI-Assisted Approaches
Writing policies in Rego or Sentinel requires learning a new language. In 2026, AI tools significantly accelerate this process.
What AI does well:
- Generating initial policy drafts from plain English requirements
- Converting between OPA and Sentinel syntax
- Creating comprehensive test cases for edge conditions
- Explaining complex Rego comprehensions
What still needs humans:
- Deciding which resources require which constraints
- Setting appropriate severity levels for violations
- Reviewing AI-generated policies for logical correctness
- Understanding the business context behind compliance requirements
Useful prompt:
Write an OPA Rego policy that:
1. Denies AWS EC2 instances without the "Environment" tag
2. Allows exceptions for instances with "temporary: true" in metadata
3. Include comprehensive unit tests for both cases
4. Use Rego v1 syntax with explicit imports
When This Breaks Down
Policy as code has limitations:
Complexity explosion: As policies grow, interdependencies become hard to track. A policy allowing t3.micro instances conflicts with a policy requiring encrypted EBS volumes on certain instance types.
False positives: Overly strict policies block legitimate use cases. Teams start asking for exemptions, and you end up with a policy full of exceptions.
Performance at scale: Evaluating thousands of policies against large Terraform plans can slow CI significantly. OPA handles this well with partial evaluation, but you need to optimize.
Drift between policy and reality: Policies enforce what’s planned, not what’s running. A manually-created resource bypasses all policy checks.
Consider complementary tools:
- Terraform drift detection for existing resources
- Cloud-native tools (AWS Config, Azure Policy) for runtime enforcement
- Compliance testing for IaC for regulatory requirements
Decision Framework
Choose OPA when:
- You manage Kubernetes alongside Terraform
- You need policies for API authorization or CI/CD gates
- Your infrastructure spans multiple clouds
- Budget constraints rule out Terraform Enterprise
Choose Sentinel when:
- You’re all-in on HashiCorp Cloud Platform
- You want enforcement levels without building custom CI logic
- Your team already knows Sentinel from Vault or Nomad
- You need first-class support and SLAs
Use both when:
- OPA for Kubernetes admission control (Gatekeeper)
- Sentinel for Terraform-specific governance in TFC
Measuring Success
| Metric | Before | After | How to Track |
|---|---|---|---|
| Policy violations in prod | Unknown | 0 | Cloud audit logs |
| Mean time to violation detection | Days/weeks | <5 minutes | CI pipeline timestamps |
| Policy coverage | 0% | 80%+ resources | opa test –coverage |
| False positive rate | N/A | <5% | Exemption request count |
Warning signs it’s not working:
- Teams bypassing CI to avoid policy checks
- Growing list of permanent exemptions
- Policies that never fire (too permissive)
- Policies blocking every PR (too strict)
What’s Next
Start small. Pick one high-impact policy — maybe S3 encryption or instance tagging — and implement it end-to-end:
- Write the policy with tests
- Add to CI as a warning (advisory mode)
- Monitor for false positives for one sprint
- Promote to blocking (mandatory mode)
- Expand to the next policy
The goal isn’t 100% policy coverage on day one. It’s building muscle memory for treating policies like production code.
Related articles:
- Terraform Testing and Validation Strategies
- Infrastructure as Code Testing
- GitOps Workflows for QA and Testing
- Compliance Testing for IaC
External resources:
Official Resources
FAQ
What is OPA (Open Policy Agent) and how does it work?
OPA is a general-purpose policy engine that evaluates JSON input against Rego policies. You define allowed/denied rules in Rego, run ‘opa eval -i input.json -d policy.rego data.allow’, and OPA returns a decision. OPA integrates with Kubernetes (admission control), Terraform, Envoy (authorization), REST APIs, and microservices. It’s CNCF graduated and widely adopted.
What is the difference between OPA and HashiCorp Sentinel?
OPA is open-source, general-purpose, and uses Rego. It integrates with any system that can make HTTP calls. Sentinel is proprietary to HashiCorp, uses its own DSL, and integrates natively with Terraform Cloud, Vault, Consul, and Nomad. If your stack is primarily HashiCorp, Sentinel offers tighter integration. For multi-platform policy enforcement, OPA is more versatile.
How do I write tests for OPA policies?
OPA supports built-in unit testing with ‘opa test’. Write test rules that start with ’test_’ in a separate _test.rego file: ’test_deny_http_service { deny with input as {“service”: {“port”: 80}} }’. Run with ‘opa test policies/’. Test both positive cases (policy should allow) and negative cases (policy should deny) for every policy rule.
How do I integrate policy as code into Terraform CI/CD?
For OPA: use conftest to run OPA policies against Terraform plan JSON output (’terraform plan -out=plan.binary; terraform show -json plan.binary | conftest test -’). For Sentinel: configure in Terraform Cloud workspace, Sentinel runs automatically on every plan. Block applies when policies fail. Store policies in version control alongside infrastructure code.
See Also
- Policy as Code Testing: A Complete Guide to OPA and Sentinel - Master policy as code testing with Open Policy Agent (OPA) and…
- IAM Policy Testing: Automated Validation with Access Analyzer, Checkov, and Policy Simulators - Master IAM policy testing with AWS IAM Access Analyzer, Checkov,…
- GCP Infrastructure Testing: Terratest, Config Validator, and Policy Library for Google Cloud - Master GCP infrastructure testing with Terratest for Terraform…
- Cost Estimation Testing for Infrastructure as Code: Complete Guide - Master cost estimation testing for IaC with Infracost, terraform…
