Skip to content

feat(api): support per-route gRPC initial metadata for ExtProc via ExtProcPerRoute#8463

Open
surenraju-careem wants to merge 4 commits intoenvoyproxy:mainfrom
surenraju-careem:feat/ext-proc-grpc-initial-metadata
Open

feat(api): support per-route gRPC initial metadata for ExtProc via ExtProcPerRoute#8463
surenraju-careem wants to merge 4 commits intoenvoyproxy:mainfrom
surenraju-careem:feat/ext-proc-grpc-initial-metadata

Conversation

@surenraju-careem
Copy link

@surenraju-careem surenraju-careem commented Mar 9, 2026

What type of PR is this?

feat(api)

What this PR does / why we need it:

Adds a grpcInitialMetadata field to the ExtProc API in EnvoyExtensionPolicy, allowing users to specify per-route key-value pairs sent as gRPC stream initial metadata to the external processing server via ExtProcPerRoute.overrides.grpc_initial_metadata.

Today, patchRoute() in the xDS translator always emits an empty FilterConfig{Config: &anypb.Any{}} for every ext_proc-enabled route — regardless of which EnvoyExtensionPolicy (with sectionName scoping) is attached. This means the ext_proc server has no stable, per-route signal to determine which HTTPRoute rule is being processed.

The only current option is Attributes["xds.route_name"], but that value is index-based (httproute/ns/name/rule/0/match/0/...) and breaks whenever rules are reordered.

With this change, operators can inject stable, semantic metadata:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyExtensionPolicy
metadata:
  name: checkout-ext-proc
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: checkout-route
    sectionName: fraud-check-rule
  extProc:
  - backendRefs:
    - name: fraud-check-service
      port: 9001
    grpcInitialMetadata:
    - name: x-handler
      value: fraud-check
    - name: x-route-rule
      value: fraud-check-rule

Envoy then delivers these as gRPC stream initial metadata to the ext_proc server on every request matching that rule, enabling the server to apply rule-specific logic without any unstable xDS route name parsing.

This maps directly to ExtProcOverrides.grpc_initial_metadata (field 7), which is fully implemented in Envoy since envoy#31544.

Which issue(s) this PR fixes:

Fixes #8459

Changes:

  • api/v1alpha1: add GRPCInitialMetadata []ExtProcGRPCInitialMetadataEntry to ExtProc struct
  • internal/ir: add GRPCInitialMetadata field and ExtProcGRPCInitialMetadata type
  • internal/gatewayapi: map API field to IR in buildExtProc()
  • internal/xds/translator: patchRoute() emits a typed ExtProcPerRoute with overrides.grpc_initial_metadata when entries are present; falls back to empty FilterConfig otherwise
  • CRD manifests regenerated (make manifests)
  • API docs regenerated (make generate)
  • examples/grpc-ext-proc: updated to read and reflect gRPC stream initial metadata in response headers for e2e observability

Release Notes: Yes

…tProcPerRoute

Add `grpcInitialMetadata` field to the `ExtProc` API in EnvoyExtensionPolicy,
enabling users to specify per-route key-value pairs that Envoy sends as gRPC
stream initial metadata to the external processing server via
ExtProcPerRoute.overrides.grpc_initial_metadata.

This allows ext_proc servers to identify which HTTPRoute rule is being
processed and apply route-specific handler logic without relying on
unstable index-based xDS route names (e.g. rule/0/match/0).

Changes:
- api/v1alpha1: add GRPCInitialMetadata []ExtProcGRPCInitialMetadataEntry
  to ExtProc struct with kubebuilder MaxItems=16 validation
- internal/ir: add GRPCInitialMetadata field and ExtProcGRPCInitialMetadata
  type to ExtProc IR struct
- internal/gatewayapi: map GRPCInitialMetadata from API to IR in buildExtProc
- internal/xds/translator: patchRoute now emits a typed ExtProcPerRoute with
  overrides.grpc_initial_metadata when entries are configured, falling back
  to the existing empty FilterConfig when none are set
- CRD manifests regenerated via make manifests
- API docs regenerated via make generate
- release-notes/current.yaml: add entry for new feature
- examples/grpc-ext-proc: read gRPC stream initial metadata and reflect
  values in response headers to enable e2e verification

Fixes envoyproxy#8459

Signed-off-by: Suren Raju <suren.raju@careem.com>
@surenraju-careem surenraju-careem requested a review from a team as a code owner March 9, 2026 14:17
@netlify
Copy link

netlify bot commented Mar 9, 2026

Deploy Preview for cerulean-figolla-1f9435 canceled.

Name Link
🔨 Latest commit 949d979
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/69afbbdb614629000995730c

@codecov
Copy link

codecov bot commented Mar 10, 2026

Codecov Report

❌ Patch coverage is 17.24138% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.09%. Comparing base (a470576) to head (949d979).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
internal/xds/translator/extproc.go 17.39% 17 Missing and 2 partials ⚠️
internal/gatewayapi/envoyextensionpolicy.go 16.66% 4 Missing and 1 partial ⚠️

❌ Your patch check has failed because the patch coverage (17.24%) is below the target coverage (60.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8463      +/-   ##
==========================================
- Coverage   74.13%   74.09%   -0.05%     
==========================================
  Files         242      242              
  Lines       37579    37604      +25     
==========================================
+ Hits        27859    27862       +3     
- Misses       7778     7798      +20     
- Partials     1942     1944       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Pass extProc by pointer in buildExtProc to fix gocritic hugeParam lint
  (egv1a1.ExtProc is 96 bytes, passing by value flagged by linter)
- Update generated helm CRD test outputs (all.out.yaml, e2e.out.yaml,
  envoy-gateway-crds.out.yaml) to match latest manifests
- Fix case-insensitive grep in image.mk for Docker API version check

Signed-off-by: Suren Raju <suren.raju@careem.com>
zhaohuabing

This comment was marked as duplicate.

Copy link
Member

@zhaohuabing zhaohuabing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add gRPC initial metadata to one of the existing xds test yaml file so we can verify the generated envoy config?

@zhaohuabing zhaohuabing requested review from a team and guydc March 12, 2026 05:40
// per-route metadata without duplicating the full gRPC service configuration.
//
// +optional
GRPCInitialMetadata []ExtProcGRPCInitialMetadataEntry `json:"grpcInitialMetadata,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that we may need to support HTTP ext proc in the future? If so, a GRPCService wrapper might be more furture-proof. cc @guydc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants