Apache APISIX and Open Policy Agent authorization

Teams that want API access decisions in version-controlled Rego policies can connect Apache APISIX to Open Policy Agent with the opa plugin. This page covers what reaches OPA, how allow decisions are returned, and where OPA should run.

On this page

Apache APISIX Open Policy Agent authorization for API routes

Authorization logic often lives in several places: each service checks roles in its own code, gateway rules are written in a different format, and no single place shows who can call what. If you want one policy engine that decides access at the gateway, the APISIX opa plugin is a direct way to test that model. It sends request, route and consumer context from APISIX to an Open Policy Agent (OPA) policy written in Rego, and APISIX enforces the answer before the request reaches the upstream service. This keeps the decision logic in reviewable policy files rather than scattered across application code.

Before you design policies, confirm the exact fields that APISIX sends to OPA, the shape of the response it expects, and how it handles denials and errors. These details belong to the plugin documentation for the APISIX version you run, and they can change between releases, so check them against your target version rather than relying on an older example. Also confirm how the plugin behaves when OPA is unreachable, because that choice decides whether the gateway fails open or closed. Plan a test suite that sends allowed and denied requests for each route and consumer type.

APISIX is licensed under Apache-2.0 and built on NGINX and etcd, so the gateway's licensing and core components are settled before you add a policy engine. Deciding where OPA runs is a separate question. Running it beside the gateway keeps the decision path short and under your control, but it adds a service to deploy, version, monitor and back up. Ask your team to document who owns Rego policy changes, how policies are tested and released, and which audit records show each decision. Performance characteristics of the OPA call should be measured in your own environment, not assumed.

What the team needs before connecting OPA to APISIX

Connecting Open Policy Agent to APISIX depends on a few decisions made before any Rego is written: the APISIX release, the deployment mode, where OPA runs, and which upstream services will be covered. Each card below names what to confirm and who owns the answer.

Pin the APISIX release

Choose the exact APISIX version your team will standardize on and record it in the change plan. The downloads page lists 3.19.0 as released on September 28, 2026, but it does not mark any release as long-term support, so confirm with the vendor documentation which line your support window and upgrade plan will cover. Check the opa plugin behavior and configuration keys in the docs for that exact version before writing the integration.

Select the deployment mode

Decide between traditional, decoupled and standalone mode, because the mode determines where route and plugin configuration lives and how a policy change reaches the gateway. Traditional and decoupled modes depend on etcd, while standalone mode reads a YAML or JSON file or the API. Confirm the mode with your platform team and read the deployment modes documentation for the ports and admin settings each one requires.

Stand up OPA and its policy repository

Plan where the OPA instance runs, how it is versioned, and who approves policy changes. Policies in Rego should live in a Git repository with review and tests, and the team must decide how bundles or policy files reach OPA. Confirm the OPA version and bundle delivery method against the OPA documentation, and agree who owns the decision logic that APISIX will depend on.

Map network paths from APISIX to OPA

APISIX sends each authorization check to OPA over HTTP, so the gateway nodes need a reachable, low-latency path to every OPA endpoint they call. Document the source and destination addresses, ports, TLS settings and firewall rules for each environment. Confirm how OPA is reached during a zone or cluster failure, because a denied or failed call changes what users see.

Inventory upstream services and routes

List every upstream service, route and HTTP method that will be governed by OPA, along with the identity data each one expects. The inventory tells you which request headers, paths, consumer names and route metadata the policy needs and which ones are not required. Mark routes that are public, internal or partner-only, since each class may need a separate policy package and test set.

Agree on a test and rollback plan

Before enabling OPA on live routes, define how you will test allow and deny decisions, measure added latency and roll back if policy evaluation fails. Use a non-production environment that mirrors your route inventory and record the expected decision for each sample request. Confirm the failure behavior your APISIX version exposes so that a policy outage does not silently open or close access.

Configuration sequence for the APISIX opa plugin

