From d6efaf6c72b7fa39c5ae43bf5523b2a2559618ec Mon Sep 17 00:00:00 2001 From: Hariharan Subramanian Date: Thu, 30 Jul 2026 20:06:17 -0400 Subject: [PATCH] api: add maxRequestHeaderLimit to ClientTrafficPolicy Adds headers.maxRequestHeaderLimit to ClientTrafficPolicy, mapping to Envoy's HTTP connection manager max_request_headers_kb setting. The value is a resource.Quantity rounded up to the nearest KiB, validated to be at least 1Ki and at most 8192Ki (Envoy's maximum). Requests whose headers exceed the limit receive a 431 response. Scoped to the max-request-header field only (host normalization landed separately in #9115) and named with the *Limit suffix per maintainer feedback on #8825. Fixes #5368 Signed-off-by: Hariharan Subramanian --- api/v1alpha1/clienttrafficpolicy_types.go | 16 ++ api/v1alpha1/zz_generated.deepcopy.go | 5 + ...y.envoyproxy.io_clienttrafficpolicies.yaml | 18 +++ ...y.envoyproxy.io_clienttrafficpolicies.yaml | 18 +++ internal/gatewayapi/clienttrafficpolicy.go | 21 +++ ...ax-request-header-limit-with-error.in.yaml | 29 ++++ ...x-request-header-limit-with-error.out.yaml | 142 +++++++++++++++++ ...ficpolicy-max-request-header-limit.in.yaml | 29 ++++ ...icpolicy-max-request-header-limit.out.yaml | 143 ++++++++++++++++++ internal/ir/xds.go | 4 + internal/ir/zz_generated.deepcopy.go | 5 + internal/xds/translator/listener.go | 5 + .../in/xds-ir/max-request-headers-kb.yaml | 18 +++ .../max-request-headers-kb.clusters.yaml | 23 +++ .../max-request-headers-kb.endpoints.yaml | 12 ++ .../max-request-headers-kb.listeners.yaml | 34 +++++ .../xds-ir/max-request-headers-kb.routes.yaml | 14 ++ ...equest-header-limit-clienttrafficpolicy.md | 1 + site/content/en/latest/api/extension_types.md | 1 + 19 files changed, 538 insertions(+) create mode 100644 internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.in.yaml create mode 100644 internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.out.yaml create mode 100644 internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.in.yaml create mode 100644 internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.out.yaml create mode 100644 internal/xds/translator/testdata/in/xds-ir/max-request-headers-kb.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.clusters.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.endpoints.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.listeners.yaml create mode 100644 internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.routes.yaml create mode 100644 release-notes/current/new_features/5368-max-request-header-limit-clienttrafficpolicy.md diff --git a/api/v1alpha1/clienttrafficpolicy_types.go b/api/v1alpha1/clienttrafficpolicy_types.go index 202a6954a88..cae9efbbf0a 100644 --- a/api/v1alpha1/clienttrafficpolicy_types.go +++ b/api/v1alpha1/clienttrafficpolicy_types.go @@ -6,6 +6,7 @@ package v1alpha1 import ( + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" ) @@ -188,6 +189,21 @@ type HeaderSettings struct { // // +optional Host *HostSettings `json:"host,omitempty"` + + // MaxRequestHeaderLimit provides configuration for the maximum size of the + // request headers allowed for incoming connections, mapping to the Envoy + // `max_request_headers_kb` HTTP connection manager setting. Requests whose + // headers exceed this limit receive a 431 (Request Header Fields Too Large) + // response. The value is rounded up to the nearest KiB, must be at least 1Ki, + // and cannot exceed 8192Ki (the maximum Envoy supports). + // For example, 60Ki, 96Ki, 128Ki etc. + // Note that when the suffix is not provided, the value is interpreted as bytes. + // Default: 60Ki bytes. + // + // +kubebuilder:validation:XIntOrString + // +kubebuilder:validation:Pattern="^[1-9]+[0-9]*([EPTGMK]i|[EPTGMk])?$" + // +optional + MaxRequestHeaderLimit *resource.Quantity `json:"maxRequestHeaderLimit,omitempty"` } // WithUnderscoresAction configures the action to take when an HTTP header with underscores diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index b966f945df9..6ab6ee2ef3c 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -4977,6 +4977,11 @@ func (in *HeaderSettings) DeepCopyInto(out *HeaderSettings) { *out = new(HostSettings) (*in).DeepCopyInto(*out) } + if in.MaxRequestHeaderLimit != nil { + in, out := &in.MaxRequestHeaderLimit, &out.MaxRequestHeaderLimit + x := (*in).DeepCopy() + *out = &x + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HeaderSettings. diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index b873c582aa7..0b56f3e259d 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -748,6 +748,24 @@ spec: - name x-kubernetes-list-type: map type: object + maxRequestHeaderLimit: + allOf: + - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + - pattern: ^[1-9]+[0-9]*([EPTGMK]i|[EPTGMk])?$ + anyOf: + - type: integer + - type: string + description: |- + MaxRequestHeaderLimit provides configuration for the maximum size of the + request headers allowed for incoming connections, mapping to the Envoy + `max_request_headers_kb` HTTP connection manager setting. Requests whose + headers exceed this limit receive a 431 (Request Header Fields Too Large) + response. The value is rounded up to the nearest KiB, must be at least 1Ki, + and cannot exceed 8192Ki (the maximum Envoy supports). + For example, 60Ki, 96Ki, 128Ki etc. + Note that when the suffix is not provided, the value is interpreted as bytes. + Default: 60Ki bytes. + x-kubernetes-int-or-string: true preserveXRequestID: description: |- PreserveXRequestID configures Envoy to keep the X-Request-ID header if passed for a request that is edge diff --git a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml index 5b73c4161ad..f6ed8c44a5b 100644 --- a/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml +++ b/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_clienttrafficpolicies.yaml @@ -747,6 +747,24 @@ spec: - name x-kubernetes-list-type: map type: object + maxRequestHeaderLimit: + allOf: + - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + - pattern: ^[1-9]+[0-9]*([EPTGMK]i|[EPTGMk])?$ + anyOf: + - type: integer + - type: string + description: |- + MaxRequestHeaderLimit provides configuration for the maximum size of the + request headers allowed for incoming connections, mapping to the Envoy + `max_request_headers_kb` HTTP connection manager setting. Requests whose + headers exceed this limit receive a 431 (Request Header Fields Too Large) + response. The value is rounded up to the nearest KiB, must be at least 1Ki, + and cannot exceed 8192Ki (the maximum Envoy supports). + For example, 60Ki, 96Ki, 128Ki etc. + Note that when the suffix is not provided, the value is interpreted as bytes. + Default: 60Ki bytes. + x-kubernetes-int-or-string: true preserveXRequestID: description: |- PreserveXRequestID configures Envoy to keep the X-Request-ID header if passed for a request that is edge diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index f6daf2a3ae2..697ba63ec71 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -1001,6 +1001,10 @@ func translateClientIPDetection(clientIPDetection *egv1a1.ClientIPDetectionSetti httpIR.ClientIPDetection = (*ir.ClientIPDetectionSettings)(clientIPDetection) } +// maxRequestHeaderLimitKB is the maximum value (in KiB) that Envoy supports for +// the HTTP connection manager max_request_headers_kb setting. +const maxRequestHeaderLimitKB = 8192 + func translateListenerHeaderSettings(headerSettings *egv1a1.HeaderSettings, httpIR *ir.HTTPListener) error { if headerSettings == nil { return nil @@ -1035,6 +1039,23 @@ func translateListenerHeaderSettings(headerSettings *egv1a1.HeaderSettings, http var errs error + if headerSettings.MaxRequestHeaderLimit != nil { + // Envoy's max_request_headers_kb is expressed in KiB, so convert the + // byte quantity and round up to the nearest KiB. + bytes, ok := headerSettings.MaxRequestHeaderLimit.AsInt64() + switch { + case !ok || bytes < 1024: + errs = errors.Join(errs, fmt.Errorf("MaxRequestHeaderLimit value %s must be at least 1Ki", headerSettings.MaxRequestHeaderLimit.String())) + default: + kb := (bytes + 1023) / 1024 + if kb > maxRequestHeaderLimitKB { + errs = errors.Join(errs, fmt.Errorf("MaxRequestHeaderLimit value %s exceeds the maximum of %dKi", headerSettings.MaxRequestHeaderLimit.String(), maxRequestHeaderLimitKB)) + } else { + httpIR.Headers.MaxRequestHeadersKB = ptr.To(uint32(kb)) + } + } + } + if headerSettings.EarlyRequestHeaders != nil { headersToAdd, headersToRemove, removeOnMatch, err := translateHeaderModifier(headerSettings.EarlyRequestHeaders, "EarlyRequestHeaders") if err != nil { diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.in.yaml new file mode 100644 index 00000000000..b60c4a74ec2 --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.in.yaml @@ -0,0 +1,29 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + namespace: envoy-gateway + name: target-gateway-1 + generation: 10 + spec: + headers: + maxRequestHeaderLimit: "512" + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-1 + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: Same diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.out.yaml new file mode 100644 index 00000000000..c2df66e38b5 --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit-with-error.out.yaml @@ -0,0 +1,142 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + generation: 10 + name: target-gateway-1 + namespace: envoy-gateway + spec: + headers: + maxRequestHeaderLimit: "512" + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: 'Headers: MaxRequestHeaderLimit value 512 must be at least 1Ki.' + observedGeneration: 10 + reason: Invalid + status: "False" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + observedGeneration: 10 + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http-1 + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - name: envoy-gateway/gateway-1/http-1 + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + headers: + withUnderscoresAction: RejectRequest + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http-1 + name: envoy-gateway/gateway-1/http-1 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.in.yaml new file mode 100644 index 00000000000..05134ef8ce9 --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.in.yaml @@ -0,0 +1,29 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + namespace: envoy-gateway + name: target-gateway-1 + generation: 10 + spec: + headers: + maxRequestHeaderLimit: 96Ki + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-1 + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: Same diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.out.yaml new file mode 100644 index 00000000000..ded993ac327 --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-max-request-header-limit.out.yaml @@ -0,0 +1,143 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + generation: 10 + name: target-gateway-1 + namespace: envoy-gateway + spec: + headers: + maxRequestHeaderLimit: 96Ki + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + observedGeneration: 10 + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: spec.targetRef is deprecated, use spec.targetRefs instead + observedGeneration: 10 + reason: DeprecatedField + status: "True" + type: Warning + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http-1 + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - name: envoy-gateway/gateway-1/http-1 + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + headers: + maxRequestHeadersKB: 96 + withUnderscoresAction: RejectRequest + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http-1 + name: envoy-gateway/gateway-1/http-1 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/ir/xds.go b/internal/ir/xds.go index a1cf02a509b..7a94f459607 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -951,6 +951,10 @@ type HeaderSettings struct { // LateRemoveResponseHeadersOnMatch defines header name matchers that would remove headers after envoy response processing. LateRemoveResponseHeadersOnMatch []*StringMatch `json:"lateRemoveResponseHeadersOnMatch,omitempty" yaml:"lateRemoveResponseHeadersOnMatch,omitempty"` + + // MaxRequestHeadersKB defines the maximum request headers size in KiB allowed for incoming connections. + // Maps to the Envoy `max_request_headers_kb` HTTP connection manager setting. + MaxRequestHeadersKB *uint32 `json:"maxRequestHeadersKB,omitempty" yaml:"maxRequestHeadersKB,omitempty"` } // ClientTimeout sets the timeout configuration for downstream connections diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 252d73c9259..ae7b305c589 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -2822,6 +2822,11 @@ func (in *HeaderSettings) DeepCopyInto(out *HeaderSettings) { } } } + if in.MaxRequestHeadersKB != nil { + in, out := &in.MaxRequestHeadersKB, &out.MaxRequestHeadersKB + *out = new(uint32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HeaderSettings. diff --git a/internal/xds/translator/listener.go b/internal/xds/translator/listener.go index be3e2eb1367..48c038a9765 100644 --- a/internal/xds/translator/listener.go +++ b/internal/xds/translator/listener.go @@ -406,6 +406,11 @@ func (t *Translator) addHCMToXDSListener( mgr.StripTrailingHostDot = irListener.Host.StripTrailingHostDot } + // Set the maximum request headers size if configured. + if h := irListener.Headers; h != nil && h.MaxRequestHeadersKB != nil { + mgr.MaxRequestHeadersKb = wrapperspb.UInt32(*h.MaxRequestHeadersKB) + } + // Set the :scheme header to match the upstream transport protocol (http/https) if configured. // This ensures the correct scheme is sent to backends using TLS when enabled. if irListener.MatchBackendScheme { diff --git a/internal/xds/translator/testdata/in/xds-ir/max-request-headers-kb.yaml b/internal/xds/translator/testdata/in/xds-ir/max-request-headers-kb.yaml new file mode 100644 index 00000000000..4043ce9b6d2 --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/max-request-headers-kb.yaml @@ -0,0 +1,18 @@ +http: + - name: "first-listener" + address: "::" + port: 8081 + hostnames: + - "*" + routes: + - name: "first-route" + hostname: "*" + destination: + name: "first-route-dest" + settings: + - endpoints: + - host: "1.1.1.1" + port: 8081 + name: "first-route-dest/backend/0" + headers: + maxRequestHeadersKB: 96 diff --git a/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.clusters.yaml new file mode 100644 index 00000000000..886a7d9f6cd --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.clusters.yaml @@ -0,0 +1,23 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: first-route-dest + ignoreHealthOnHostRemoval: true + loadBalancingPolicy: + policies: + - typedExtensionConfig: + name: envoy.load_balancing_policies.least_request + typedConfig: + '@type': type.googleapis.com/envoy.extensions.load_balancing_policies.least_request.v3.LeastRequest + localityLbConfig: + localityWeightedLbConfig: {} + name: first-route-dest + perConnectionBufferLimitBytes: 32768 + type: EDS diff --git a/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.endpoints.yaml new file mode 100644 index 00000000000..79a52664410 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.endpoints.yaml @@ -0,0 +1,12 @@ +- clusterName: first-route-dest + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 1.1.1.1 + portValue: 8081 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: first-route-dest/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.listeners.yaml new file mode 100644 index 00000000000..96486484aea --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.listeners.yaml @@ -0,0 +1,34 @@ +- address: + socketAddress: + address: '::' + portValue: 8081 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + maxRequestHeadersKb: 96 + normalizePath: true + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: first-listener + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-8081 + useRemoteAddress: true + name: first-listener + maxConnectionsToAcceptPerSocketEvent: 1 + name: first-listener + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.routes.yaml new file mode 100644 index 00000000000..0b5b4bee7bb --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/max-request-headers-kb.routes.yaml @@ -0,0 +1,14 @@ +- ignorePortInHostMatching: true + name: first-listener + virtualHosts: + - domains: + - '*' + name: first-listener/* + routes: + - match: + prefix: / + name: first-route + route: + cluster: first-route-dest + upgradeConfigs: + - upgradeType: websocket diff --git a/release-notes/current/new_features/5368-max-request-header-limit-clienttrafficpolicy.md b/release-notes/current/new_features/5368-max-request-header-limit-clienttrafficpolicy.md new file mode 100644 index 00000000000..2a96e95523f --- /dev/null +++ b/release-notes/current/new_features/5368-max-request-header-limit-clienttrafficpolicy.md @@ -0,0 +1 @@ +Added a `maxRequestHeaderLimit` field under `ClientTrafficPolicy`'s `headers` to configure the maximum request header size (Envoy's `max_request_headers_kb`) without an EnvoyPatchPolicy. The value is a Quantity rounded up to the nearest KiB, must be at least 1Ki, and cannot exceed 8192Ki. diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 12e60a35cc0..4217fbaba3e 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -3421,6 +3421,7 @@ _Appears in:_ | `earlyRequestHeaders` | _[HTTPHeaderFilter](#httpheaderfilter)_ | false | | EarlyRequestHeaders defines settings for early request header modification, before envoy performs
routing, tracing and built-in header manipulation. | | `lateResponseHeaders` | _[HTTPHeaderFilter](#httpheaderfilter)_ | false | | LateResponseHeaders defines settings for global response header modification. | | `host` | _[HostSettings](#hostsettings)_ | false | | Host enables managing how the Host/Authority header set by clients can be normalized. | +| `maxRequestHeaderLimit` | _[Quantity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#quantity-resource-api)_ | false | | MaxRequestHeaderLimit provides configuration for the maximum size of the
request headers allowed for incoming connections, mapping to the Envoy
`max_request_headers_kb` HTTP connection manager setting. Requests whose
headers exceed this limit receive a 431 (Request Header Fields Too Large)
response. The value is rounded up to the nearest KiB, must be at least 1Ki,
and cannot exceed 8192Ki (the maximum Envoy supports).
For example, 60Ki, 96Ki, 128Ki etc.
Note that when the suffix is not provided, the value is interpreted as bytes.
Default: 60Ki bytes. | #### HealthCheck