http lane inspects requests and responses. Envoy’s ext_authz already hands OPA the method, path and headers of a request, and the lane keeps that arrangement. It adds two things ext_authz cannot do by construction: it reads the response, which is where data leaves the building, and it keys policy on a stable resource identity instead of raw paths.
config.yaml
The normalized resource
Policy keyed on raw paths needs a regex per endpoint. The codec collapses dynamic segments to*, so /users/12345/orders/98765 becomes /users/*/orders/* and one http_resource rule covers the endpoint:
The slug survives on purpose: nothing distinguishes
/users/alice from /users/settings, and collapsing it would widen every rule written against either without warning. In doubt the codec keeps the segment, so a policy can end up too narrow but never too broad. File extensions survive too (/reports/12345.pdf → /reports/*.pdf), because a policy may allow *.csv and deny *.sql.
The http block
The defaults expose nothing: no bodies, no headers. Everything you capture reaches the policy engine, the audit trail and, where an analyzer is configured, a third party, so capture is opt-in per field.
Identity
identity_header names the header your authenticating proxy sets, and the subject lands in every audit row and in input.context for OPA. Trusting a header is safe only when nothing but that proxy can reach the listener, so bind loopback or a unix socket. On a listener reachable from anywhere else, a caller can assert any identity.
Masking
HTTP declares its body length in a header the gate can correct, so masking works by substitution: the gate rewrites values in place and retagsContent-Length for the size delta. It rewrites only when it can do so soundly, meaning a complete header block, exactly one Content-Length, and a declared length matching the bytes present. In any other case it forwards the original bytes, because a wrong Content-Length desynchronizes each request that follows on a keep-alive connection.
A chunked response has no Content-Length and goes through unmasked. Where masking is the control, keep the upstream on plain responses, or put a guardrail on the resource instead.
Denials
A denied request returns403 Forbidden with the rule’s message and Connection: close:
The Envoy lane
Keep your existingext_authz filter, and OPA still answers reachability first. The one change is the route’s cluster, which points at the Sidecar instead of at the service:
envoy.yaml
httpbin lane in deploy/docker-compose/envoy-stack/ runs exactly this shape:
Next
Guardrail Rules
http_resource globs, http_status ranges, and deferring a match to Rego.Risk Analysis
Why an
ai_analysis rule on this lane requires capture_body, and what it costs.