This sequence moves one API authorization decision from application code or the gateway into an OPA Rego policy, proving each layer works on a single test route before production traffic depends on it. The output is a tested policy, a gateway route that consults it, and evidence of allowed and denied requests.

  1. Stand up OPA in a test environment

    The platform team runs OPA in a non-production environment that can reach the gateway, using the OPA version and deployment method approved for your organization. Confirm the OPA listening address and any TLS or authentication settings with the APISIX opa plugin documentation before you write the gateway configuration, rather than assuming defaults. Check that OPA answers its health endpoint from the gateway host or pod. This step is done when OPA responds to a basic request from the same network segment as APISIX.

  2. Load a first Rego policy

    The security engineer writes a deliberately small Rego policy that allows one method on one path for one known identity, and nothing else. Load it into OPA and query the policy directly with a hand-built input document that mirrors what the gateway will send. This confirms the rule logic before the gateway is involved. Done when the direct query returns the expected allow value for the permitted input and a deny for everything else.

  3. Expose a single test route in APISIX

    The platform engineer creates one route in a non-production APISIX instance that points to a harmless test upstream, with no other plugins attached. Use the Admin API or your configuration-as-code workflow, and record the route ID and the upstream it targets. Send a plain request through the route to confirm that the gateway forwards traffic before any authorization logic is added. Done when the test request reaches the upstream and returns the upstream's response.

  4. Configure the opa plugin on the test route

    Add the opa plugin to the test route, pointing it at the OPA host and the policy path that matches the package and rule you loaded in the second step. Keep the configuration in version control so the change can be reviewed and rolled back. Confirm each field name and its accepted values against the plugin documentation for your APISIX version. Done when the route saves without a configuration error and the gateway reports the plugin as active on that route.

  5. Send allowed and denied test requests

    The QA or security engineer sends one request that the policy should allow and one that it should deny, using known test identities and tokens. Record the gateway response code and body for each request. Compare the results against the expected outcome written down before the test. Done when the allowed request reaches the upstream and the denied request is refused, and both results match the expected outcome.

  6. Verify decisions in OPA logs

    The engineer checks that OPA recorded a decision for each test request, either in its decision log output or in the logging destination you configured. Match the decision entries to the two test requests by timestamp or request identifier. Confirm the input fields OPA received contain what the policy needs and nothing the policy should not see. Done when each test request has a matching decision entry and the input content has been reviewed against your data handling rules.

  7. Extend the policy to production routes

    The team adds the opa plugin to production routes one group at a time, using the same reviewed configuration pattern and a planned rollback path. Each route gets its own policy rules and a documented owner. Confirm with the vendor documentation how custom denial responses are configured before changing user-facing errors. Done when every production route in the first group returns the expected allow and deny results under monitoring, and the rollback has been rehearsed.

Mapping request, route and consumer data into the OPA input

This table compares the categories of data APISIX can place in the input sent to Open Policy Agent, where each value comes from, and what the Rego rule uses it for. Read each row as a decision: include a field only when a policy needs it, and treat tokens and personal data as excluded by default. The main takeaway is that the OPA input is an allowlist you design, not a copy of the whole request.

Data categorySource in APISIXPurpose in the Rego ruleSensitivity and what to confirm
HTTP method and pathRequest method and URI of the incoming requestMatches the operation a rule allows, such as read versus write on a resource pathLow sensitivity, but paths can embed identifiers; confirm how the opa plugin serializes the request into input
Selected headersNamed request headers the team chooses to forwardChecks tenant or version headers that the gateway trustsMedium; never forward Authorization or cookie headers; confirm which headers are included by default
Route identifierMatched route ID or name from the APISIX route configurationSeparates policies per API so one Rego package does not cover unrelated routesLow; confirm whether the route ID or the route name is sent and keep it stable across environments
Consumer identityConsumer name set by an authentication plugin such as key-auth, jwt-auth or openid-connectTies the decision to a known caller and its role or group membershipMedium; confirm which authentication plugin sets the consumer and whether group claims are mapped into the request context
Client attributes added by the teamValues set by upstream plugins or variables added to the request contextAdds business context such as customer tier, region or data classificationVaries; personal data should be excluded or pseudonymized, and each attribute should have a documented source
Token contentsDecoded claims from JWT or OpenID Connect validation, if the team passes them onCan carry roles, scopes and audience for fine-grained checksHigh; raw bearer tokens should not be sent to OPA, and claim forwarding should be limited to named claims
Client IP and network contextClient address and forwarded headers as seen by the gatewayRestricts access by network zone or source rangeMedium; confirm how X-Forwarded-For is trusted before the rule depends on it

