Open Policy Agent and Rego: Policy Evaluation Explained
Open Policy Agent (OPA) helps teams apply policy checks across services, Kubernetes clusters, and infrastructure workflows without embedding every rule in application code. Policies are written in Rego, evaluated against structured input, and returned as decisions for another component to enforce. This explainer covers OPA’s architecture, Rego’s role, Kubernetes integration boundaries, and a small policy you can run and test locally.
What Is Open Policy Agent?
Open Policy Agent is a general-purpose policy engine: software that evaluates a query against policy rules and supplied data, then returns a result. The calling system decides what to do with that result. An API can reject a request, a deployment pipeline can fail a plan, or a service can allow an operation. OPA itself does not automatically block actions throughout an environment.
OPA separates policy decisions from the component that enforces them. A service can send JSON input to an OPA process over its API, or an application written in Go can embed OPA. The OPA project repository describes the engine as a general-purpose policy engine. Its official documentation covers the runtime, policy distribution, integrations, and decision APIs.
Rego is the declarative language used to express rules over structured data such as JSON. Instead of writing a sequence of instructions that modifies an object, a policy describes conditions under which a result is true or what information a query should return. The Rego policy language guide explains its syntax, data model, and evaluation behavior.
The Problem OPA Solves
Without a policy engine, teams often place rules directly in application branches, CI scripts, admission webhooks, and cloud-specific controls. That can produce repeated checks with subtly different meanings. Changing a rule then requires finding every copy, coordinating releases, and confirming that each integration applies it consistently.
OPA offers a shared evaluation model: policy can be reviewed, versioned, tested, and distributed separately from the systems that ask policy questions. A service can use the same decision logic as a pipeline while supplying context appropriate to its own request. This is useful when rules change more frequently than the consuming application or need to be understood and audited independently.
The separation also adds responsibility. A policy result is only as trustworthy as its input, policy version, and enforcement point. OPA does not automatically discover every resource, obtain fresh identity data, or make a caller enforce a denial. Teams must decide how policy and data reach each runtime, how the caller handles errors, and what happens if an evaluation is unavailable.
How OPA and Rego Evaluate a Decision
The usual flow has four parts:
- A policy enforcement point (PEP) receives an action, such as a Kubernetes admission request or an API call. It prepares the attributes the policy needs.
- The PEP sends input to an OPA runtime. Input is structured data, usually JSON. OPA can also evaluate against data that was loaded with the policy or delivered separately.
- OPA evaluates a query using Rego rules and the provided input and data. A query may return a boolean, a structured decision, a list of violations, or other JSON-compatible output.
- The PEP acts on the result. It allows, rejects, warns about, or otherwise handles the request according to the integration’s contract.
This division is often described as a policy decision point (PDP) and a policy enforcement point. OPA is the PDP; the service, API server, gateway, or pipeline is the PEP. Keeping them distinct makes it possible to reuse decision logic, but the enforcement component still needs clear behavior for denials, malformed responses, timeouts, and unavailable policy services.
| Integration | Where evaluation runs | Main trade-off | Typical fit |
|---|---|---|---|
| OPA as a local service | A process or sidecar called through OPA’s API | Supports clients in different languages, but adds a process and request boundary | Services that need a common policy interface |
| OPA embedded in an application | In the application’s process through a library | Avoids a network hop, but couples runtime upgrades and integration to that application | Go applications that need in-process evaluation |
| Gatekeeper for Kubernetes | A Kubernetes controller and admission webhook using OPA | Adds Kubernetes-specific resources and operations | Cluster admission rules managed as Kubernetes objects |
| Kubernetes ValidatingAdmissionPolicy | Inside the Kubernetes API server using CEL, not OPA | Less infrastructure for supported expressions, but a different language and feature set | Straightforward request validations native to Kubernetes |
For Kubernetes, the API server can send matching requests to an admission webhook. The Kubernetes documentation on dynamic admission control describes that request and response boundary. Gatekeeper builds a Kubernetes policy controller around OPA; it is an integration built on OPA, not simply another name for the standalone engine. The native ValidatingAdmissionPolicy and CEL explainer covers the alternative that evaluates supported rules within the API server.
Components and Key Concepts
Input is the request context supplied by a caller. For authorization, it might contain a user, action, and resource. For Kubernetes, it can contain an admission review with the object and request metadata. Keep inputs explicit and minimize sensitive fields that policies do not need.
Policy is the collection of Rego modules that define decisions. A module declares a package, may import language features, and defines rules. Policies are data-driven: a rule can refer to input and to data supplied alongside the policy. Rules should make default behavior deliberate, especially for access decisions.
Data contains values used by rules, such as an approved list of regions or team ownership information. Data can be packaged with policy or supplied to the runtime. This separation lets teams update reference data without rewriting every rule, but each deployment still needs a clear freshness and ownership model.
The OPA runtime and query interface evaluate a named query. OPA can run as a local service or be embedded; clients and deployment patterns determine how requests reach it. A service integration should define timeouts, health checks, and fail-open or fail-closed behavior rather than treating every evaluation error as an ordinary policy denial.
Bundles and decision logs help operate policy at scale. Bundles package policy and data for distribution to OPA instances. Decision logging records information about evaluations for later review, subject to configured masking and retention. Both features need operational controls: a bundle should be tested before rollout, while logs should not expose secrets or personal data unnecessarily.
Real-World Use Cases
- Kubernetes admission: Validate workload objects before they are accepted, for example by requiring an approved image registry or disallowing privileged containers. Gatekeeper supplies the Kubernetes-facing resources and webhook integration; it does not remove the need to test policies and plan availability.
- API authorization: Evaluate whether a subject can perform an action on a resource, with the application remaining responsible for authentication and enforcement.
- Infrastructure plans: Inspect structured plan output in CI for requirements such as mandatory tags or restricted regions. Terraform workflows for teams discusses where policy checks can fit into plan and review stages.
- Cloud governance: Reuse policy decisions across provisioning and service boundaries while keeping provider-native controls in place where they offer stronger integration.
OPA is not a replacement for every domain-specific feature. For example, Kubernetes Pod Security Admission applies built-in Pod Security Standards, while CEL-based policies handle supported Kubernetes request checks. Choose OPA when the need for reusable, programmable decisions outweighs the cost of operating or integrating another evaluation runtime.
Getting Started: Evaluate a Policy Locally
Install the OPA CLI from the official installation documentation. On macOS, Homebrew can install it with brew install opa. On Windows, download and run the official binary in PowerShell:
Invoke-WebRequest -Uri https://openpolicyagent.org/downloads/latest/opa_windows_amd64.exe -OutFile opa.exe
.\opa.exe version
On Linux, download the static binary and make it executable:
curl -L -o opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64_static
chmod 755 opa
./opa version
Create policy.rego. This small authorization example allows one specific read request and denies other inputs by default:
package authz
import rego.v1
default allow := false
allow if {
input.user == "alice"
input.action == "read"
input.resource == "report"
}
Create request.json with the attributes the policy expects:
{
"user": "alice",
"action": "read",
"resource": "report"
}
Evaluate the named rule:
opa eval --format pretty --data policy.rego --input request.json 'data.authz.allow'
The result is true. Change the action to delete and evaluate again; the default result is false. This demonstrates policy evaluation only: no user account or report is changed, and no application request is blocked.
Add policy_test.rego to test both outcomes:
package authz
import rego.v1
test_reader_can_read_report if {
allow with input as {"user": "alice", "action": "read", "resource": "report"}
}
test_reader_cannot_delete_report if {
not allow with input as {"user": "alice", "action": "delete", "resource": "report"}
}
Run checks before sharing or integrating the module:
opa fmt --write policy.rego policy_test.rego
opa check .
opa test . -v
In a real integration, replace the example attributes with the documented input contract of the caller. For Kubernetes, test against representative AdmissionReview objects and verify the exact response behavior in a non-production cluster. For CI, test both compliant and noncompliant plans. Version policy alongside its tests, review input changes, and roll out enforcement gradually so a missing field or incompatible policy does not surprise applications.
Common Misconceptions
“OPA enforces every policy by itself.” OPA evaluates a query and returns a result. The caller must interpret it and enforce the intended action. If the caller ignores a denial, the policy has no preventive effect.
“Rego is a script that runs arbitrary steps.” Rego is declarative: rules describe relationships and results rather than a procedural sequence. It is designed for queries over structured data, and operational integrations should keep evaluation inputs explicit and bounded.
“OPA and Gatekeeper are interchangeable.” OPA is the policy engine. Gatekeeper adds Kubernetes resources, controllers, and an admission integration built around OPA. A standalone OPA deployment has a different operational interface.
“A successful local test proves production enforcement works.” Unit tests validate policy behavior for supplied inputs. They do not verify the caller sends the expected data, the right policy version is loaded, or that the enforcement point handles errors safely. Test the complete request path before relying on a rule.
Related Articles
- Kubernetes ValidatingAdmissionPolicy and CEL explained
- Kubernetes Pod Security Admission
- Terraform workflows for teams
- Cloud governance frameworks
- Container security best practices
Changelog
- Initial publication.

