Sheet ⁨06⁩ · ⁨DevTips⁩Surveyed ⁨2026⁩

Blog post image for Policy-as-Code Governance with OPA/Rego - How Open Policy Agent enforces infrastructure standards automatically: writing policies in Rego, wiring them into Terraform and Kubernetes, and blocking non-compliant changes in CI/CD before they merge.

Policy-as-Code Governance with OPA/Rego

Published: 03 Mins read04 Mins listen
Markdown for AI(opens in a new tab)

Why policy-as-code matters

The governance problem

Managing infrastructure at scale gets complicated fast.

As your infrastructure grows, keeping it consistent and compliant gets harder. Manual reviews don’t scale past a few teams, and configuration drift arrives on its own. What you need is enforcement that runs on every change without a human in the loop.

Common infrastructure issues

  • Developers accidentally making resources publicly accessible
  • Missing required tags on cloud resources
  • Non-compliant security group configurations
  • Kubernetes deployments without resource limits
  • Terraform modules bypassing organizational standards

The problem: manual governance

Why manual reviews fail

Code review and post-deployment checks depend on a tired human noticing one line in a 400-line diff. Standards get missed, security rules get worked around, and the issue surfaces after the apply. Guardrails have to run before the deploy to be worth anything.

What it costs

Unenforced policy shows up on the invoice and in the incident review:

  • Security breaches from misconfigured resources
  • Compliance violations leading to audits and fines
  • Cost overruns from unoptimized infrastructure
  • Operational chaos from inconsistent deployments

The fix: Open Policy Agent (OPA)

What OPA is

Open Policy Agent is a policy engine that keeps policy logic out of your application and infrastructure code. You write rules in Rego, a declarative query language, and OPA evaluates them against structured input: Terraform plans, Kubernetes manifests, CI/CD configuration, or any other JSON you hand it.

What you get

  • Unified enforcement across Terraform, Kubernetes, and custom tools
  • Declarative policies that are easy to understand and maintain
  • Pre-deployment validation to catch issues before they reach production
  • Audit trails for compliance and governance requirements
  • Organization-wide standards enforced consistently

Getting started with OPA and Rego

Installing OPA

Terminal window
# macOS
brew install opa
# Linux
curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_x86_64
chmod +x opa
sudo mv opa /usr/local/bin/

A basic Rego policy

restrict-public-buckets.rego
# Deny public S3 buckets
package s3
deny[msg] {
input.resource_type == "aws_s3_bucket"
input.acl == "public-read"
msg := sprintf("S3 bucket %s cannot be public", [input.name])
}
deny[msg] {
input.resource_type == "aws_s3_bucket"
input.acl == "public-read-write"
msg := sprintf("S3 bucket %s cannot be public", [input.name])
}

Integrating OPA with Terraform

Using Conftest for Terraform

Terminal window
# Install conftest
brew install conftest
# Validate Terraform plan
terraform plan -json | conftest test -

Policy example: enforce tags

require-tags.rego
package terraform
deny[msg] {
resource := input.resource_changes[_]
resource.type in ["aws_instance", "aws_rds_cluster"]
not resource.change.after.tags.Environment
msg := sprintf("Resource %s must have Environment tag", [resource.address])
}
deny[msg] {
resource := input.resource_changes[_]
resource.type in ["aws_instance", "aws_rds_cluster"]
not resource.change.after.tags.CostCenter
msg := sprintf("Resource %s must have CostCenter tag", [resource.address])
}

Enforcing policies in Kubernetes

Installing OPA Gatekeeper

Terminal window
# Deploy Gatekeeper to your cluster
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.14/deploy/gatekeeper.yaml

A Kubernetes ConstraintTemplate

require-resource-limits.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResources
metadata:
name: require-resource-limits
spec:
match:
kinds:
- apiGroups: ['']
kinds: ['Pod']
excludedNamespaces: ['kube-system', 'gatekeeper-system']
---
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredresources
spec:
crd:
spec:
names:
kind: K8sRequiredResources
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredresources
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("Container %s must have CPU limit", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("Container %s must have memory limit", [container.name])
}

