stratium-pep extauthz¶
A gRPC server answering envoy.service.auth.v3.Authorization/Check — the
contract Envoy's ext_authz filter calls, synchronously, on every request it
fronts, before deciding whether to forward it.
Use it to police an agent's HTTP traffic. Every other mode sits beside the thing it enforces; this one sits beside Envoy, and Envoy does the enforcing on its word.
Where it sits¶
agent ──HTTP──▶ Envoy ──Check()──▶ stratium-pep extauthz ──▶ PDP
│ │
│◀── OK / PERMISSION_DENIED┘
▼
upstream service (only if OK)
The PEP never sees the request body or forwards anything. It answers one question per request, and Envoy acts on the answer.
Configuration¶
Six variables — the smallest surface of the five. Observed with an empty environment:
$ stratium-pep extauthz
stratium-pep: missing required configuration: STRATIUM_PEP_EXTAUTHZ_LISTEN_ADDR,
STRATIUM_PEP_PDP_ADDR, STRATIUM_PEP_AGENT_ID, STRATIUM_PEP_SUBJECT,
STRATIUM_PEP_CONNECT_TIMEOUT, STRATIUM_PEP_EXTAUTHZ_ALLOWED_HOSTS
| Variable | Example | Notes |
|---|---|---|
STRATIUM_PEP_EXTAUTHZ_LISTEN_ADDR |
127.0.0.1:10000 |
Where Envoy connects. |
STRATIUM_PEP_EXTAUTHZ_ALLOWED_HOSTS |
api.example.com,orders.internal |
Hosts this PEP will answer for. |
STRATIUM_PEP_PDP_ADDR |
localhost:50051 |
|
STRATIUM_PEP_AGENT_ID |
0f8f833a-… |
|
STRATIUM_PEP_SUBJECT |
you@example.com |
|
STRATIUM_PEP_CONNECT_TIMEOUT |
5s |
No session file, no approval durations, no cache window. Envoy's ext_authz
budget is milliseconds, not minutes, so this surface cannot hold a request open
waiting for anything — which is why the approval settings are absent rather than
optional.
Worked example¶
export STRATIUM_PEP_EXTAUTHZ_LISTEN_ADDR="127.0.0.1:10000" \
STRATIUM_PEP_EXTAUTHZ_ALLOWED_HOSTS="api.example.com" \
STRATIUM_PEP_PDP_ADDR="localhost:50051" \
STRATIUM_PEP_AGENT_ID="0f8f833a-ef4c-4e7e-bbb5-00d259cf5c19" \
STRATIUM_PEP_SUBJECT="agent-tester@example.com" \
STRATIUM_PEP_CONNECT_TIMEOUT=5s
stratium-pep extauthz
The Envoy side, in the listener that fronts the agent's traffic:
http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
# No failure_mode_allow. The default is deny-on-error, and that is the
# point: if this PEP is unreachable, requests must NOT sail through.
grpc_service:
envoy_grpc:
cluster_name: stratium_extauthz
timeout: 5s
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: stratium_extauthz
type: STATIC
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config: { http2_protocol_options: {} }
load_assignment:
cluster_name: stratium_extauthz
endpoints:
- lb_endpoints:
- endpoint:
address: { socket_address: { address: 127.0.0.1, port_value: 10000 } }
Never set
failure_mode_allow: trueon this filter. It converts every PEP outage into a blanket allow. Deny-on-error is Envoy's default and is the behaviour this design assumes.
The agent attaches its delegation token as a normal HTTP header:
How the decision is built¶
The tool identity, the bearer token, and a credential-stripped raw_input
are extracted from the CheckRequest. The request path becomes the catalogable
tool name, per tenant, exactly like a filesystem tool's name.
A request with no usable credential denies before the PDP is dialed. No token, no round trip, no allow.
What Envoy sees back¶
| PDP effect | Answer |
|---|---|
EFFECT_ALLOW |
OkResponse — Envoy forwards. |
EFFECT_DENY |
PERMISSION_DENIED, carrying the PDP's reason verbatim. |
EFFECT_ESCALATE |
The same PERMISSION_DENIED, plus the pending approval's id — in a dedicated response header and in the denial body. |
| anything unrecognised, including unset | Treated as deny, deliberately asserted rather than assumed. |
Escalation degrades to denial here rather than blocking, because Envoy's budget cannot accommodate a human. Retry once the approval lands.
Limits¶
- Per-request, not per-body. The decision is built from the request line, headers and host. Bodies are not inspected.
- No approval flow. By design, per the degrade above.
ALLOWED_HOSTScloses a replay, it is not a policy. It exists to stop a specific attack — a decision obtained for one host being replayed against another — which the request's ownHostalone could not prevent. What is permitted for an allowed host remains entirely the PDP's business.- One tenant. Like every other surface, the PDP it talks to serves exactly one tenant, named at that PDP's startup.
See also¶
proxy.md— the same idea for gRPC, without needing Envoy.../pep.md§ "Reading a denial".../../example/extauthz/— this surface as a runnable program, policing which LLM model an agent may call.