What is Open Policy Agent (OPA)?
Open Policy Agent (OPA) is an open-source policy engine that lets teams define and enforce policy separately from application code. It supports consistent policy enforcement across infrastructure, applications, APIs, and CI/CD workflows.
OPA is platform-agnostic, so teams can use it across Kubernetes, Terraform, service meshes, and deployment pipelines. Policies are written in Rego, a declarative language built for policy-as-code workflows, and can be stored, tested, and versioned in Git.
As a CNCF-graduated project, OPA is widely used for centralized policy enforcement in cloud-native environments.
Watch 5-min Wiz Code demo
Watch how Wiz Code applies a single policy engine across your code, IaC, and CI/CD pipelines, connecting every policy violation to its real cloud impact.

What is a policy in OPA?
In OPA, a policy is a set of rules that governs whether an action should be allowed, denied, or flagged for review. Teams use policies to enforce access controls, resource constraints, compliance requirements, and operational standards across cloud environments.
For example, policies can enforce rules such as:
No container may run as root
All S3 buckets must have encryption enabled
Only approved container registries may be used in production
Deployments fail if they violate predefined security baselines
These rules become more scalable when implemented as policy-as-code. Rather than relying on manual reviews or hardcoded checks, teams define policies in a declarative language, store them in version control, and test them like application code. This makes policy changes easier to review, audit, and enforce consistently across environments.
CI/CD Security Best Practices [Cheat Sheet]
Fortify your CI/CD pipelines with this guide on infrastructure security, code security, access, and monitoring.

