How it attaches
beacon-gateway is an Envoy
External Processing
(ext_proc) server. Envoy opens one gRPC stream per HTTP exchange and sends it the request and
reply headers and bodies. Anything built on Envoy’s HTTP filter chain can use it: plain Envoy,
Envoy Gateway and Istio gateways or sidecars.
Envoy carries the provider’s own wire format, so beacon-gateway decodes the bodies the client
sent and the provider returned. Only a POST with a body to a model endpoint is decoded. The
path decides the protocol:
Everything else (model lists, token counting, embeddings, OpenAI Assistants thread messages)
passes through untouched.
What is supported
Envoy must see the request in plain text. Put the
ext_proc filter on a listener where the
client’s TLS is terminated (an API gateway, an egress gateway that originates TLS to the provider),
not on a TCP passthrough.Configure beacon-gateway
beacon-gateway.yaml
max_body passes through unrecorded. The listener speaks plain gRPC with no
authentication, so expose it only to Envoy.
Deploy with Envoy
gateway/deploy/envoy/envoy.yaml is a complete, observe-only configuration. The parts that
matter:
envoy.yaml (excerpt)
- Request
BUFFERED. The request arrives whole and is sent in one message. Raiseper_connection_buffer_limit_byteson the listener and the provider cluster to matchmax_body(the example uses 32 MiB); Envoy’s 1 MiB default is too small for a long agent conversation. - Reply
STREAMED. Each chunk is forwarded as soon asbeacon-gatewayacknowledges it, which it does at once, so streaming keeps its token-by-token latency. - The
beacon_gatewaycluster needs HTTP/2 (http2_protocol_options), as every gRPC cluster does. - Route timeout. Long generations outlast Envoy’s 15 s default; the example sets
600s.
beacon-gateway tells buffered from streamed bodies by what arrives, so no setting on its side
has to match Envoy’s processing mode.
Validate and run the example:
provider cluster points at a local test upstream. For a real provider, point it
at api.anthropic.com:443 or api.openai.com:443 with an UpstreamTlsContext and set
auto_host_rewrite: true on the route (both are in the file’s comments). Then point clients at
Envoy, for example ANTHROPIC_BASE_URL=http://<envoy>:10000 for Claude Code.
Deploy with Envoy Gateway
Runbeacon-gateway as a Deployment with a Service on port 4021, and attach it to the
HTTPRoute that carries model traffic with an EnvoyExtensionPolicy:
envoy-extension-policy.yaml
ClientTrafficPolicy connection.bufferLimit) to cover large requests. If the gateway
authenticates callers with a SecurityPolicy JWT provider, use its claimToHeaders to put the
caller’s claims on headers and name those headers in identity_headers.
Deploy with Istio
Insert the filter with anEnvoyFilter on the workload that terminates the model traffic, such
as an egress gateway that originates TLS to the provider:
envoyfilter.yaml
beacon-gateway Service port grpc (or set appProtocol: grpc) so Istio uses HTTP/2
to it. For a sidecar, use context: SIDECAR_OUTBOUND and select the workload’s labels instead;
the sidecar sees plain text only when the application sends HTTP and the mesh originates TLS.
Troubleshooting
Related
LLM gateways
What gateway collection records and the settings shared by every gateway.
LiteLLM
Attach to a LiteLLM proxy instead.