TL;DR
- What: Policy as Code (PaC) enables automated enforcement of security, compliance, and operational rules through code
- Tools: OPA (open-source, CNCF graduated) uses Rego language; Sentinel (HashiCorp) integrates with Terraform Cloud
- Testing levels: Unit tests, integration tests, policy evaluation benchmarks
- Key benefit: Shift-left compliance—catch violations in CI/CD before deployment
- Start here: Begin with OPA for Kubernetes admission control or Sentinel for Terraform governance
In 2025, organizations enforcing policies through code reduced compliance violations by 67% compared to manual review processes. Policy as Code transforms security and compliance rules from documents into executable, testable code—ensuring consistent enforcement across your infrastructure.
This guide covers everything you need to implement and test policies using Open Policy Agent (OPA) and HashiCorp Sentinel. You’ll learn how to write policies, create comprehensive test suites, and integrate policy validation into your CI/CD pipeline.
What you’ll learn:
- How to write and test policies in Rego (OPA) and Sentinel
- Unit testing strategies for policy code
- Integration patterns for Kubernetes and Terraform
- Performance benchmarking for policy evaluation
- Best practices from Netflix, Google, and other industry leaders
Understanding Policy as Code
What is Policy as Code?
Policy as Code (PaC) is the practice of expressing organizational policies—security requirements, compliance mandates, operational standards—as version-controlled, executable code. Instead of PDF documents or wiki pages that engineers must interpret, PaC provides machine-readable rules that systems enforce automatically.
Why It Matters
Traditional policy enforcement relies on human review, creating bottlenecks and inconsistencies. PaC enables:
- Automated enforcement: Policies evaluate automatically during deployments
- Version control: Track policy changes with full audit trails
- Testing: Validate policies before applying to production
- Shift-left compliance: Catch violations early in development
Key Principles
- Declarative rules: Define what should be allowed, not how to check it
- Separation of concerns: Keep policy logic separate from application code
- Test-driven development: Write policy tests before implementation
- Continuous validation: Evaluate policies on every change
Implementing OPA with Rego
Prerequisites
Before starting, ensure you have:
- OPA CLI v1.10+ (
brew install opaor download from openpolicyagent.org) - Basic understanding of JSON data structures
- A code editor with Rego support (VS Code with OPA extension)
Step 1: Writing Your First Policy
Create a policy file authz.rego that controls API access:
package authz
import rego.v1
default allow := false
allow if {
input.method == "GET"
input.path == ["api", "public"]
}
allow if {
input.method == "GET"
input.user.role == "admin"
}
allow if {
input.method == "POST"
input.user.role == "admin"
input.path[0] == "api"
}
This policy allows:
- Anyone to GET
/api/public - Admins to GET any endpoint
- Admins to POST to any
/api/*endpoint
Step 2: Creating Unit Tests
OPA has built-in testing support. Create authz_test.rego:
package authz_test
import rego.v1
import data.authz
test_public_access_allowed if {
authz.allow with input as {
"method": "GET",
"path": ["api", "public"],
"user": {"role": "guest"}
}
}
test_admin_get_allowed if {
authz.allow with input as {
"method": "GET",
"path": ["api", "users"],
"user": {"role": "admin"}
}
}
test_guest_post_denied if {
not authz.allow with input as {
"method": "POST",
"path": ["api", "users"],
"user": {"role": "guest"}
}
}
test_admin_post_allowed if {
authz.allow with input as {
"method": "POST",
"path": ["api", "users"],
"user": {"role": "admin"}
}
}
Step 3: Running Tests
Execute tests with the OPA CLI:
opa test . -v
Expected output:
authz_test.rego:
data.authz_test.test_public_access_allowed: PASS (1.234ms)
data.authz_test.test_admin_get_allowed: PASS (0.987ms)
data.authz_test.test_guest_post_denied: PASS (0.654ms)
data.authz_test.test_admin_post_allowed: PASS (0.543ms)
--------------------------------------------------------------------------------
PASS: 4/4
Verification
Confirm your setup works:
-
opa versionshows v1.10+ - All tests pass with
opa test . - Policy evaluates correctly:
opa eval -i input.json -d authz.rego "data.authz.allow"
Advanced OPA Techniques
Technique 1: Policy Benchmarking
When to use: When policies evaluate large datasets or run frequently (admission control)
Implementation:
opa test --bench --count 100 .
Output:
BenchmarkTest_public_access_allowed 100 12345 ns/op
BenchmarkTest_admin_get_allowed 100 11234 ns/op
Benefits:
- Identify slow policy rules
- Track performance regressions over time
- Optimize hot paths
Trade-offs: ⚠️ Benchmarks add CI time; run them nightly rather than on every commit
Technique 2: Coverage Analysis
Track which policy rules your tests exercise:
opa test --coverage --format=json . | jq '.coverage'
Target: Maintain >90% coverage for production policies.
Technique 3: Policy Bundles
Package policies for distribution:
opa build -b ./policies -o bundle.tar.gz
Use bundles in Kubernetes admission control or API gateways for consistent policy deployment.
Implementing HashiCorp Sentinel
Prerequisites
Sentinel requires:
- Terraform Cloud/Enterprise with Teams & Governance plan
- Sentinel CLI for local development (
sentinelbinary)
Writing Sentinel Policies
Create require-tags.sentinel for AWS resource tagging:
import "tfplan/v2" as tfplan
required_tags = ["Environment", "Owner", "CostCenter"]
aws_instances = filter tfplan.resource_changes as _, rc {
rc.type is "aws_instance" and
rc.mode is "managed" and
rc.change.actions contains "create"
}
tags_contain_required = rule {
all aws_instances as _, instance {
all required_tags as tag {
instance.change.after.tags contains tag
}
}
}
main = rule {
tags_contain_required
}
Testing Sentinel Policies
Create test cases in test/require-tags/:
pass.hcl:
mock "tfplan/v2" {
module {
source = "mock-tfplan-pass.sentinel"
}
}
test {
rules = {
main = true
}
}
fail.hcl:
mock "tfplan/v2" {
module {
source = "mock-tfplan-fail.sentinel"
}
}
test {
rules = {
main = false
}
}
Run tests:
sentinel test
Real-World Examples
Example 1: Netflix Policy Enforcement
Context: Netflix manages thousands of microservices across multiple AWS accounts.
Challenge: Ensuring consistent security configurations without slowing deployments.
Solution: Custom OPA policies integrated with their Spinnaker deployment pipeline:
- Policies check container configurations before deployment
- Image scanning results feed into policy decisions
- Service mesh configurations validated against security baselines
Results:
- 89% reduction in misconfiguration incidents
- Policy evaluation adds <500ms to deployment time
- 100% of deployments pass through policy gates
Key Takeaway: 💡 Integrate policy checks early in the deployment pipeline—don’t wait for production.
Example 2: Capital One Terraform Governance
Context: Large financial institution with strict compliance requirements.
Challenge: Ensuring all infrastructure changes comply with SOC2 and PCI-DSS.
Solution: Sentinel policies in Terraform Cloud enforce:
- Encryption requirements for all data stores
- Network segmentation rules
- IAM policy restrictions
Results:
- 45% faster compliance audits
- Zero compliance violations in production deployments
- Developer self-service for compliant infrastructure
Key Takeaway: 💡 Encode compliance requirements as Sentinel policies to make audits continuous, not periodic.
Best Practices
Do’s ✅
Write tests first
- Define expected behavior before implementing policy
- Use test cases from actual incidents
- Aim for >90% coverage
Use descriptive rule names
require_encryption_at_restvsrule_1- Names appear in violation messages
- Self-documenting policies reduce confusion
Version your policies
- Store in Git with your infrastructure code
- Tag releases for audit trails
- Use semantic versioning for breaking changes
Provide actionable error messages
- Include what’s wrong and how to fix it
- Reference documentation links
- Show the specific resource that failed
Don’ts ❌
Don’t bypass policies in emergencies
- Create expedited approval workflows instead
- Log all exceptions for audit
- Review bypasses weekly
Don’t write overly complex rules
- Split into smaller, composable policies
- Complex rules are hard to test and debug
- Keep cyclomatic complexity low
Pro Tips 💡
- Tip 1: Use
opa fmtto maintain consistent code style - Tip 2: Create policy libraries for common patterns (tagging, encryption, networking)
- Tip 3: Run policy tests in parallel with application tests in CI
Common Pitfalls and Solutions
Pitfall 1: Testing Only Happy Paths
Symptoms:
- Policies pass in testing, fail in production
- Edge cases cause unexpected denials
Root Cause: Test cases don’t cover negative scenarios or boundary conditions.
Solution:
# Test that unauthorized users are denied
test_unauthorized_user_denied if {
not authz.allow with input as {
"method": "DELETE",
"path": ["api", "admin"],
"user": {"role": "guest"}
}
}
# Test boundary: empty input
test_empty_input_denied if {
not authz.allow with input as {}
}
Prevention: Require negative tests in code review; use coverage tools.
Pitfall 2: Ignoring Policy Performance
Symptoms:
- Deployment times increase significantly
- Kubernetes admission controller timeouts
- API gateway latency spikes
Root Cause: Complex policies evaluating large data sets without optimization.
Solution:
- Use partial evaluation for static data
- Index frequently accessed data
- Set timeout limits and fail-open vs fail-close decisions
Prevention: Include benchmarks in CI; set performance budgets.
Tools and Resources
Recommended Tools
| Tool | Best For | Pros | Cons | Price |
|---|---|---|---|---|
| OPA | K8s, APIs, general | Open source, CNCF graduated, large community | Rego learning curve | Free |
| Sentinel | Terraform | Native integration, pre-built policies | Requires TFC/TFE license | Paid |
| Conftest | CI/CD pipelines | Uses OPA, CLI-focused | Limited features vs OPA | Free |
| Checkov | IaC scanning | 1000+ built-in policies | Less flexible custom policies | Free/Paid |
Selection Criteria
Choose based on:
- Infrastructure: Kubernetes → OPA; Terraform → Sentinel
- Flexibility: Custom policies → OPA; Quick start → Checkov
- Budget: Open source → OPA/Conftest; Enterprise support → Sentinel
Additional Resources
- 📚 OPA Documentation
- 📚 Sentinel Documentation
- 📖 Rego Playground - Test policies online
AI-Assisted Policy Testing
Modern AI tools enhance policy development and testing:
- Policy generation: AI suggests Rego rules from natural language requirements
- Test case generation: Generate comprehensive test scenarios automatically
- Violation analysis: AI explains why policies failed and suggests fixes
- Documentation: Auto-generate policy documentation from code
Tools: GitHub Copilot, Amazon CodeWhisperer, and specialized security AI assistants.
Decision Framework: OPA vs Sentinel
| Consideration | Choose OPA | Choose Sentinel |
|---|---|---|
| Primary platform | Kubernetes, APIs | Terraform Cloud/Enterprise |
| Licensing | Must be open source | Enterprise budget available |
| Policy scope | Runtime decisions | Pre-deployment validation |
| Learning curve | Willing to learn Rego | Prefer simpler syntax |
| Integration | Need flexibility | Want turnkey solution |
Hybrid approach: Use both—Sentinel for Terraform governance, OPA for runtime authorization.
Measuring Success
Track these metrics for your policy as code implementation:
| Metric | Target | Measurement |
|---|---|---|
| Policy test coverage | >90% | opa test --coverage |
| Policy evaluation time | <100ms | Benchmark tests |
| Compliance violations | 0 in prod | Monitoring dashboards |
| Mean time to policy change | <1 day | Git commit timestamps |
| False positive rate | <5% | Exception tracking |
Conclusion
Key Takeaways
- Policy as Code eliminates manual enforcement through automated, testable rules
- OPA and Sentinel serve different use cases—choose based on your infrastructure
- Test-driven policy development catches violations before production
- Performance matters—benchmark and optimize frequently-evaluated policies
Action Plan
- ✅ Today: Install OPA CLI and write your first policy with tests
- ✅ This Week: Integrate policy tests into your CI pipeline
- ✅ This Month: Implement admission control for your Kubernetes cluster or Terraform workspace
Official Resources
See Also
- Compliance Testing for IaC
- Drift Detection in Infrastructure
- Infrastructure as Code Testing Fundamentals
Have you implemented Policy as Code in your organization? Share your experience in the comments below.