CI/CD pipeline integration

GitHub Actions example

.github/workflows/policy-check.yml
name: Policy Validation
on: [pull_request]
jobs:
policy-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install OPA
run: |
curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_x86_64
chmod +x opa
sudo mv opa /usr/local/bin/
- name: Run Policy Tests
run: |
opa test policies/ -v
- name: Validate Terraform
if: hashFiles('*.tf') != ''
run: |
terraform init
terraform plan -json | opa eval -d policies/ 'data.terraform.deny' -f pretty

Best practices

1. Start at the organization level

Define policies at the organization level, not project level. Make them discoverable and documented.

# Start with clear policy namespaces
package org_policies.infrastructure.aws.security
package org_policies.kubernetes.workload

2. Fail safely

Distinguish between hard denials and warnings:

package my_policies
deny[msg] {
# Hard deny: completely block this
input.security_critical_violation == true
msg := "This violates critical security policy"
}
warn[msg] {
# Warning: recommend but allow with approval
input.non_standard_naming == true
msg := "Consider following naming standards"
}

3. Test your policies

Terminal window
# Test policy logic before deployment
opa test policies/ -v

4. Keep policies in version control

Keep policies in the same repo as infrastructure code, with proper code review processes.

Monitoring and auditing

Log policy violations

Capture and log every policy decision for audit trails:

package audit
log_decision[decision] {
decision := {
"action": "denied",
"reason": input.violation_reason,
"timestamp": input.timestamp,
"resource": input.resource_id
}
}

A rollout timeline

PhaseFocusTimeline
Phase 1Basic security policies (public access, required tags)Week 1-2
Phase 2Terraform integration in CI/CDWeek 3-4
Phase 3Kubernetes Gatekeeper deploymentWeek 5-6
Phase 4Full auditing and monitoring rolloutWeek 7-8

Wrapping up

Policy-as-code moves the check from after the deploy to before it.

With OPA and Rego, the same rules apply across Terraform, Kubernetes and whatever else you can feed JSON. Start with the security policies you’d be embarrassed to explain in an incident review, get those passing, then widen the net. Rolling out fifty policies at once mostly teaches your team how to add exceptions.

Resources

Was this useful?

You might also enjoy

More posts on similar topics

Helm Charts: Templating & Multi-Environment Kubernetes Deployments

Helm Charts: Templating & Multi-Environment Kubernetes Deployments

Why Helm matters The Kubernetes manifest problem Managing Kubernetes manifests at scale becomes a nightmare. You have a deployment for dev, staging and production. Each one is 90% identi

Container Image Vulnerability Scanning in CI/CD with Trivy

Container Image Vulnerability Scanning in CI/CD with Trivy

Why container security matters Where the vulnerabilities hide A container image is one of the largest pieces of untrusted code you ship. Every image you build carries the base OS layer,

7 Reasons Learning the Linux Terminal is Worth It (Even for Beginners)

7 Reasons Learning the Linux Terminal is Worth It (Even for Beginners)

Why learn the Linux terminal? Why it still matters Even with the graphical tools and AI assistants available now, the terminal is the most direct way to work with a Linux system. It's a core

Managing Terraform at Scale with Terragrunt

Managing Terraform at Scale with Terragrunt

The problem with Terraform at scale Duplicated code across environments If you're managing infrastructure with Terraform across several environments or projects, you've probably hit the point

Securing CI/CD with IAM Roles

Securing CI/CD with IAM Roles

Why secure your CI/CD pipeline? Why pipeline security matters Your pipeline holds credentials for every environment you deploy to, which makes it one of the most valuable targets you own. A s

Understanding Kubernetes Services: ClusterIP vs NodePort vs LoadBalancer

Understanding Kubernetes Services: ClusterIP vs NodePort vs LoadBalancer

If you're working with Kubernetes, you've probably noticed that Pods come and go, and their IP addresses keep changing. That's where Services come in. They give you a stable way to keep your apps acce

6 related posts