envoyproxy / envoyproxy/gateway

feat(api): ExtProc - Support per-route gRPC initial metadata via ExtProcPerRoute

Open
#8,459 1 comment 4 reactions 0 assignees View on GitHub
stale
Dominant language
Go
Stars
3k
Forks
864
Avg merge
2d 2h
Merged PRs (30d)
140

Description

*Description*:

Envoy's External Processing filter supports per-route configuration overrides via [`ExtProcPerRoute`](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_proc/v3/ext_proc.proto#extensions-filters-http-ext-proc-v3-extprocperroute). One of its capabilities is `overrides.grpc_initial_metadata` — static key-value pairs delivered to the ext_proc server as gRPC metadata at the start of each streaming call, scoped per route.

Currently, the xDS translator always writes an empty `anypb.Any{}` into `typed_per_filter_config` for each matched route ([`extproc.go`](https://github.com/envoyproxy/gateway/blob/main/internal/xds/translator/extproc.go)). This only enables or disables the filter per route — it carries no configuration. There is no first-class API in `EnvoyExtensionPolicy` to populate `ExtProcPerRoute.overrides`.

This is the direct analogue of #6592 (ExtAuth `contextExtensions`), resolved in v1.7 by exposing `checkSettings.contextExtensions` in `SecurityPolicy.ExtAuth`. The same pattern should apply to ExtProc.

### Desired Behaviour

A new optional field `grpcInitialMetadata` in `EnvoyExtensionPolicy.spec.extProc[]`, following the same `Value` / `ValueRef` pattern introduced for `ContextExtension` in `ext_auth_types.go`:

```yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: checkout-ext-proc
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: checkout-route
sectionName: payment-rule # named HTTPRoute rule — scoped per rule (GEP-713)
extProc:
- backendRefs:
- name: ext-proc-service
port: 9002
processingMode:
request:
headers: Send
response:
headers: Send
grpcInitialMetadata:
- name: x-handler-chain
type: Value
value: "fraud-check,geo-enrichment,audit"
- name: x-tenant-id
type: Value
value: "acme"
- name: x-signing-key
type: ValueRef
valueRef:
kind: Secret
name: request-signing-key
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
name: catalogue-ext-proc
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: catalogue-route
sectionName: search-rule
extProc:
- backendRefs:
- name: ext-proc-service
port: 9002
grpcInitialMetadata:
- name: x-handler-chain
type: Value
value: "geo-enrichment" # different handler chain for this rule
```

The ext_proc server reads `x-handler-chain` from gRPC stream initial metadata and executes the appropriate handlers. Different rules on the same HTTPRoute — or across different HTTPRoutes — dispatch to different handler chains within the same ext_proc deployment.

### Generated xDS Output

```yaml
# checkout-route / payment-rule
typed_per_filter_config:
envoy.filters.http.ext_proc/envoyextensionpolicy/default/checkout-ext-proc/extproc/0:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute
overrides:
grpc_initial_metadata:
- key: x-handler-chain
value: "fraud-check,geo-enrichment,audit"
- key: x-tenant-id
value: "acme"
- key: x-signing-key
value: ""

# catalogue-route / search-rule
typed_per_filter_config:
envoy.filters.http.ext_proc/envoyextensionpolicy/default/catalogue-ext-proc/extproc/0:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute
overrides:
grpc_initial_metadata:
- key: x-handler-chain
value: "geo-enrichment"
```

### Why Not Route Metadata (`xds.route_metadata` via `Attributes[]`)?

EG already supports forwarding route metadata to ext_proc via the `attributes` field (#3170). However `xds.route_metadata` is `envoy.config.core.v3.Metadata` — a typed, namespaced protobuf struct. Ext_proc servers that dispatch based on a handler list or route identifier need flat string values, not a typed struct requiring protobuf parsing.

Additionally, EG's route metadata API is annotation-based on the `HTTPRoute` object. Since `HTTPRouteRule` has no independent metadata in the Gateway API spec, per-rule metadata cannot be expressed. `grpcInitialMetadata` scoped via `sectionName` is naturally per-rule — already proven to work at the rule level (#8311, confirmed in `envoyextensionpolicy.go:536`).

This mirrors the conclusion from #6592 where `context_extensions` (`map[string]string`) was chosen over `route_metadata_context_namespaces` for the same reason.

### Use Case

A single ext_proc deployment implementing multiple custom handlers (request signing, fraud detection, geo enrichment, audit logging, etc.). Different routes require different handler chains. Without per-route metadata delivery the only workaround is having the ext_proc server re-match request path and method against its own routing table, duplicating Envoy's routing logic.

### Workaround

Users must currently use `EnvoyPatchPolicy` with `JSONPatch`, which requires knowing EG's internal route name format (`httproute/{namespace}/{name}/rule/{idx}/match/{idx}`) and filter name — internal implementation details that break on rule reordering:

```yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyPatchPolicy
spec:
type: JSONPatch
jsonPatches:
- type: type.googleapis.com/envoy.config.route.v3.RouteConfiguration
name: default/eg/https
operation:
op: replace
jsonPath: .virtual_hosts[*].routes[?(@.name=="httproute/default/checkout-route/rule/0/match/-1")].typed_per_filter_config["envoy.filters.http.ext_proc/envoyextensionpolicy/default/checkout-ext-proc/extproc/0"]
value:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExtProcPerRoute
overrides:
grpc_initial_metadata:
- key: x-handler-chain
value: "fraud-check,geo-enrichment,audit"
```

### Implementation Notes

Follows the same path as #6592:

1. **`api/v1alpha1/ext_proc_types.go`** — add `GRPCInitialMetadata []*GRPCInitialMetadataEntry` to `ExtProc` struct. Model `GRPCInitialMetadataEntry` exactly on `ContextExtension` in `ext_auth_types.go` — same `Value` / `ValueRef` union discriminator, same kubebuilder validation markers.
2. **`internal/ir/`** — add corresponding field to the `ExtProc` IR struct.
3. **`internal/gatewayapi/envoyextensionpolicy.go`** — copy API value into IR; resolve any `SecretKeyRef` / `ConfigMapKeyRef` references.
4. **`internal/xds/translator/extproc.go`** — in `patchRoute()`, when `GRPCInitialMetadata` is non-empty, marshal `ExtProcPerRoute` with `overrides.grpc_initial_metadata` populated (`[]*corev3.HeaderValue`) and pass `&routev3.FilterConfig{Config: perRouteAny}` instead of the current empty `anypb.Any{}`.
5. **`internal/provider/kubernetes/`** — reconcile `SecretKeyRef` / `ConfigMapKeyRef` references.

*Relevant Links*:
- [Envoy `ExtProcPerRoute` / `ExtProcOverrides` proto](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_proc/v3/ext_proc.proto#extensions-filters-http-ext-proc-v3-extprocoverrides)
- [ExtAuth `contextExtensions` — analogous issue #6592](https://github.com/envoyproxy/gateway/issues/6592)
- [Support Additional ExtProc Options — #3170](https://github.com/envoyproxy/gateway/issues/3170)
- [EEP `sectionName` support — #8311](https://github.com/envoyproxy/gateway/issues/8311)
- [Route and VHost Metadata — #3318](https://github.com/envoyproxy/gateway/issues/3318)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.