How does OPA work?
OPA works by evaluating incoming requests against policies and returning a decision based on predefined rules. In most implementations, the evaluation flow follows three steps: input, policy evaluation, and decision output.
1. Input
OPA receives input as structured JSON data.
This input contains context about the request, such as:
Who is making the request
Which resource they want to access
What action they want to perform
Environmental context like namespaces, labels, or deployment metadata
For example, in Kubernetes, the input might include a pod specification submitted to the API server. In Terraform, it may contain the JSON output of a plan file before infrastructure is deployed.
2. Policy evaluation
OPA evaluates the input against policies written in Rego, its declarative policy language. Policies define the conditions that must be met for an action to proceed.
Because policies are externalized from application code, teams can update enforcement rules centrally without modifying individual services or deployment workflows.
3. Decision output
OPA returns a structured decision response. This often includes an allow or deny result, but policies can also return warnings, violations, metadata, or risk scores depending on the implementation.
In Kubernetes environments using Gatekeeper, teams commonly use three enforcement actions:
deny: Block the request entirely
dryrun: Log violations without blocking
warn: Allow the request while returning a warning
This entire process happens in memory and typically completes in sub-millisecond time, which means OPA adds minimal latency to production request paths.
Understanding Rego
Rego is OPA’s declarative policy language. Unlike imperative programming languages, where developers define every step required to reach a result, Rego focuses on describing the conditions that determine whether a decision passes or fails.
This distinction is important because policy logic becomes easier to read, audit, and maintain. Instead of tracing through application control flow, teams can review a policy directly and understand what it enforces. That makes Rego well-suited for security controls, compliance requirements, and operational guardrails that need to stay consistent across environments.
For example, a Rego policy might enforce rules such as:
Containers must not run as root
Only approved registries may be used
Infrastructure must include encryption by default
Rego policies can be stored in version-controlled repositories, tested with OPA’s built-in test framework, and rolled back if a change introduces unintended behavior. This allows policy changes to follow the same review and deployment workflows as application code.
To experiment with Rego interactively, teams can use the OPA Playground at play.openpolicyagent.org. The Playground lets you write policies, provide sample input, and evaluate policy decisions directly in the browser without installing OPA locally.
Why OPA matters for cloud-native security
As cloud environments grow, policy enforcement becomes harder to manage consistently. Different teams implement authorization checks in different ways, infrastructure standards drift between environments, and compliance requirements become difficult to audit at scale.
Security and compliance: OPA helps organizations automate security and compliance enforcement across infrastructure and deployment workflows. Teams can require encryption, restrict privileged workloads, enforce approved registries, and block insecure configurations before they reach production.
For example, OPA policies can prevent vulnerable container images from being deployed, which matters given that 12% of cloud environments currently expose vulnerable containers. Because policies are centrally managed and version-controlled, teams also gain a stronger audit trail for compliance reviews and security investigations.
Flexibility and scalability: OPA integrates across Kubernetes, Terraform, Envoy, CI/CD pipelines, and custom applications, allowing teams to apply consistent guardrails across different parts of the stack. This becomes increasingly important as organizations scale from a small number of services to hundreds of workloads across multiple cloud environments.
Decoupling policy from code: OPA externalizes policy decisions instead of embedding them directly into application logic. Rather than maintaining separate authorization checks across dozens of services, teams can define a single policy that applies consistently across Kubernetes clusters, APIs, CI/CD pipelines, and infrastructure workflows.
This gives security and platform teams two operational advantages:
Security agility: Security teams can update global policies without waiting for application deployment cycles or modifying individual services.
Developer focus: Engineers can spend less time maintaining authorization logic and more time building application functionality.
OPA integrations
OPA is designed to run across multiple control points in cloud-native environments. Rather than enforcing policies in a single platform, teams typically integrate OPA into Kubernetes admission control, infrastructure-as-code validation, and CI/CD pipelines so violations are blocked before they become production risks.
The following integrations represent some of the most common OPA deployment patterns.
Kubernetes and Gatekeeper
Gatekeeper is OPA’s Kubernetes-native integration. It runs as an admission controller webhook, intercepting requests to the Kubernetes API and evaluating them against policies before resources are created or modified.
Gatekeeper supports multiple enforcement modes, including deny, dryrun, and warn, allowing teams to gradually introduce policies before enforcing them fully in production.
This layered approach helps teams catch misconfigurations at multiple stages. OPA can evaluate Kubernetes manifests during CI/CD before deployment, while Gatekeeper enforces policies again at admission time inside the cluster.
For example, teams commonly use Gatekeeper to block privileged containers or require approved registries before workloads are deployed.
Example ConstraintTemplate that denies containers from running as root:
package k8srunasnonroot
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.runAsNonRoot != true
msg := "Containers must set runAsNonRoot: true"
}Terraform
With Terraform, teams commonly evaluate the JSON output of a plan against Rego policies before infrastructure changes are applied.
A typical workflow uses conftest to validate Terraform plans during CI:
terraform plan -out plan.out
terraform show -json plan.out > plan.json
conftest test plan.jsonPolicies can check for issues such as public exposure, missing encryption, or overly permissive IAM configurations. For example, a policy might require all AWS S3 buckets to have encryption enabled before terraform apply succeeds.
This is where infrastructure-as-code scanning becomes valuable for catching misconfigurations before deployment.
CI/CD pipelines and GitHub Actions
OPA is commonly used as a policy gate inside CI/CD pipelines. The simplest model treats policy evaluation like a unit test: if the policy fails, the pipeline fails.
For example, a GitHub Actions workflow might run policy validation against Kubernetes manifests before deployment:
- name: Policy check
run: |
conftest test ./k8s/manifestsThis allows teams to surface violations directly in pull requests and deployment workflows rather than discovering them after release. It also supports fail-closed enforcement models, where builds stop automatically when policy requirements are not met.
Teams often combine these workflows with Wiz Code to correlate policy violations with runtime risk, exposed workloads, and cloud context.
OPA vs. HashiCorp Sentinel
OPA and HashiCorp Sentinel both support policy-as-code workflows, but they serve different operating models. OPA is best for organizations that want one policy framework across multiple platforms, while Sentinel is a better fit for teams already standardized on HashiCorp tooling.
| Category | OPA | HashiCorp Sentinel |
|---|---|---|
| Deployment model | Open source, platform-agnostic | Proprietary, HashiCorp-native |
| Policy language | Rego | Sentinel language |
| Best fit | Multi-platform policy enforcement across Kubernetes, Terraform, APIs, CI/CD, and custom apps | Terraform-centric workflows in Terraform Cloud or Terraform Enterprise |
| Governance | CNCF-graduated, community-governed | Tightly integrated with HashiCorp tooling |
| Use case | Unified policy framework across environments | Embedded policy enforcement inside HashiCorp infrastructure workflows |
Best practices for OPA policy design
Effective OPA policies should be clear, modular, performant, and easy to maintain across large environments.
1. Define clear policy goals
Ensure each policy has a specific, measurable goal so teams can evaluate and maintain policies consistently. For instance, a clearly defined policy may require all containers to define resource limits before deployment.
The following example policy denies the creation of any pod in which containers lack defined resource limits:
package kubernetes.admission
deny[{"msg": msg}] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.resources.limits
msg := "All containers must have resource limits set"
}2. Use modular policy design
Enhance manageability by decomposing complex policies into smaller, reusable modules. In Rego, teams commonly use package namespacing to organize reusable policy modules across environments.
The following policy verifies if the container image originates from an approved registry by importing and utilizing a separate module:
package kubernetes.admission
import data.image_policy
deny[{"msg": msg}] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not image_policy.allowed_registry(container.image)
msg := "Container image must be from an allowed registry"
}
# image_policy.rego
package image_policy
allowed_registry(image) {
startswith(image, "myregistry.com/")
}3. Optimize for performance
Write efficient policies to minimize evaluation time, especially in high-throughput environments. The following policy precomputes a set of allowed namespaces to quickly check whether the pod's namespace is permitted.
package kubernetes.admission
# Precompute allowed namespaces
allowed_ns := { "default", "kube-system", "production" }
deny[{"msg": msg}] {
input.request.kind.kind == "Pod"
not input.request.object.metadata.namespace in allowed_ns
msg := "Pod namespace is not allowed"
}Partial evaluation and caching can further reduce latency when policies are evaluated frequently against similar inputs.
4. Implement logging and monitoring
Incorporate logging within policies to support auditing and troubleshooting workflows.
The following policy logs denied pod creation requests so teams can audit policy violations and investigate enforcement activity:
package kubernetes.admission
# A deny rule that prevents pod creation if containers don't have resource limits
deny[{"msg": msg}] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.resources.limits
msg := "All containers must have resource limits set"
# Log the denied request message for external logging purposes
logging_msg := sprintf("Denied request for Pod: %v, reason: %v", [input.request.object.metadata.name, msg])
log_violation(logging_msg)
}
log_violation(logging_msg) {
print(logging_msg)
}5. Regularly review and update policies
Policies should evolve alongside applications, infrastructure changes, and emerging threats. The following example expands an existing policy by adding a new rule that requires containers to run as non-root users to reflect new compliance requirements:
package kubernetes.admission
deny[{"msg": msg}] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.resources.limits
msg := "All containers must have resource limits set"
}
# New policy addition for compliance
deny[{"msg": msg}] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.securityContext.runAsUser == 1000
msg := "Containers must run as non-root user"
}Use the OPA test framework to validate policy changes before rolling them out, and keep policies in version control so you can track changes over time.
How Wiz enforces OPA policies across your cloud
Wiz applies OPA-powered policies consistently across the entire development lifecycle, from code to runtime. Instead of managing policies in isolation, teams can enforce guardrails across cloud environments while correlating violations with contextual risk factors such as external exposure, excessive permissions, and sensitive data access.
That context matters during prioritization. A policy violation on an internet-exposed workload with production database access presents a very different risk profile than the same violation in an isolated development environment. Wiz surfaces these combinations automatically so security teams can focus on the issues with the highest potential impact.
As organizations extend policy enforcement to AI workloads, Wiz also provides visibility into model pipelines and training data access, applying the same OPA-powered guardrails to emerging AI infrastructure.
To see how OPA-powered policy enforcement works in practice, get a demo of Wiz’s unified cloud security platform.
Secure your cloud from code to production
Learn why CISOs at the fastest growing companies trust Wiz to accelerate secure cloud development.