Open Policy Agent, usually shortened to OPA, is an open source, general-purpose policy engine that lets teams write authorization and compliance rules as code and enforce them consistently across many different systems, instead of hardcoding that logic separately inside each application or service. A team writes rules in OPA's own language, called Rego, feeds the engine some structured input describing a request or a resource, and gets back a decision: allow, deny, or a more detailed structured result depending on how the rule is written. It runs the same way whether it's checking a Kubernetes deployment, an API request, or a piece of infrastructure code, which is exactly what makes it general-purpose rather than tied to one specific domain.
The reason OPA exists is that authorization and policy logic tends to get duplicated and scattered across a codebase without something like it. Each service ends up with its own hardcoded checks (this user can do this action, this request is allowed from this network), written by different engineers, in different languages, with no single place to see or audit what the actual rules are. Changing a rule means finding and updating it in every service that implemented its own version, and there's no guarantee all of them got updated consistently or correctly. This is exactly the kind of drift that shows up during a security review, when two services that are supposed to enforce the same access rule turn out to behave slightly differently because one of them missed an update six months earlier.
What distinguishes OPA from writing that logic directly into application code is the separation it creates between policy and the systems that need to make decisions based on it. Rules live in Rego files, version-controlled like any other code, and any system that needs a decision (a Kubernetes cluster deciding whether to admit a workload, an API gateway deciding whether to allow a request, a CI pipeline deciding whether a Terraform plan is safe to apply) sends OPA the relevant input and gets a decision back, without needing to reimplement the rule itself. This is the same separation of concerns that made centralized logging and centralized configuration management valuable once organizations had more than a handful of services; OPA applies that same idea specifically to the question of what's allowed and what isn't.
By 2026, OPA is one of the most widely deployed tools in the policy as code space, having graduated as a project under the Cloud Native Computing Foundation and become the engine underneath related tools like Gatekeeper for Kubernetes admission control and Conftest for testing configuration files against policy. It shows up across infrastructure provisioning, container orchestration, API authorization, and CI/CD pipelines, largely because its general-purpose design lets one tool cover use cases that would otherwise need several separate, purpose-built systems. That breadth is a big part of why it's the tool most engineers reach for first when a policy as code project starts, even when the specific first use case ends up being fairly narrow.
This page covers how OPA actually evaluates a policy decision step by step, how it compares to hardcoding authorization logic directly into an application, the specific places OPA tends to show up in a real infrastructure stack, where it fits and where it doesn't, and how a team gets started with it without trying to rewrite every policy at once. The underlying idea is that decoupling policy from the systems that enforce it makes rules easier to see, easier to test, and easier to change consistently everywhere they apply.
The process starts with input: a piece of structured data, almost always JSON, describing whatever is being evaluated. This could be a request to an API (who's asking, what are they asking for, what's their role), a Kubernetes manifest about to be deployed (what does it request, what labels does it have), or a Terraform plan showing infrastructure about to be created. Whatever system needs a decision packages up the relevant details about that decision into this input format and sends it to OPA. Getting this input right is one of the more underrated parts of a successful deployment; a service that forgets to include a piece of context the policy actually needs will get a technically correct but practically wrong decision, and debugging that gap can be confusing if nobody thinks to check the input first.
OPA then evaluates that input against the Rego rules it's been loaded with. Rego is a declarative language, meaning a rule describes what should be true for a decision to be allowed, rather than a sequence of steps to execute. A rule might read, in plain terms, "allow this request if the user's role is admin, or if the user's role is editor and the resource being modified belongs to them." OPA runs the applicable rules against the input and computes the result. Multiple rules can apply to the same input at once, and Rego has specific conventions for how those combine into a final decision, which is one of the trickier parts of the language for newcomers to get comfortable with.
The output is a decision, which can be as simple as a true or false value (allow or deny) or, more often in real deployments, a richer structured result that includes the decision alongside additional details, like specific reasons for a denial or additional data the calling system needs. This output gets sent back to whatever system asked the question, and that system acts on it: an API gateway blocks or allows the request, a Kubernetes cluster admits or rejects the workload, a pipeline stops or continues. Including the "why," not just the "what," in that output matters a lot in practice, since a bare denial gives the requester nothing to act on, while a denial with a specific reason lets them fix the problem themselves.
The important architectural detail is that OPA itself doesn't take any action; it only makes decisions. The system asking the question is responsible for actually enforcing what OPA decided. This keeps OPA focused on one job and lets it be dropped into very different kinds of systems (a Kubernetes cluster, a microservice, a CI pipeline) without needing to understand or integrate with the specifics of what each of those systems does after receiving a decision, which is a big part of why it's usable in so many different contexts. It also means OPA itself can be swapped out or upgraded independently of the systems that call it, as long as the input and output formats stay stable, which is a useful property when a team wants to change how policies are evaluated without touching every calling service.
Hardcoded authorization logic means the rules about who can do what live directly inside the application's own code, usually as conditional statements scattered through whatever parts of the codebase need to make an access decision. This is often the fastest way to get something working, since there's no separate system to set up, and for a single small application with a small number of simple rules, it's a completely reasonable choice. Plenty of successful, well-run applications never need anything more sophisticated than this, and reaching for OPA before the underlying complexity actually exists just adds overhead nobody needed yet.
The problems show up as the organization grows past a single application. Every additional service that needs similar authorization logic either duplicates the same rules in its own code (with all the drift and inconsistency that duplication tends to introduce over time) or shares a library that gets out of sync across services running different versions of it. Auditing what the actual rules are, across an organization with dozens of services, means reading through code in every one of them, since there's no single place the rules live. This is often the moment a security team first raises the issue, usually after being asked a question like "which services currently allow this specific permission" and realizing there's no fast, reliable way to answer it.
OPA addresses this directly by pulling the rules out into one place, written in one language, that every service queries the same way. A change to a rule (say, adding a new role with specific permissions) happens once, in the Rego policy, and every service that queries OPA immediately reflects the updated rule the next time it asks, without needing a code change or a redeploy of the services themselves. Auditing becomes a matter of reading the policy files, not searching through a dozen codebases for scattered conditional logic. That single source of truth also makes onboarding new engineers faster, since understanding "how does authorization work here" becomes a matter of reading one set of Rego files instead of tracing logic through several unrelated repositories.
The tradeoff is added architectural complexity: a service now has a runtime dependency on OPA (or an embedded copy of it) for every decision that used to be a simple in-process check. This adds a network call or an embedded evaluation step where there wasn't one before, and it requires the team to actually learn Rego, which has its own learning curve. For a single small application with simple, stable rules, hardcoded logic can remain the more practical choice; OPA earns its complexity once there are multiple services that need the same rules applied consistently. A reasonable rule of thumb is to wait until at least two or three services genuinely need the same authorization logic before introducing OPA, rather than adopting it speculatively in anticipation of future growth that may or may not materialize.
Kubernetes admission control is one of the most common deployments, usually through Gatekeeper, a project built specifically to bring OPA into the Kubernetes admission control pipeline. Every time something gets deployed to a cluster, Gatekeeper intercepts the request, sends the relevant details to OPA, and blocks the deployment if it violates a policy, like requesting privileged access it shouldn't have or missing a required label. This is often the first place organizations adopt OPA, because Kubernetes provides a clean, well-defined hook for exactly this kind of check.
Conftest brings OPA to configuration file testing more broadly, checking things like Terraform plans, Kubernetes YAML files, or Dockerfiles against policy before they're ever applied or built. This is commonly wired into a CI pipeline as a step that runs before a deployment or an infrastructure change goes any further, catching policy violations at the point where they're cheapest to fix, before anything has actually been created. Because Conftest runs against plain files rather than a live cluster or a running service, it's often the easiest of OPA's common integrations to add to an existing pipeline, requiring no changes to the application or infrastructure being checked.
API and service-level authorization is a less standardized but increasingly common use, where a service embeds OPA directly (often as a library, sometimes as a sidecar process) and queries it for every incoming request that needs an access decision. Envoy, a widely used service proxy, has direct integration support for OPA for exactly this purpose, letting authorization checks happen at the network layer rather than inside every individual service's own code. This pattern is attractive specifically because it doesn't require touching application code at all; the proxy handles the check before a request ever reaches the service behind it.
Beyond these common patterns, OPA shows up in custom internal tools wherever an organization decides a decision should be driven by policy rather than hardcoded logic: feature flag rollout rules, data access controls, cost approval workflows. The general-purpose nature of OPA means it isn't limited to any one of these use cases; the input format is flexible enough that almost any decision reducible to "given this data, is this allowed" can be modeled as a Rego policy. Teams that adopt OPA for one purpose often find, six months later, that a second team has independently started using it for something unrelated, simply because the tool was already available and trusted internally.
OPA fits well anywhere a decision can be reduced to evaluating structured data against a defined rule, and where that same kind of decision needs to be made consistently across multiple systems. Kubernetes admission control, infrastructure provisioning checks, and API authorization across many microservices are all strong fits, because in each case the alternative is scattered, hard-to-audit logic duplicated across many places. The common thread across all of these fits is repetition: the same kind of decision needs to be made over and over, in more than one place, which is exactly the condition that makes centralizing the logic worthwhile.
It fits less well for a single small application with simple, stable authorization needs and no plans to scale that logic across additional services. Standing up OPA, learning Rego, and maintaining a separate policy deployment is real overhead, and for a small, contained use case, a straightforward conditional check inside the application is often genuinely the more sensible choice, at least until the organization grows into needing the consistency OPA provides. Introducing it too early for a single, simple case tends to slow the team down without a corresponding benefit, since there's no drift or duplication problem yet for OPA to solve.
It also fits poorly for decisions that need deep context OPA wasn't given as input. OPA can only decide based on what it's handed; if a decision genuinely requires real-time information that isn't practical to pass in (a live external system's current state, for example), OPA either needs that data fed to it as part of the input, which adds complexity to the calling system, or the decision needs to stay outside of OPA's scope entirely. It's not a general substitute for application logic that depends on runtime state beyond what's reasonably passed in as structured input. A common mistake here is trying to make OPA reach out and fetch additional context itself mid-decision; that's possible in some setups but adds latency and a new failure mode, and it's usually cleaner to gather the needed context before calling OPA in the first place.
Performance-sensitive paths deserve a specific mention. OPA evaluations are generally fast, but adding a decision call (whether over the network or via an embedded library) to a very high-throughput, latency-sensitive request path needs to be measured, not assumed. Most deployments handle this well, especially using OPA's embedded or sidecar deployment modes rather than a remote network call for every decision, but it's worth verifying rather than assuming it's a non-issue for a specific, unusually latency-sensitive system. Load testing the actual decision path, with realistic policy complexity, before rolling it out to a high-traffic service is a cheap way to catch a problem that would be far more expensive to discover in production.
Pick one well-defined, high-value use case rather than trying to centralize every policy decision in the organization at once. Kubernetes admission control through Gatekeeper is a common and reasonable starting point for organizations already running Kubernetes, because it comes with a fairly clear, contained scope: policies about what gets deployed to the cluster, evaluated at a well-defined point in the deployment process. Organizations without a Kubernetes footprint often start instead with Conftest against Terraform plans, since it requires the least new infrastructure to stand up and gives a fast first result to build confidence around.
Spend real time learning Rego before writing production rules, since it has a different mental model than most general-purpose programming languages that engineers are used to. It's declarative rather than imperative, which means describing the conditions under which something is true rather than writing a sequence of steps. Working through OPA's own documentation and a handful of small practice policies before touching anything production-facing pays off, because early mistakes in Rego tend to come from applying an imperative mindset to a declarative language. Pairing an experienced Rego author with newer team members on the first few real rules tends to shorten this learning curve considerably compared to everyone learning it independently from documentation alone.
Test policies the same way application code gets tested, using OPA's built-in testing framework to write unit tests for each rule against a range of inputs, including edge cases and cases that should be denied. Skipping this step and only testing policies manually against a few obvious cases is one of the more common ways teams get burned, discovering after the fact that a rule allowed something it shouldn't have, or blocked something legitimate, in a case nobody thought to check by hand. Treating test coverage for policy rules with the same seriousness as test coverage for application code is a habit worth establishing early, before the rule set grows large enough that testing feels like an afterthought nobody has time for.
Roll new policies out in a non-blocking or audit-only mode first, where OPA logs what decision it would have made without actually enforcing it, before switching to active enforcement. This mirrors the same warning-first approach that policy as code broadly benefits from, and it's specifically important with OPA because Rego's flexibility makes it possible to write a rule that behaves subtly differently from what was intended, and that difference is much cheaper to catch in audit mode than after it's already blocked real traffic. Give a new policy at least a couple of weeks in audit mode before flipping it to enforce, long enough to see it run against a genuinely representative slice of real traffic rather than just a quiet Tuesday.
Open Policy Agent is an open source, general-purpose policy engine that evaluates rules written in its own language, Rego, against structured input to produce automatic allow, deny, or detailed decisions, used to enforce authorization and compliance rules consistently across systems.
Rego is the declarative policy language OPA uses to write rules. Instead of a sequence of steps, a Rego rule describes the conditions under which a decision should be true, which OPA then evaluates against whatever input it's given.
Yes. OPA is open source and free to use, maintained as a project under the Cloud Native Computing Foundation, which it graduated from after reaching a mature, widely adopted state.
The most common integration is through Gatekeeper, a project built specifically to bring OPA into Kubernetes admission control, intercepting deployment requests and checking them against Rego policies before allowing them into the cluster.
Yes. OPA is used for API and microservice authorization, infrastructure provisioning checks through tools like Conftest, service mesh authorization through integrations like Envoy, and custom internal policy decisions of many kinds.
In most deployments, no, since evaluations are fast and can run embedded within the application rather than over the network. For unusually latency-sensitive systems, it's worth measuring the actual impact rather than assuming it's negligible.
OPA separates policy logic from the application, letting rules live in one place and be queried consistently by multiple services, whereas hardcoded logic tends to get duplicated and drift out of sync across services over time.
It has a real learning curve for engineers used to imperative programming languages, mainly because it's declarative. Most teams find it manageable with dedicated practice time and OPA's own documentation, but it shouldn't be treated as a quick, no-effort addition.
Policy as code is the broader practice of writing rules as version-controlled code that gets enforced automatically. Open Policy Agent is one of the most widely used tools for actually implementing that practice, providing both the Rego language and the engine that evaluates it.