From 98457b52c17fd230f3c5b7606de41377f9cbc7ac Mon Sep 17 00:00:00 2001 From: Guy Daich Date: Wed, 27 Nov 2024 18:10:33 -0600 Subject: [PATCH] api: ext-proc attributes (#4794) * api: ext-proc attributes Signed-off-by: Guy Daich * fix lint Signed-off-by: Guy Daich --------- Signed-off-by: Guy Daich --- api/v1alpha1/ext_proc_types.go | 10 ++ api/v1alpha1/zz_generated.deepcopy.go | 5 + ....envoyproxy.io_envoyextensionpolicies.yaml | 20 +++ release-notes/current.yaml | 3 +- site/content/en/latest/api/extension_types.md | 2 + site/content/zh/latest/api/extension_types.md | 2 + .../envoyextensionpolicy_test.go | 151 ++++++++++++++++++ 7 files changed, 192 insertions(+), 1 deletion(-) diff --git a/api/v1alpha1/ext_proc_types.go b/api/v1alpha1/ext_proc_types.go index cbdaf97ba45..ca78b619c4d 100644 --- a/api/v1alpha1/ext_proc_types.go +++ b/api/v1alpha1/ext_proc_types.go @@ -22,11 +22,21 @@ const ( ) // ProcessingModeOptions defines if headers or body should be processed by the external service +// and which attributes are sent to the processor type ProcessingModeOptions struct { // Defines body processing mode // // +optional Body *ExtProcBodyProcessingMode `json:"body,omitempty"` + + // Defines which attributes are sent to the external processor. Envoy Gateway currently + // supports only the following attribute prefixes: connection, source, destination, + // request, response, upstream and xds.route. + // https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes + // + // +optional + // +kubebuilder:validation:items:Pattern=`^(connection\.|source\.|destination\.|request\.|response\.|upstream\.|xds\.route_)[a-z_1-9]*$` + Attributes []string `json:"attributes,omitempty"` } // ExtProcProcessingMode defines if and how headers and bodies are sent to the service. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 12f634586c6..457afa58ac4 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -4124,6 +4124,11 @@ func (in *ProcessingModeOptions) DeepCopyInto(out *ProcessingModeOptions) { *out = new(ExtProcBodyProcessingMode) **out = **in } + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProcessingModeOptions. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml index e6cb298d3a8..0fbbcafe94e 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml @@ -918,6 +918,16 @@ spec: Defines processing mode for requests. If present, request headers are sent. Request body is processed according to the specified mode. properties: + attributes: + description: |- + Defines which attributes are sent to the external processor. Envoy Gateway currently + supports only the following attribute prefixes: connection, source, destination, + request, response, upstream and xds.route. + https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes + items: + pattern: ^(connection\.|source\.|destination\.|request\.|response\.|upstream\.|xds\.route_)[a-z_1-9]*$ + type: string + type: array body: description: Defines body processing mode enum: @@ -931,6 +941,16 @@ spec: Defines processing mode for responses. If present, response headers are sent. Response body is processed according to the specified mode. properties: + attributes: + description: |- + Defines which attributes are sent to the external processor. Envoy Gateway currently + supports only the following attribute prefixes: connection, source, destination, + request, response, upstream and xds.route. + https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes + items: + pattern: ^(connection\.|source\.|destination\.|request\.|response\.|upstream\.|xds\.route_)[a-z_1-9]*$ + type: string + type: array body: description: Defines body processing mode enum: diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 7b9d547d839..9ec82fc249b 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -14,7 +14,8 @@ security updates: | # New features or capabilities added in this release. new features: | - - Added support for trusted CIDRs in the ClientIPDetectionSettings API + Added support for trusted CIDRs in the ClientIPDetectionSettings API + Added support for sending attributes to external processor in EnvoyExtensionPolicy API # Fixes for bugs identified in previous versions. bug fixes: | diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 80614c2645e..fc7142446c1 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -2960,6 +2960,7 @@ _Appears in:_ ProcessingModeOptions defines if headers or body should be processed by the external service +and which attributes are sent to the processor _Appears in:_ - [ExtProcProcessingMode](#extprocprocessingmode) @@ -2967,6 +2968,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | _[ExtProcBodyProcessingMode](#extprocbodyprocessingmode)_ | false | Defines body processing mode | +| `attributes` | _string array_ | false | Defines which attributes are sent to the external processor. Envoy Gateway currently
supports only the following attribute prefixes: connection, source, destination,
request, response, upstream and xds.route.
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes | #### ProviderType diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 80614c2645e..fc7142446c1 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -2960,6 +2960,7 @@ _Appears in:_ ProcessingModeOptions defines if headers or body should be processed by the external service +and which attributes are sent to the processor _Appears in:_ - [ExtProcProcessingMode](#extprocprocessingmode) @@ -2967,6 +2968,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | _[ExtProcBodyProcessingMode](#extprocbodyprocessingmode)_ | false | Defines body processing mode | +| `attributes` | _string array_ | false | Defines which attributes are sent to the external processor. Envoy Gateway currently
supports only the following attribute prefixes: connection, source, destination,
request, response, upstream and xds.route.
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes | #### ProviderType diff --git a/test/cel-validation/envoyextensionpolicy_test.go b/test/cel-validation/envoyextensionpolicy_test.go index 7c9c168df10..a1d435e55dc 100644 --- a/test/cel-validation/envoyextensionpolicy_test.go +++ b/test/cel-validation/envoyextensionpolicy_test.go @@ -433,6 +433,157 @@ func TestEnvoyExtensionPolicyTarget(t *testing.T) { }, wantErrors: []string{}, }, + { + desc: "ExtProc with valid attributes", + mutate: func(sp *egv1a1.EnvoyExtensionPolicy) { + sp.Spec = egv1a1.EnvoyExtensionPolicySpec{ + ExtProc: []egv1a1.ExtProc{ + { + BackendCluster: egv1a1.BackendCluster{ + BackendRefs: []egv1a1.BackendRef{ + { + BackendObjectReference: gwapiv1.BackendObjectReference{ + Name: "grpc-proc-service", + Port: ptr.To(gwapiv1.PortNumber(80)), + }, + }, + }, + }, + ProcessingMode: &egv1a1.ExtProcProcessingMode{ + Request: &egv1a1.ProcessingModeOptions{ + Attributes: []string{ + "request.path", + "request.url_path", + "request.host", + "request.scheme", + "request.method", + "request.headers", + "request.referer", + "request.useragent", + "request.time", + "request.id", + "request.protocol", + "request.query", + "request.duration", + "request.size", + "request.total_size", + "response.code", + "response.code_details", + "response.flags", + "response.grpc_status", + "response.headers", + "response.trailers", + "response.size", + "response.total_size", + "response.backend_latency", + "source.address", + "source.port", + "destination.address", + "destination.port", + }, + }, + Response: &egv1a1.ProcessingModeOptions{ + Attributes: []string{ + "connection.id", + "connection.mtls", + "connection.requested_server_name", + "connection.tls_version", + "connection.subject_local_certificate", + "connection.subject_peer_certificate", + "connection.dns_san_local_certificate", + "connection.dns_san_peer_certificate", + "connection.uri_san_local_certificate", + "connection.uri_san_peer_certificate", + "connection.sha256_peer_certificate_digest", + "connection.transport_failure_reason", + "connection.termination_details", + "upstream.address", + "upstream.port", + "upstream.tls_version", + "upstream.subject_local_certificate", + "upstream.subject_peer_certificate", + "upstream.dns_san_local_certificate", + "upstream.dns_san_peer_certificate", + "upstream.uri_san_local_certificate", + "upstream.uri_san_peer_certificate", + "upstream.sha256_peer_certificate_digest", + "upstream.local_address", + "upstream.transport_failure_reason", + "upstream.request_attempt_count", + }, + }, + }, + }, + }, + PolicyTargetReferences: egv1a1.PolicyTargetReferences{ + TargetRef: &gwapiv1a2.LocalPolicyTargetReferenceWithSectionName{ + LocalPolicyTargetReference: gwapiv1a2.LocalPolicyTargetReference{ + Group: "gateway.networking.k8s.io", + Kind: "Gateway", + Name: "eg", + }, + }, + }, + } + }, + wantErrors: []string{}, + }, + { + desc: "ExtProc with invalid attributes", + mutate: func(sp *egv1a1.EnvoyExtensionPolicy) { + sp.Spec = egv1a1.EnvoyExtensionPolicySpec{ + ExtProc: []egv1a1.ExtProc{ + { + BackendCluster: egv1a1.BackendCluster{ + BackendRefs: []egv1a1.BackendRef{ + { + BackendObjectReference: gwapiv1.BackendObjectReference{ + Name: "grpc-proc-service", + Port: ptr.To(gwapiv1.PortNumber(80)), + }, + }, + }, + }, + ProcessingMode: &egv1a1.ExtProcProcessingMode{ + Request: &egv1a1.ProcessingModeOptions{ + Attributes: []string{ + "xds.node", + "metadata", + "filter_state", + "upstream_filter_state", + }, + }, + Response: &egv1a1.ProcessingModeOptions{ + Attributes: []string{ + "xds.node", + "xds.cluster", + "plugin_name", + }, + }, + }, + }, + }, + PolicyTargetReferences: egv1a1.PolicyTargetReferences{ + TargetRef: &gwapiv1a2.LocalPolicyTargetReferenceWithSectionName{ + LocalPolicyTargetReference: gwapiv1a2.LocalPolicyTargetReference{ + Group: "gateway.networking.k8s.io", + Kind: "Gateway", + Name: "eg", + }, + }, + }, + } + }, + wantErrors: []string{ + "spec.extProc[0].processingMode.request.attributes[0]: Invalid value: \"xds.node\": spec.extProc[0].processingMode.request.attributes[0] in body should match '^(connection\\.|source\\.|destination\\.|request\\.|response\\.|upstream\\.|xds\\.route_)[a-z_1-9]*$'", + "spec.extProc[0].processingMode.request.attributes[1]: Invalid value: \"metadata\": spec.extProc[0].processingMode.request.attributes[1] in body should match '^(connection\\.|source\\.|destination\\.|request\\.|response\\.|upstream\\.|xds\\.route_)[a-z_1-9]*$'", + "spec.extProc[0].processingMode.request.attributes[2]: Invalid value: \"filter_state\": spec.extProc[0].processingMode.request.attributes[2] in body should match '^(connection\\.|source\\.|destination\\.|request\\.|response\\.|upstream\\.|xds\\.route_)[a-z_1-9]*$'", + "spec.extProc[0].processingMode.request.attributes[3]: Invalid value: \"upstream_filter_state\": spec.extProc[0].processingMode.request.attributes[3] in body should match '^(connection\\.|source\\.|destination\\.|request\\.|response\\.|upstream\\.|xds\\.route_)[a-z_1-9]*$'", + "spec.extProc[0].processingMode.response.attributes[0]: Invalid value: \"xds.node\": spec.extProc[0].processingMode.response.attributes[0] in body should match '^(connection\\.|source\\.|destination\\.|request\\.|response\\.|upstream\\.|xds\\.route_)[a-z_1-9]*$'", + "spec.extProc[0].processingMode.response.attributes[1]: Invalid value: \"xds.cluster\": spec.extProc[0].processingMode.response.attributes[1] in body should match '^(connection\\.|source\\.|destination\\.|request\\.|response\\.|upstream\\.|xds\\.route_)[a-z_1-9]*$'", + "spec.extProc[0].processingMode.response.attributes[2]: Invalid value: \"plugin_name\": spec.extProc[0].processingMode.response.attributes[2] in body should match '^(connection\\.|source\\.|destination\\.|request\\.|response\\.|upstream\\.|xds\\.route_)[a-z_1-9]*$'", + }, + }, } for _, tc := range cases {