diff --git a/api/v1alpha1/clienttrafficpolicy_types.go b/api/v1alpha1/clienttrafficpolicy_types.go index 58412c73723..619bbeb50f3 100644 --- a/api/v1alpha1/clienttrafficpolicy_types.go +++ b/api/v1alpha1/clienttrafficpolicy_types.go @@ -99,8 +99,30 @@ type HeaderSettings struct { // and responses. // +optional EnableEnvoyHeaders *bool `json:"enableEnvoyHeaders,omitempty"` + + // WithUnderscoresAction configures the action to take when an HTTP header with underscores + // is encountered. The default action is to reject the request. + // +optional + WithUnderscoresAction *WithUnderscoresAction `json:"withUnderscoresAction,omitempty"` } +// WithUnderscoresAction configures the action to take when an HTTP header with underscores +// is encountered. +// +kubebuilder:validation:Enum=Allow;RejectRequest;DropHeader +type WithUnderscoresAction string + +const ( + // WithUnderscoresActionAllow allows headers with underscores to be passed through. + WithUnderscoresActionAllow WithUnderscoresAction = "Allow" + // WithUnderscoresActionRejectRequest rejects the client request. HTTP/1 requests are rejected with + // the 400 status. HTTP/2 requests end with the stream reset. + WithUnderscoresActionRejectRequest WithUnderscoresAction = "RejectRequest" + // WithUnderscoresActionDropHeader drops the client header with name containing underscores. The header + // is dropped before the filter chain is invoked and as such filters will not see + // dropped headers. + WithUnderscoresActionDropHeader WithUnderscoresAction = "DropHeader" +) + // ClientIPDetectionSettings provides configuration for determining the original client IP address for requests. // // +kubebuilder:validation:XValidation:rule="!(has(self.xForwardedFor) && has(self.customHeader))",message="customHeader cannot be used in conjunction with xForwardedFor" diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 69bd7d8746f..a16dc0e4bc6 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1950,6 +1950,11 @@ func (in *HeaderSettings) DeepCopyInto(out *HeaderSettings) { *out = new(bool) **out = **in } + if in.WithUnderscoresAction != nil { + in, out := &in.WithUnderscoresAction, &out.WithUnderscoresAction + *out = new(WithUnderscoresAction) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HeaderSettings. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index fb90c27071f..70490a6419e 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -125,6 +125,15 @@ spec: description: EnableEnvoyHeaders configures Envoy Proxy to add the "X-Envoy-" headers to requests and responses. type: boolean + withUnderscoresAction: + description: WithUnderscoresAction configures the action to take + when an HTTP header with underscores is encountered. The default + action is to reject the request. + enum: + - Allow + - RejectRequest + - DropHeader + type: string type: object http1: description: HTTP1 provides HTTP/1 configuration on the listener. diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index 562bdcde1d3..d60a4345a1c 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -510,7 +510,8 @@ func translateListenerHeaderSettings(headerSettings *egv1a1.HeaderSettings, http return } httpIR.Headers = &ir.HeaderSettings{ - EnableEnvoyHeaders: ptr.Deref(headerSettings.EnableEnvoyHeaders, false), + EnableEnvoyHeaders: ptr.Deref(headerSettings.EnableEnvoyHeaders, false), + WithUnderscoresAction: ir.WithUnderscoresAction(ptr.Deref(headerSettings.WithUnderscoresAction, egv1a1.WithUnderscoresActionRejectRequest)), } } diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml index 82a60c2c033..136450f2abd 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.in.yaml @@ -7,6 +7,7 @@ clientTrafficPolicies: spec: headers: enableEnvoyHeaders: true + withUnderscoresAction: Allow targetRef: group: gateway.networking.k8s.io kind: Gateway diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml index a3bf3ad5ce2..005487ada5b 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-headers.out.yaml @@ -8,6 +8,7 @@ clientTrafficPolicies: spec: headers: enableEnvoyHeaders: true + withUnderscoresAction: Allow targetRef: group: gateway.networking.k8s.io kind: Gateway @@ -129,6 +130,7 @@ xdsIR: - address: 0.0.0.0 headers: enableEnvoyHeaders: true + withUnderscoresAction: Allow hostnames: - '*' isHTTP2: false @@ -140,6 +142,7 @@ xdsIR: - address: 0.0.0.0 headers: enableEnvoyHeaders: true + withUnderscoresAction: Allow hostnames: - '*' isHTTP2: false diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 86664e59567..73f23a992db 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -361,6 +361,14 @@ type PathSettings struct { EscapedSlashesAction PathEscapedSlashAction `json:"escapedSlashesAction" yaml:"escapedSlashesAction"` } +type WithUnderscoresAction egv1a1.WithUnderscoresAction + +const ( + WithUnderscoresActionAllow = WithUnderscoresAction(egv1a1.WithUnderscoresActionAllow) + WithUnderscoresActionRejectRequest = WithUnderscoresAction(egv1a1.WithUnderscoresActionRejectRequest) + WithUnderscoresActionDropHeader = WithUnderscoresAction(egv1a1.WithUnderscoresActionDropHeader) +) + // ClientIPDetectionSettings provides configuration for determining the original client IP address for requests. // +k8s:deepcopy-gen=true type ClientIPDetectionSettings egv1a1.ClientIPDetectionSettings @@ -394,6 +402,11 @@ type HeaderSettings struct { // The default is to suppress these headers. // Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/router/v3/router.proto#extensions-filters-http-router-v3-router EnableEnvoyHeaders bool `json:"enableEnvoyHeaders,omitempty" yaml:"enableEnvoyHeaders,omitempty"` + + // WithUnderscoresAction configures the action to take when an HTTP header with underscores + // is encountered. The default action is to reject the request. + // Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/protocol.proto#envoy-v3-api-enum-config-core-v3-httpprotocoloptions-headerswithunderscoresaction + WithUnderscoresAction WithUnderscoresAction `json:"withUnderscoresAction,omitempty" yaml:"withUnderscoresAction,omitempty"` } // ClientTimeout sets the timeout configuration for downstream connections diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index d84fc58c4e9..8058d3cf633 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -236,7 +236,7 @@ func (t *Translator) addXdsHTTPFilterChain(xdsListener *listenerv3.Listener, irL MergeSlashes: irListener.Path.MergeSlashes, PathWithEscapedSlashesAction: translateEscapePath(irListener.Path.EscapedSlashesAction), CommonHttpProtocolOptions: &corev3.HttpProtocolOptions{ - HeadersWithUnderscoresAction: corev3.HttpProtocolOptions_REJECT_REQUEST, + HeadersWithUnderscoresAction: translateHeadersWithUnderscoresAction(irListener.Headers), }, Tracing: hcmTracing, } @@ -737,3 +737,17 @@ func buildTCPProxyHashPolicy(lb *ir.LoadBalancer) []*typev3.HashPolicy { return nil } + +func translateHeadersWithUnderscoresAction(in *ir.HeaderSettings) corev3.HttpProtocolOptions_HeadersWithUnderscoresAction { + if in != nil { + switch in.WithUnderscoresAction { + case ir.WithUnderscoresActionAllow: + return corev3.HttpProtocolOptions_ALLOW + case ir.WithUnderscoresActionRejectRequest: + return corev3.HttpProtocolOptions_REJECT_REQUEST + case ir.WithUnderscoresActionDropHeader: + return corev3.HttpProtocolOptions_DROP_HEADER + } + } + return corev3.HttpProtocolOptions_REJECT_REQUEST +} diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 961a9000efd..87c7def0d4e 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1337,6 +1337,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `enableEnvoyHeaders` | _boolean_ | false | EnableEnvoyHeaders configures Envoy Proxy to add the "X-Envoy-" headers to requests and responses. | +| `withUnderscoresAction` | _[WithUnderscoresAction](#withunderscoresaction)_ | false | WithUnderscoresAction configures the action to take when an HTTP header with underscores is encountered. The default action is to reject the request. | #### HealthCheck @@ -2613,6 +2614,17 @@ _Appears in:_ +#### WithUnderscoresAction + +_Underlying type:_ _string_ + +WithUnderscoresAction configures the action to take when an HTTP header with underscores is encountered. + +_Appears in:_ +- [HeaderSettings](#headersettings) + + + #### XDSTranslatorHook _Underlying type:_ _string_