| Attachment | Type URL (@type) | Per-route override | Build feature |
|---|---|---|---|
HTTP filter chain (http_filters) | type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor | Yes — envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute, or envoy.config.route.v3.FilterConfig | None |
What it does
External processing (ext_proc) hands each request and response to a gRPC service you run, which can mutate headers and bodies or answer immediately on Arion's behalf. processing_mode decides what is sent — headers, bodies, trailers, in streamed or buffered form — so the processor sees only what it needs. It is the extension point for logic that lives outside the proxy; for in-process extension see Wasm filters.
Minimal configuration
From arion-runtime-ext_proc.yaml; the fragment is an entry in http_filters, before the router. The target cluster must speak HTTP/2:
- name: ext_proc
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor
failure_mode_allow: false
message_timeout: 5s
processing_mode:
request_header_mode: "SEND"
response_header_mode: "SKIP"
grpc_service:
envoy_grpc:
cluster_name: ext_proc_serverFields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
grpc_service | object | Yes | — | Processor target: envoy_grpc (cluster_name, optional max_receive_message_length) or google_grpc (target_uri), plus an optional timeout. |
failure_mode_allow | bool | No | false | Continue when the processor is unreachable or errors. When false, processor message timeouts return 504 and processor or stream errors return 500. |
processing_mode | object | No | headers only | Per-phase modes, below. |
message_timeout | duration | No | 200ms | How long to wait for the processor's reply to each message. |
max_message_timeout | duration | No | unset | Upper bound the processor may raise the timeout to. |
mutation_rules | object | No | unset | Restrict header mutations with allow_all_routing, allow_envoy, disallow_system, disallow_all, allow_expression, disallow_expression and disallow_is_error. Omitting the object applies no mutation-rule restrictions. |
forward_rules | object | No | all | allowed_headers / disallowed_headers matcher lists limiting which headers are sent to the processor. |
allow_mode_override | bool | No | false | Let the processor change the processing mode mid-stream. |
allowed_override_modes | list | No | empty | Processing modes the processor may switch to. |
route_cache_action | enum | No | DEFAULT | DEFAULT, CLEAR or RETAIN the route after header mutations. |
send_body_without_waiting_for_header_response | bool | No | false | Stream body chunks without waiting for the header reply. |
observability_mode | bool | No | false | Fire-and-forget: send messages but never wait for answers. |
disable_immediate_response | bool | No | false | Ignore immediate_response messages from the processor. |
deferred_close_timeout | duration | No | unset | Grace period before closing the processor stream. |
metadata_options | object | No | unset | Limited support for forwarding_namespaces.untyped; include envoy.lb to report the served endpoint with response headers. |
http_service, filter_metadata, request_attributes, response_attributes and status_on_error are unsupported and refused at startup.
Header mutations
Omitting mutation_rules allows the processor to modify supported headers without mutation-rule restrictions. With mutation_rules: {}, the default rules block changes to host, :authority, :scheme, :method and x-envoy- headers. Other supported pseudo-headers remain allowed unless disallow_system is enabled; allow_all_routing, allow_envoy and the expression fields adjust these restrictions.
For set_headers, leaving both append and append_action unset adds or replaces the header. append: true appends instead; an explicit append takes precedence over append_action.
Processing modes
request_header_mode / response_header_mode and the trailer modes take DEFAULT, SEND or SKIP. request_body_mode / response_body_mode take NONE, STREAMED, BUFFERED, BUFFERED_PARTIAL or FULL_DUPLEX_STREAMED.
For a processor that waits for the complete request before answering its headers, use FULL_DUPLEX_STREAMED with send_body_without_waiting_for_header_response: true. This lets request body messages reach the processor without waiting for its header reply.
Metadata forwarding
metadata_options.forwarding_namespaces.untyped: [envoy.lb] enables served-endpoint feedback. With response-header processing enabled, a cluster using the OverrideHost load-balancing policy reports the actual served endpoint in ProcessingRequest.metadata_context.filter_metadata["envoy.lb"]["x-gateway-destination-endpoint-served"], including fallback selections. This is processor metadata, not an HTTP response header.
Other untyped namespace names are accepted but do not enable arbitrary metadata forwarding. Nonempty forwarding_namespaces.typed, receiving_namespaces and cluster_metadata_forwarding_namespaces are rejected; empty receiving or cluster namespace objects are accepted. metadata_options cannot be set in per-route overrides.
Per-route override
Routes adjust the filter through typed_per_filter_config keyed by its chain name. The override type is ExtProcPerRoute: either disabled: true, or overrides carrying a different processing_mode, grpc_service or failure_mode_allow for that route. These settings work with both inline route_config and routes delivered over RDS. Per-route settings retain the filter's metadata forwarding configuration.
Ordering and interactions
The processor sees requests as earlier filters left them and can still short-circuit with an immediate response; place ext_proc before the router and after authentication unless the processor itself does the authenticating.
See the AI Inference Gateway overview and inference routing guide for endpoint selection through ext_proc.