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

  1. Declarative rules: Define what should be allowed, not how to check it
  2. Separation of concerns: Keep policy logic separate from application code
  3. Test-driven development: Write policy tests before implementation
  4. Continuous validation: Evaluate policies on every change

Implementing OPA with Rego

Prerequisites

Before starting, ensure you have:

  • OPA CLI v1.10+ (brew install opa or 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 version shows 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 (sentinel binary)

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 ✅

  1. Write tests first

    • Define expected behavior before implementing policy
    • Use test cases from actual incidents
    • Aim for >90% coverage
  2. Use descriptive rule names

    • require_encryption_at_rest vs rule_1
    • Names appear in violation messages
    • Self-documenting policies reduce confusion
  3. Version your policies

    • Store in Git with your infrastructure code
    • Tag releases for audit trails
    • Use semantic versioning for breaking changes
  4. Provide actionable error messages

    • Include what’s wrong and how to fix it
    • Reference documentation links
    • Show the specific resource that failed

Don’ts ❌

  1. Don’t bypass policies in emergencies

    • Create expedited approval workflows instead
    • Log all exceptions for audit
    • Review bypasses weekly
  2. 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 fmt to 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

ToolBest ForProsConsPrice
OPAK8s, APIs, generalOpen source, CNCF graduated, large communityRego learning curveFree
SentinelTerraformNative integration, pre-built policiesRequires TFC/TFE licensePaid
ConftestCI/CD pipelinesUses OPA, CLI-focusedLimited features vs OPAFree
CheckovIaC scanning1000+ built-in policiesLess flexible custom policiesFree/Paid

Selection Criteria

Choose based on:

  1. Infrastructure: Kubernetes → OPA; Terraform → Sentinel
  2. Flexibility: Custom policies → OPA; Quick start → Checkov
  3. Budget: Open source → OPA/Conftest; Enterprise support → Sentinel

Additional Resources


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

ConsiderationChoose OPAChoose Sentinel
Primary platformKubernetes, APIsTerraform Cloud/Enterprise
LicensingMust be open sourceEnterprise budget available
Policy scopeRuntime decisionsPre-deployment validation
Learning curveWilling to learn RegoPrefer simpler syntax
IntegrationNeed flexibilityWant 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:

MetricTargetMeasurement
Policy test coverage>90%opa test --coverage
Policy evaluation time<100msBenchmark tests
Compliance violations0 in prodMonitoring dashboards
Mean time to policy change<1 dayGit commit timestamps
False positive rate<5%Exception tracking

Conclusion

Key Takeaways

  1. Policy as Code eliminates manual enforcement through automated, testable rules
  2. OPA and Sentinel serve different use cases—choose based on your infrastructure
  3. Test-driven policy development catches violations before production
  4. Performance matters—benchmark and optimize frequently-evaluated policies

Action Plan

  1. Today: Install OPA CLI and write your first policy with tests
  2. This Week: Integrate policy tests into your CI pipeline
  3. This Month: Implement admission control for your Kubernetes cluster or Terraform workspace

Official Resources

See Also


Have you implemented Policy as Code in your organization? Share your experience in the comments below.