diff --git a/examples/grpc-ext-proc/main.go b/examples/grpc-ext-proc/main.go index 785480f1d20..ecdac6bd6be 100644 --- a/examples/grpc-ext-proc/main.go +++ b/examples/grpc-ext-proc/main.go @@ -210,6 +210,16 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc resp := &envoy_service_proc_v3.ProcessingResponse{} switch v := req.Request.(type) { case *envoy_service_proc_v3.ProcessingRequest_RequestHeaders: + xdsRouteName := "" + + if req.Attributes != nil { + if epa, ok := req.Attributes["envoy.filters.http.ext_proc"]; ok { + if rqa, ok := epa.Fields["xds.route_name"]; ok { + xdsRouteName = rqa.GetStringValue() + } + } + } + xrch := "" if v.RequestHeaders != nil { hdrs := v.RequestHeaders.Headers.GetHeaders() @@ -230,6 +240,12 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc RawValue: []byte("true"), }, }, + { + Header: &envoy_api_v3_core.HeaderValue{ + Key: "x-request-xds-route-name", + RawValue: []byte(xdsRouteName), + }, + }, }, }, }, @@ -257,8 +273,19 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc RequestHeaders: rhq, }, } + break case *envoy_service_proc_v3.ProcessingRequest_ResponseHeaders: + + respXDSRouteName := "" + + if req.Attributes != nil { + if epa, ok := req.Attributes["envoy.filters.http.ext_proc"]; ok { + if rsa, ok := epa.Fields["xds.route_name"]; ok { + respXDSRouteName = rsa.GetStringValue() + } + } + } rhq := &envoy_service_proc_v3.HeadersResponse{ Response: &envoy_service_proc_v3.CommonResponse{ HeaderMutation: &envoy_service_proc_v3.HeaderMutation{ @@ -269,6 +296,12 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc RawValue: []byte("true"), }, }, + { + Header: &envoy_api_v3_core.HeaderValue{ + Key: "x-response-xds-route-name", + RawValue: []byte(respXDSRouteName), + }, + }, }, }, }, diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go index bb5da8be140..72133f83ace 100644 --- a/internal/gatewayapi/envoyextensionpolicy.go +++ b/internal/gatewayapi/envoyextensionpolicy.go @@ -481,6 +481,10 @@ func (t *Translator) buildExtProc( if extProc.ProcessingMode.Request.Body != nil { extProcIR.RequestBodyProcessingMode = ptr.To(ir.ExtProcBodyProcessingMode(*extProc.ProcessingMode.Request.Body)) } + + if extProc.ProcessingMode.Request.Attributes != nil { + extProcIR.RequestAttributes = append(extProcIR.RequestAttributes, extProc.ProcessingMode.Request.Attributes...) + } } if extProc.ProcessingMode.Response != nil { @@ -488,6 +492,10 @@ func (t *Translator) buildExtProc( if extProc.ProcessingMode.Response.Body != nil { extProcIR.ResponseBodyProcessingMode = ptr.To(ir.ExtProcBodyProcessingMode(*extProc.ProcessingMode.Response.Body)) } + + if extProc.ProcessingMode.Response.Attributes != nil { + extProcIR.ResponseAttributes = append(extProcIR.ResponseAttributes, extProc.ProcessingMode.Response.Attributes...) + } } } diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml index ca3297a5fae..95e8b95701f 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.in.yaml @@ -203,8 +203,13 @@ envoyExtensionPolicies: processingMode: request: body: Buffered + attributes: + - request.path response: body: Streamed + attributes: + - xds.route_metadata + - connection.requested_server_name messageTimeout: 5s failOpen: true - apiVersion: gateway.envoyproxy.io/v1alpha1 diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml index a1d7beec90b..3fd129b8047 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-extproc-with-backendtlspolicy.out.yaml @@ -113,8 +113,13 @@ envoyExtensionPolicies: messageTimeout: 5s processingMode: request: + attributes: + - request.path body: Buffered response: + attributes: + - xds.route_metadata + - connection.requested_server_name body: Streamed targetRef: group: gateway.networking.k8s.io @@ -363,8 +368,13 @@ xdsIR: failOpen: true messageTimeout: 5s name: envoyextensionpolicy/default/policy-for-gateway/extproc/0 + requestAttributes: + - request.path requestBodyProcessingMode: Buffered requestHeaderProcessing: true + responseAttributes: + - xds.route_metadata + - connection.requested_server_name responseBodyProcessingMode: Streamed responseHeaderProcessing: true hostname: www.bar.com diff --git a/internal/ir/xds.go b/internal/ir/xds.go index c9fb1dd56b8..7114afc1f22 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -2602,6 +2602,14 @@ type ExtProc struct { // ResponseBodyProcessingMode Defines response body processing ResponseBodyProcessingMode *ExtProcBodyProcessingMode `json:"responseBodyProcessingMode,omitempty" yaml:"responseBodyProcessingMode,omitempty"` + + // RequestAttributes defines which envoy attributes are provided as context to external processor + // when processing requests + RequestAttributes []string `json:"requestAttributes,omitempty" yaml:"requestAttributes,omitempty"` + + // ResponseAttributes defines which envoy attributes are provided as context to external processor + // when processing responses + ResponseAttributes []string `json:"responseAttributes,omitempty" yaml:"responseAttributes,omitempty"` } // Wasm holds the information associated with the Wasm extensions. diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index de0be09ff0f..f7384181dff 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -944,6 +944,16 @@ func (in *ExtProc) DeepCopyInto(out *ExtProc) { *out = new(ExtProcBodyProcessingMode) **out = **in } + if in.RequestAttributes != nil { + in, out := &in.RequestAttributes, &out.RequestAttributes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ResponseAttributes != nil { + in, out := &in.ResponseAttributes, &out.ResponseAttributes + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtProc. diff --git a/internal/xds/translator/extproc.go b/internal/xds/translator/extproc.go index 57cc9634d09..2270b2fb79d 100644 --- a/internal/xds/translator/extproc.go +++ b/internal/xds/translator/extproc.go @@ -137,6 +137,18 @@ func extProcConfig(extProc ir.ExtProc) *extprocv3.ExternalProcessor { config.ProcessingMode.ResponseHeaderMode = extprocv3.ProcessingMode_SEND } + if extProc.RequestAttributes != nil { + var attrs []string + attrs = append(attrs, extProc.RequestAttributes...) + config.RequestAttributes = attrs + } + + if extProc.ResponseAttributes != nil { + var attrs []string + attrs = append(attrs, extProc.ResponseAttributes...) + config.ResponseAttributes = attrs + } + return config } diff --git a/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml b/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml index 3fa4cd8bcc7..da4939c228d 100644 --- a/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/ext-proc.yaml @@ -23,8 +23,13 @@ http: - name: envoyextensionpolicy/default/policy-for-route-2/extproc/0 failOpen: true messageTimeout: 5s + requestAttributes: + - xds.route_metadata + - connection.requested_server_name requestHeaderProcessing: true requestBodyProcessingMode: Buffered + responseAttributes: + - request.path responseBodyProcessingMode: Streamed authority: grpc-backend-4.default:4000 destination: @@ -71,6 +76,11 @@ http: - name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/extproc/0 failOpen: false messageTimeout: 15s + requestAttributes: + - xds.route_metadata + - connection.requested_server_name + responseAttributes: + - request.path authority: grpc-backend.envoy-gateway:9000 destination: name: envoyextensionpolicy/envoy-gateway/policy-for-gateway-1/0/grpc-backend diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml index acf4c0a40f6..a75f1ccc268 100755 --- a/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc.listeners.yaml @@ -32,6 +32,11 @@ responseBodyMode: STREAMED responseHeaderMode: SKIP responseTrailerMode: SKIP + requestAttributes: + - xds.route_metadata + - connection.requested_server_name + responseAttributes: + - request.path - disabled: true name: envoy.filters.http.ext_proc/envoyextensionpolicy/default/policy-for-route-1/extproc/0 typedConfig: @@ -78,6 +83,11 @@ requestTrailerMode: SKIP responseHeaderMode: SKIP responseTrailerMode: SKIP + requestAttributes: + - xds.route_metadata + - connection.requested_server_name + responseAttributes: + - request.path - name: envoy.filters.http.router typedConfig: '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router diff --git a/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml b/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml index 3663e19b610..90d25613be5 100644 --- a/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml +++ b/test/e2e/testdata/ext-proc-envoyextensionpolicy.yaml @@ -51,8 +51,12 @@ spec: namespace: gateway-conformance-infra port: 9002 processingMode: - request: {} - response: {} + request: + attributes: + - xds.route_name + response: + attributes: + - xds.route_name --- apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyExtensionPolicy diff --git a/test/e2e/tests/ext_proc.go b/test/e2e/tests/ext_proc.go index 033da67f6bd..aa1ec549335 100644 --- a/test/e2e/tests/ext_proc.go +++ b/test/e2e/tests/ext_proc.go @@ -63,16 +63,24 @@ var ExtProcTest = suite.ConformanceTest{ Request: http.Request{ Path: "/processor", Headers: map[string]string{ - "x-request-ext-processed": "true", // header added by ext-processor to backend-bound request - "x-request-client-header-received": "original", // this is the original client header preserved by ext-proc in a new header - "x-request-client-header": "mutated", // this is the mutated value expected to reach upstream + // header added by ext-processor to backend-bound request + "x-request-ext-processed": "true", + // this is the original client header preserved by ext-proc in a new header + "x-request-client-header-received": "original", + // this is the mutated value expected to reach upstream + "x-request-client-header": "mutated", + // header added by ext-processor to request based on the xds.route_name attribute + "x-request-xds-route-name": "httproute/gateway-conformance-infra/http-with-ext-proc/rule/0/match/0/www_example_com", }, }, }, Response: http.Response{ StatusCode: 200, Headers: map[string]string{ - "x-response-ext-processed": "true", // header added by ext-processor to client-bound response + // header added by ext-processor to client-bound response + "x-response-ext-processed": "true", + // header added by ext-processor to response based on the xds.cluster_name attribute + "x-response-xds-route-name": "httproute/gateway-conformance-infra/http-with-ext-proc/rule/0/match/0/www_example_com", }, }, Namespace: ns,