
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Manual compliance reviews cannot keep pace with modern infrastructure velocity, creating bottlenecks or dangerous gaps in security governance. Implementing Policy as Code with OPA and Conftest shifts these critical checks left into your development workflow, ensuring every change meets organizational standards before it ever reaches production. This approach transforms subjective audit checklists into deterministic, automated tests that integrate directly with your existing Infrastructure as Code with Terraform pipelines.
What is Policy as Code with OPA and Conftest and why does it matter?
Policy as Code with OPA and Conftest represents a fundamental shift from reactive auditing to proactive prevention. Open Policy Agent (OPA) serves as the general-purpose policy engine that evaluates arbitrary structured data against rules written in Rego, a declarative query language designed specifically for policy logic. Conftest acts as the developer-facing interface, wrapping OPA to validate configuration files like Terraform plans, Kubernetes manifests, Dockerfiles, and Helm charts without requiring you to manage raw JSON inputs manually.
In practice, this separation of concerns matters because infrastructure teams often struggle to bridge the gap between compliance requirements and engineering implementation. Security teams write PDFs; engineers write YAML. OPA translates those PDF requirements into executable code that lives alongside your application source. When you treat policies as first-class artifacts stored in Git, you gain version history, peer review workflows, and automated testing for your governance rules themselves. This alignment is essential for maintaining SOC 2 or ISO 27001 compliance at scale, where evidence collection must be continuous rather than point-in-time.
How do you write effective Rego policies for infrastructure validation?
Rego has a learning curve because it operates on set theory and logic programming rather than imperative scripting. A common mistake is trying to write Rego like Python or Bash. Instead, think in terms of queries: you are asking questions about your data, and violations occur when certain conditions evaluate to true. Start simple and build complexity incrementally.
Basic deny rule structure
Every useful policy starts with a clear violation definition. The following example enforces that all AWS S3 buckets must have versioning enabled, a baseline requirement for most backup and disaster recovery strategies:
package terraform.s3
import rego.v1
deny contains msg if {
some resource in input.resource_changes
resource.type == "aws_s3_bucket"
resource.change.after.versioning[0].enabled != true
msg := sprintf("S3 bucket '%s' must have versioning enabled", [resource.address])
} This pattern uses the contains keyword to collect multiple violations into a set, which is crucial when validating large Terraform plans with hundreds of resources. The some ... in construct iterates safely over arrays, avoiding index errors when resources don't exist. Always use sprintf for messages to include specific resource identifiers—generic error messages waste debugging time during CI/CD pipeline execution.
Testing policies before deployment
Never deploy untested Rego. Create test fixtures representing both compliant and non-compliant configurations, then write assertions using Conftest's built-in test framework or OPA's native test runner. Store tests adjacent to your policies in version control. If you cannot articulate what constitutes a pass versus fail case in a unit test, your policy is too vague for production enforcement.
How do you integrate Conftest into CI/CD pipelines for automated enforcement?
Integration timing determines whether Policy as Code with OPA and Conftest acts as a helpful guardrail or an annoying blocker. Validate as early as possible while maintaining sufficient context for meaningful evaluation. For Terraform specifically, always validate the plan output rather than raw HCL files—the plan contains resolved values, computed attributes, and actual state changes that static analysis cannot see.
- Generate the Terraform plan in JSON format using
terraform plan -out=tfplan && terraform show -json tfplan > tfplan.json - Run Conftest against the plan file with your policy directory:
conftest test tfplan.json --policy ./policies - Configure your CI system to fail the job on any deny results, treating warnings as informational only
- Archive the plan artifact and policy version used for audit trail reproducibility
- Optionally push passing plans to an artifact store for subsequent apply stages
In GitLab CI or GitHub Actions, this typically adds 10–30 seconds to pipeline duration—a negligible cost compared to remediating a misconfigured production database. The key insight from years of running these systems: consistency matters more than strictness. A policy that catches 80% of issues reliably beats one that theoretically covers everything but produces false positives that engineers learn to ignore.
When should you use OPA versus Conftest versus cloud-native policy tools?
Choosing the right tool depends on your existing ecosystem, team expertise, and compliance requirements. While Policy as Code with OPA and Conftest provides maximum flexibility, cloud vendors now offer managed alternatives that reduce operational overhead at the cost of portability.
| Criteria | OPA + Conftest | AWS SCP / Azure Policy | Kyverno / Gatekeeper |
|---|---|---|---|
| Language | Rego (declarative) | JSON / Portal UI | YAML CRDs / Rego |
| Scope | Any structured data | Single cloud API calls | Kubernetes admission only |
| Shift-left capability | Excellent (CLI + CI) | Poor (post-deploy enforcement) | Moderate (dry-run mode) |
| Multi-cloud support | Native | None | Limited |
| Learning curve | Steep initially | Low | Moderate |
| Audit evidence export | Custom (full control) | Built-in reports | K8s events / logs |
| Best for | Complex cross-domain policies | Cloud account guardrails | K8s runtime enforcement |
For organizations pursuing multi-cloud strategies or needing to validate non-infrastructure artifacts (API schemas, application configs, IAM policies), OPA remains unmatched. Cloud-native tools excel at preventing API-level misconfigurations within their respective platforms but cannot replace pre-deployment validation. Many mature teams run both: OPA/Conftest in CI for shift-left prevention, plus cloud-native policies as defense-in-depth runtime guards.
How do you manage policy lifecycle and avoid technical debt in Rego?
Policies age poorly when treated as afterthoughts. Without deliberate lifecycle management, your Rego codebase becomes a tangled mess of exceptions, outdated rules, and undocumented assumptions that block legitimate work. Apply the same software engineering discipline to policies that you apply to application code.
Version and tag policy bundles
Never reference mutable policy sources in production pipelines. Use OPA Bundle API or Git tags to pin exact policy versions consumed by each deployment. When updating policies, maintain backward compatibility or coordinate breaking changes with dependent teams. Document the rationale behind each rule in comments—six months later, nobody will remember why that specific CIDR range was whitelisted.
Implement exception handling explicitly
Real-world infrastructure requires exceptions. Build a structured exception mechanism into your policy library rather than scattering hardcoded overrides throughout rules. A centralized exception registry with expiration dates, approval references, and ownership metadata keeps temporary waivers from becoming permanent security holes. This discipline proves invaluable during AWS IAM best practices audits where reviewers demand justification for every deviation.
Monitor policy effectiveness metrics
Track violation rates, false positive frequency, and mean-time-to-resolution for policy failures. Policies that generate constant noise without catching real risks should be refined or retired. Conversely, rules that never trigger may indicate dead code or insufficient test coverage. Treat policy health as an observable system metric, not a set-and-forget artifact.
Start enforcing Policy as Code with OPA and Conftest today
Begin with a single high-value policy targeting your most frequent misconfiguration—public S3 buckets, missing encryption, overly permissive security groups—and integrate Conftest validation into one pilot pipeline. Measure the catch rate, gather developer feedback, refine the messaging, then expand scope incrementally. Resist the urge to boil the ocean with comprehensive policy libraries before proving the workflow works for your team.
If your organization needs guidance implementing Policy as Code with OPA and Conftest across complex multi-cloud environments or preparing for compliance audits, reach out to discuss your specific infrastructure challenges. Getting the foundation right early prevents costly rework and ensures your governance scales with your engineering velocity.