# OPA policies

> How the Agent Gateway uses Open Policy Agent (OPA) and the Rego language for layered, declarative access control across gateway and surface policy layers.
Policies are the gateway’s decision engine for request access. They define who may do what, and under which conditions, and determine whether traffic is allowed, denied, or subjected to extra checks.

## What a policy is

A policy is a rule set written in Rego and evaluated by the gateway’s built-in policy engine. Agent Gateway embeds regorus (Rust-native OPA) in-process, so policy decisions run directly in the request path with no external OPA service.

Every meaningful request is evaluated against applicable policies before processing continues.

A policy can be enabled or disabled at any time. An enabled policy is evaluated on all matching requests. A disabled policy is skipped entirely without deleting the rule.

## Policy scopes

Policies are organised into two scopes, presented as tabs in the Policies page.

| Scope | What it controls | Runs | Effect of denial |
| Gateway | Cluster-wide rules applying to all traffic. | First, after authentication. | Final. Cannot be overridden by surface policy. |
| Agent Surface | Rules attached to a specific surface: inbound requests, outbound target behaviour, and responses. | After gateway policy. | Denies the request for that surface only. |

Use gateway scope for non-negotiable organisation guardrails. Use surface scope for surface-specific refinements.

## What a policy can inspect

When a policy runs, it receives structured context in the input document.

| Context | What it contains |
| HTTP details | Method, path, and request headers. |
| Direction and parties | Inbound or outbound. Source and target gateway node IDs (source_id, target_id), used to identify which gateway or endpoint originated and is receiving the request. |
| Surface context | Surface identifier, name, and active variant when relevant. |
| Caller identity | Authenticated caller context. The method field identifies the auth variant: jwt_bearer (subject and claims), api_key (key name), did_auth (DID), or mtls (principal and certificate fields). |
| Protocol context | MCP method, tool name, resource URI, and prompt name on MCP surfaces. A2A message and method on A2A surfaces. |
| Agent context | Agent card and trust registry result, when Extract Trust Registry Data is enabled. |
| Payment context | Payment gate state and metadata, when a Payment element is configured. |

See the [OPA policy input reference](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/policy-input.md) for the complete input document schema and all namespace paths.

## Policies in the UI

Within each scope tab, policies are listed with their name, description, a preview of the first rule line, status (Enabled or Disabled), and timestamps. Policy edits take effect on subsequent requests immediately, with no gateway restart required.

## Where policies fit in the gateway

Policy evaluation is woven through the request pipeline.

### Standard evaluation order

On inbound flows, gateway scope is evaluated first, after authentication. Surface scope is evaluated later, before forwarding. A denial at either stage is final.

  Inbound request
  →
  Authentication
  →
  Gateway policy
  →
  Surface policy
  →
  Forward to target

This layered model lets you enforce non-negotiable controls at gateway scope while delegating surface-specific refinements to individual surfaces.

### MCP tool policies

MCP surfaces support an additional inline policy mechanism called MCP Tool Policies. Add it by dropping the MCP Tools element from the element palette onto the surface canvas. Each entry in the element binds a tool_name to a policy_definition_id, and you can add multiple entries. Enforcement is an allowlist scoped to tools/call and is active whenever the list is non-empty (there is no separate enable toggle):

| Scenario | Behaviour |
| Non-tools/call method (for example initialize, tools/list) | Not gated. Passes through regardless of the tool policy list. |
| tools/call for a tool with no matching entry | Denied. Default-deny applies whenever the list is non-empty. |
| tools/call for a tool with one or more matching entries | Each matching entry is evaluated in declaration order. Entries whose policy definition is disabled are skipped. The first enabled entry returning false denies the request. If all matching entries are skipped (all definitions disabled), the request is allowed. |

This behaviour is identical on the direct surface path and the Gateway Connection path.

## How Rego policies work

A Rego policy is a text file containing a package declaration, an optional default rule, and one or more conditional rules.

```rego
package surface.policy            # Package name must match the layer (see above)

default allow = false             # Deny unless a rule explicitly returns true

allow if {                        # Rule: allow when all conditions in the block are true
    input.source_auth.subject     # Condition: authenticated subject must be present
    input.mcp.tool_name           # Condition: a tool name must be present in the request
}
```

Rego evaluates rules by trying every block that uses the same rule name. If any block evaluates to true, the overall rule is true. Rules are evaluated against the structured input document described below.

### Default allow vs default deny

```rego
default allow = false    # Safe default: deny all unless explicitly permitted
default allow = true     # Permissive default: allow all unless explicitly denied
```

Starting with default allow = false and explicitly allowing what you need is safer for production use.

## Use cases

### MCP surface: restrict tool access by role

A surface serving an MCP tool server needs to give admin users full access and limit all other authenticated users to a safe subset of tools.

The surface-level policy (package surface.policy) checks the JWT role claim and the requested tool name. The gateway populates input.source_auth from a validated bearer token and input.mcp.tool_name from the parsed MCP request body.

```rego
package surface.policy

default allow = false

# Admin users can call any tool.
allow if {
    input.source_auth.claims.role == "admin"
    input.mcp.method == "tools/call"
}

# Authenticated users can call safe tools only.
allow if {
    input.source_auth.subject
    input.mcp.method == "tools/call"
    safe_tool(input.mcp.tool_name)
}

# All authenticated users can use non-tool MCP methods.
allow if {
    input.source_auth.subject
    input.mcp.method != "tools/call"
}

safe_tool("search") := true
safe_tool("summarise") := true
safe_tool("translate") := true
```

### A2A surface: require trusted agents

A payment surface only accepts A2A requests from agents that are verified in the trust registry and have a resolvable DID.

The surface-level policy (package surface.policy) accesses input.agent.*, which the gateway builds from the agent card and trust registry lookups when Extract Trust Registry Data is enabled on the surface. If a field referenced in a rule condition is absent from input.agent, that condition evaluates to undefined and the request is denied.

```rego
package surface.policy

default allow = false

allow if {
    input.agent.did
    input.agent.trust_verification == true
}
```

## Further reading

For deep dives into Rego syntax, operators, and built-in functions, see the official OPA documentation:

- [Rego policy language](https://www.openpolicyagent.org/docs/latest/policy-language/): Operators, sets, comprehensions, imports, and rule types.

- [Rego built-in functions](https://www.openpolicyagent.org/docs/latest/policy-reference/): String, numeric, object, set, time, and HTTP functions available in any rule.

- [OPA Playground](https://play.openpolicyagent.org/): Interactive environment for testing policies against JSON input before deploying.

- [Policy testing](https://www.openpolicyagent.org/docs/latest/policy-testing/): How to write unit tests for Rego policies using the rego_test.rego convention.

## Related

- [OPA policy input reference](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/policy-input.md): Complete input field reference, covering all namespaces, availability by evaluation path, source_auth variants, and the McpPolicyContext schema for MCP tool policies.

- [Agent identity and DIDs](/products/affinidi-trust-fabric/agent-gateway/concepts/identity.md): How agent identity is resolved and made available in surface-level policies.

- [Trust registries](/products/affinidi-trust-fabric/agent-gateway/concepts/connections/trust-registry.md): How the gateway queries trust registry records to populate input.agent.trust_verification.

- [Surfaces](/products/affinidi-trust-fabric/agent-gateway/concepts/surfaces.md): The full request processing pipeline, including where policy evaluation sits.