How the allow response contract shapes enforcement

The policy result shape decides whether the gateway allows a request, so the contract between your Rego package and the opa plugin has to be settled before any route is switched over. The plugin reads a decision from the OPA response and acts on it. Your policy must return a value in the exact structure the current plugin documentation describes for allow decisions, and the team should not assume a structure from an older example or from another gateway. Confirm the field names, the expected types and the behavior for a boolean versus an object result against the documentation for the APISIX version you pin, then prove it with test requests on a staging route.

Treat a missing or undefined result as a denial. In Rego, a rule that does not match simply produces no value, and a naive integration can read that absence as success or fail in a way nobody tested. Write the policy so every path returns an explicit allow or deny, add a default deny rule at the top of the package, and write negative tests for requests with no matching role, an unknown route, a malformed token claim and an OPA timeout. Ask the gateway team to confirm how APISIX behaves when OPA is unreachable or returns a non-JSON body, because that failure mode belongs to your fail-closed design, not to a default you inherit.

Custom denial responses let you control the status code and body returned to the client when OPA refuses a request. The option names and their supported forms are plugin-specific and change between releases, so take them from the plugin reference for your pinned version rather than from this page. Decide what the body may reveal. A denial message that names the missing scope helps developers, but it can also tell an attacker which policy rules exist, so agree the wording with your security team. Keep the denial behavior under the same version control and test suite as the Rego policy, since a change to either one changes what clients can observe.

Where OPA should run next to the gateway

Running OPA beside APISIX, either as a sidecar container in the same Kubernetes pod or as a local process on the same virtual machine, gives the shortest path for each authorization call. The gateway talks to OPA over the loopback or pod network, so the decision adds little network time and does not depend on a shared service being up. The trade-off is that every gateway instance carries its own OPA, so policy bundles must reach every copy and version drift becomes possible.

  • Latency: Calls stay on localhost or the pod network, which is the lowest-latency option of the three.
  • Failure domain: A failing OPA affects only the gateway instance it runs with, but a bad bundle can affect every instance that loads it.
  • Who operates it: The platform team operates both components, so the same pipeline must roll out gateway and policy changes.
  • Deployment mode: In traditional and decoupled mode, the sidecar or local process sits with the data plane. In standalone mode, it works the same way, though the gateway configuration comes from a file or API rather than etcd.
  • Policy distribution: Confirm how bundles are pushed or pulled into each copy of OPA and how the team detects a copy running an old version.

Before choosing this option, confirm the resource overhead per instance with your own load tests, since it multiplies with every gateway replica.

Security settings for an OPA-backed gateway

Moving authorization into OPA makes the policy path a security boundary in its own right. The cards below cover the decisions to settle before production: who can reach OPA, who can change policy, what happens when OPA is down, what data leaves the gateway, and who can change the gateway configuration that calls OPA.

Restrict who can call OPA

Only the APISIX data plane should be able to send decision requests to OPA. Any other caller that can reach the OPA port could query or probe policy decisions. Confirm in your environment that OPA listens on a private interface or a dedicated network segment, that firewall or network policy allows only the gateway nodes or pods, and that OPA is not exposed through a shared ingress. Check the OPA endpoint setting in your route configuration against the address you intended.

Protect the policy repository

Rego policies decide who may call each API, so a change to a policy is a change to production access. Store policy in version control with branch protection, require review by a second person, and run automated tests against policy files before a bundle is published. Confirm who holds write access to the repository and to the bundle storage that OPA reads from, and whether those accounts use the same MFA and audit controls as your other production systems.

Fail closed on protected routes

Decide what the gateway does when OPA times out or returns an error. For protected routes, the safe default is to deny the request, so an outage in the policy service does not open the API. Confirm how the plugin is configured for each route, test the behavior by stopping OPA in a staging environment, and make sure monitoring alerts on denials that spike during an outage. Public routes can be handled differently, but that choice should be recorded.

Keep tokens out of OPA inputs

The input document sent to OPA can include request headers, route data and consumer details. Raw bearer tokens, API keys and session cookies should not be forwarded when the policy only needs claims or an identifier. Review which fields the plugin sends, strip credentials from the input, and check whether OPA decision logs are enabled. If they are, confirm they are redacted or masked, have a set retention period, and are restricted to the team that needs them.

