Cloud and BYOC for Orca Agent Engine are in Private Preview — request an invite
Docs

Authorization

Decide which principals may make which calls through Orca AI Gateway, using static ACLs, an external policy engine, or your own service.

An authorizer runs after the principal has been established and before any budget or content check. It answers one question: may this principal make this call?

plugins:
  authorizers:
    - name: acl
      kind: yaml_acl
      required: true
      failure_mode: deny
      rules:
        - effect: allow
          action: invoke
          resource: { kind: model, name: "gpt-*" }

Authorizers are a list, so you can layer a fast local check in front of an external policy engine.

Available kinds

kindWhat it does
yaml_aclEvaluates static rules declared inline in the plugin config.
opa_httpDelegates the decision to an Open Policy Agent endpoint.
ext_procDelegates to your own gRPC service.
allow_allPermits everything. Intended for development.

The shipped binary has no usable cedar authorizer. orca-gateway check accepts kind: cedar, but the gateway then fails at boot with unsupported kind "cedar". Use opa_http for policy-engine authorization.

yaml_acl

The simplest option, and the right one when your rules are a modest, static list. Rules match on scope dimensions and the request. Declare them inline: the server does not load a file field for this authorizer.

Because it evaluates in-process with no network call, yaml_acl adds no meaningful latency, which makes it a good first layer even when a policy engine handles the harder cases.

A matching deny always wins over a matching allow; no matching allow denies the request:

plugins:
  authorizers:
    - name: inline-acl
      kind: yaml_acl
      rules:
        - effect: deny
          principal_kind: anonymous
          reason: authentication required
        - effect: allow
          action: invoke
          scope:
            workspace_id: ws_42
          resource:
            kind: model
            name: "gpt-*"
        - effect: allow
          action: invoke
          scope:
            workspace_id: ws_42
          resource:
            kind: route
            name: "*"

Model traffic is authorized twice: once for the requested model and again for the route selected by the routing policy. A production ACL needs matching allow rules for both resources.

Each rule can match principal_kind, scope, resource, action, and conditions. Resource names support exact, prefix, suffix, contains, and * glob patterns. Match scope only on dimensions that every accepted credential binds through a verified claim or API-key attribute; see Identity and scope.

Deny anonymous callers

A request that carries no credential reaches the authorizer as an anonymous principal. Add a deny rule for principal_kind: anonymous to every production ACL, as the example above does. Because a matching deny always wins, the gateway answers every request without a credential with 403 forbidden and the rule's reason. With opa_http or ext_proc, make your policy deny anonymous principals.

opa_http

Delegates to Open Policy Agent, which is the right choice once policy needs data the gateway does not hold - group membership, cost centers, an approval workflow.

plugins:
  authorizers:
    - name: opa
      kind: opa_http
      policy_url: "http://opa.svc:8181/v1/data/orca/allow"
      timeout_ms: 2000
      required: true
      failure_mode: deny

The gateway posts { "input": { "principal", "resource", "action", "scope", "request_id", "trace_id" } } and expects { "result": { "allow": true|false, "reason": "..." } }. Missing result is a deny.

An external authorizer puts a network call on the critical path of every request. Keep OPA close to the gateway, and think carefully about failure_mode: deny means an OPA outage stops all traffic, while allow means an outage silently disables authorization. Neither is free.

ext_proc

For authorization logic you want to own outright, run a gRPC service and point the gateway at it. The wire contract is the ext_proc protocol adapted from Envoy.

plugins:
  authorizers:
    - name: custom
      kind: ext_proc
      endpoint: "http://authz-sidecar:9000"
      timeout_ms: 500

Running it as a sidecar rather than a shared service keeps the call local and removes a cluster-wide dependency from the request path.

allow_all

plugins:
  authorizers:
    - name: dev
      kind: allow_all

Every request is permitted. Use it to get a development gateway running before policy exists, and make sure it never reaches a production config.

Choosing a failure mode

failure_mode decides what a runtime error from the authorizer means, not what a deny means - an intentional deny always refuses the request.

  • deny is the correct default. An authorizer that cannot reach its policy source should not let traffic through.
  • allow trades correctness for availability, and is only defensible when another layer is already enforcing the same rule.

Initialization errors currently fail gateway boot regardless of required. The flag is carried in configuration but does not change startup behavior or ongoing readiness aggregation.

On this page