Secure the Admin API

The Admin API stores the route and plugin configuration, including the OPA endpoint and the policy path each route uses. Anyone who can change that configuration can disable authorization or point a route at a different policy service. Confirm the Admin API is reachable only from management networks, that its access key is changed from the default and stored in your secrets system, and that configuration changes are reviewed and logged. Ask your team how the etcd store behind it is protected and backed up.

Testing policies before they block production traffic

Treat every Rego change as a release that needs tests before it reaches the gateway. Start with unit tests written for each rule using the OPA test tooling, so that each allow and deny path has a named test case with a fixed input document. Cover the cases that matter most for your APIs: a valid consumer on the right route, a consumer missing a required scope or role, a request to a path that has no rule, and malformed or missing headers. Confirm the exact input fields your APISIX configuration sends to OPA, because a test built on a guessed input shape passes locally and fails in production.

Next, replay traffic against a staging route that runs the same APISIX plugin configuration as production. Use recorded requests from your access logs where your data handling rules allow it, and synthetic requests where they do not. Compare the decision APISIX returns with the decision you expected for each case, and keep the replay set in version control next to the policy so it grows with every incident. If your process supports it, run the new policy in a shadow or log-only period, where decisions are recorded but not enforced, and review the denials it would have produced before switching enforcement on. The length of that period should come from your own change process, not from a default.

Store Rego policies in the same version control, review and approval workflow as application code, with the same owners and the same audit trail. Keep the previous policy bundle as a tagged, deployable artifact so that a rollback is a known action rather than an emergency rewrite. Before go-live, agree who can trigger a rollback, what signals (such as a spike in 403 responses on a route) justify one, and how the team confirms that the restored bundle is in force. Ask your DeployOpen or internal platform team to document this path as part of the runbook, and rehearse it once in staging.

Common failures when APISIX calls OPA

This table lists the failures most often seen when the APISIX opa plugin sends requests to Open Policy Agent, with the likely cause and the specific check that confirms it. Read each row against the gateway error log, the OPA decision log and the plugin configuration, starting with the first row that matches your symptom. Most failures trace back to connectivity, a mismatched policy path or an input shape that changed after an upgrade.

FailureLikely causeFix and where to check
OPA unreachable or timing outThe host, port or timeout in the opa plugin does not match where OPA listens, or a network policy blocks the gateway from reaching it.Confirm the endpoint and timeout in the plugin configuration, test the connection from the APISIX container or node, and check the APISIX error log for connection or timeout entries.
Policy path does not existThe policy path in the plugin points to a package or rule name that is not loaded in OPA, often after a rename or a bundle that failed to load.Compare the configured path with the package and rule names in your Rego files, then query OPA's policy listing and confirm the bundle or file was loaded without errors.
Undefined or unexpected result shapeThe policy returns undefined, or a value other than the boolean allow field APISIX expects, so the request is refused even though the logic looks correct.Query the decision in OPA directly with the same input, check that the rule defines allow as a boolean in every branch, and use the OPA decision log to see the raw result.
Consumer identity missing at OPAThe authentication plugin runs after the opa plugin in the plugin chain, so no consumer data exists when OPA is called.Review plugin priorities in the route or global configuration and confirm the authentication plugin runs first. Log the input that reaches OPA to see whether the consumer field is present.
Input fields differ after an APISIX upgradeA later APISIX release changed the request, route or consumer fields passed to OPA, so existing rules read missing or renamed keys.Before upgrading, capture a sample input from the current version and from the target version in a test environment. Check the plugin documentation and release notes for input changes and add tests that fail on missing keys.
Denials return an unhelpful bodyThe opa plugin returns its default denial response, which does not explain the reason or match the format your API clients expect.Set a custom denial status and body in the plugin configuration, using a reason supplied by the policy where your design allows it. Confirm the response in a test call and check the client error handling.
Policy changes not taking effectOPA is still serving an older bundle or cached data, or the gateway is calling a different OPA instance than the one you updated.Check the bundle revision reported by each OPA instance, confirm the running instance count and endpoints, and compare the decision log timestamps with your deployment time.

Questions buyers ask before connecting APISIX to OPA

What drives the effort of connecting APISIX to Open Policy Agent?

The effort is driven mainly by four things: the number of routes and consumers that need a decision, how complex the Rego policies are, which identity sources supply the claims and roles those policies read, and which deployment mode APISIX runs in. A few routes with role checks on a single identity provider is a small scope. Many routes with attribute-based rules, several identity sources and a split between traditional and decoupled deployments is a larger one. Ask the partner to list each of these four factors in the written scope so you can see which ones they counted.

Can our in-house team do this with existing Rego skills?

Often yes, if the team already writes and tests Rego and can run APISIX in a lab. The gateway side needs knowledge of routes, the opa plugin configuration and how APISIX forwards request data, and the policy side needs test discipline so that a changed rule cannot silently open an endpoint. Teams without either skill usually benefit from a partner for the first policy set, then keep ownership of later changes. Ask the partner to show how they would hand over policy tests and the gateway configuration so your team can run them without outside help.

What do we need to provide for the engagement?

Plan to provide access to the APISIX environment, the OPA deployment, and the identity provider that issues the tokens or claims your policies will read. You will also need named policy owners who can state which users may call which routes, and a set of test traffic that represents real requests, including denied cases. Without policy owners, the team writing Rego ends up guessing at business rules. Without test traffic, the first verification happens in production. Ask for these items to be listed by name in the scope so responsibilities are clear from the start.

How does the timeline relate to the agreed scope?

The timeline follows the scope that both sides sign before work starts. Each route group, policy set, identity source and environment in that scope adds planning, build and test work, and each change request after signing adds time again. Because most engagements are fixed-scope, the schedule should be tied to named deliverables and to the reviews where policy owners approve behavior. Ask the partner to state which milestones depend on your side, such as access grants or policy sign-off, so delays on your side are visible rather than hidden in the plan.

What should a quote for this work include?

A useful quote lists the routes and consumers in scope, the policy domains to be written, the identity sources and claims used, the deployment mode and environments, and the OPA hosting layout next to the gateway. It should state which tests are delivered, such as policy unit tests and end-to-end checks against the gateway, and how denial responses are handled. It should also separate one-time work from anything that recurs, such as policy changes, upgrades or support. DeployOpen does not publish a price list, so the quote follows from the written scope.

Which parts of the design depend on the deployment mode?

Where OPA runs and how policy data reaches it depend on how APISIX is deployed. APISIX supports traditional, decoupled and standalone modes, and the configuration path differs in each. In traditional and decoupled modes, the Admin API on port 9180 manages configuration, while in standalone mode configuration comes from a file or API. Confirm with the vendor documentation which mode your environment uses and whether OPA sits beside each gateway node or behind a shared service, because that choice affects latency and failure behavior.

Does moving authorization into OPA remove the need for security review?

No. Moving decisions into Rego policies centralizes logic, but the policies still need review by people who understand the access rules, and the gateway still needs hardening. Ask the partner how policy changes are reviewed, tested and approved, and how a failed or unreachable OPA call is handled. Security testing of the APIs and gateway can be scoped alongside the work, which is a separate deliverable from the policy build.

How DeployOpen scopes and delivers the APISIX and OPA integration

DeployOpen plans, implements, tests and documents self-hosted open-source platforms inside your own infrastructure, including Apache APISIX gateways that call Open Policy Agent for authorization decisions. We agree the scope in writing first, then build the policy path, test denial behavior and hand over the running system with its documentation.

How we scope

  • We list the routes and consumers that will call OPA and the decisions each route must return.
  • We agree which request, route and consumer fields reach OPA, and which fields stay out of the policy input.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts.

How we build

  • We configure the opa plugin on test routes, then write Rego policies against the agreed input and allow contract.
  • We set custom denial responses for each route so clients receive the status and body your API standards require.
  • We run OPA beside the gateway in your environment and test fail-open and fail-closed behavior when OPA is unreachable.

How we hand over

  • We deliver Rego policy source, plugin configuration and test cases in version control for your team to review.
  • We document the decision flow, input schema, denial responses and the steps to add or change a policy.
  • We walk your engineers through policy testing and rollback so your team can run the integration without us.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer after handover.
  • Retainers can cover APISIX and OPA version upgrades, policy changes and periodic authorization testing.
  • Ask for the support scope, response expectations and upgrade handling in writing alongside the initial quote.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.