Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support Client IP Detection using XFF on ClientTrafficPolicy #2535

Merged
merged 15 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions api/v1alpha1/clienttrafficpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ type ClientTrafficPolicySpec struct {
//
// +optional
EnableProxyProtocol *bool `json:"enableProxyProtocol,omitempty"`
// ClientIPDetectionSettings provides XFF and extension configuration for client IP detection on the listener.
//
// +optional
ClientIPDetection *ClientIPDetectionSettings `json:"clientIPDetection,omitempty"`
// HTTP3 provides HTTP/3 configuration on the listener.
//
// +optional
Expand All @@ -84,6 +88,73 @@ type ClientTrafficPolicySpec struct {
HTTP1 *HTTP1Settings `json:"http1,omitempty"`
}

// ClientIPDetectionSettings provides XFF and extension configuration for client IP detection on the listener.
//
// +kubebuilder:validation:XValidation:rule="!(has(self.xffNumTrustedHops) && has(self.extensions))",message="extensions cannot be used in conjunction with xffNumTrustedHops"
type ClientIPDetectionSettings struct {
davidalger marked this conversation as resolved.
Show resolved Hide resolved
// XffNumTrustedHops controls the number of additional ingress proxy hops from the right side of XFF HTTP
// headers to trust when determining the origin client's IP address.
// Refer to https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-forwarded-for
// for more details.
//
// +optional
XffNumTrustedHops *uint32 `json:"xffNumTrustedHops,omitempty"`
// Extensions provides configuration for supported original IP detection extensions. Refer to:
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#envoy-v3-api-field-extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-original-ip-detection-extensions
// for more details.
//
// +optional
Extensions *OriginalIPDetectionExtensions `json:"extensions,omitempty"`
}

// OriginalIPDetectionExtensions provides a list of extensions to be used for client IP detection.
//
// +kubebuilder:validation:XValidation:rule="!(has(self.customHeader) && has(self.xff))",message="customHeader cannot be used in conjunction with xff"
type OriginalIPDetectionExtensions struct {
// CustomHeader provides configuration for the custom header original IP detection extension.
// Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/original_ip_detection/custom_header/v3/custom_header.proto
// for more details.
//
// +optional
CustomHeader *CustomHeaderExtensionSettings `json:"customHeader,omitempty"`
// Xff provides configuration for the XFF original IP detection extension.
// Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/original_ip_detection/xff/v3/xff.proto
// for more details.
//
// +optional
Xff *XffExtensionSettings `json:"xff,omitempty"`
}

// CustomHeaderExtensionSettings provides configuration for the custom header original IP detection extension.
type CustomHeaderExtensionSettings struct {
// HeaderName of the of the header containing the original downstream remote address, if present.
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=255
// +kubebuilder:validation:Pattern="^[A-Za-z0-9-]+$"
//
HeaderName string `json:"headerName"`
// RejectWithStatus is the HTTP response status to use when detection fails, if present. May be
// any valid HTTP response status code within the range 400-511 (inclusive).
//
// +kubebuilder:validation:Minimum=400
// +kubebuilder:validation:Maximum=511
//
// +optional
RejectWithStatus *uint32 `json:"rejectWithStatus,omitempty"`
// AllowExtensionToSetAddressAsTrusted allows the extension to mark the address as trusted
// by the HCM, allowing the address to be used to determine if the request is internal.
//
// +optional
AllowExtensionToSetAddressAsTrusted bool `json:"allowExtensionToSetAddressAsTrusted"`
}

// XffExtensionSettings provides configuration for the XFF original IP detection extension.
type XffExtensionSettings struct {
// NumTrustedHops controls the number of additional ingress proxy hops from the right side of XFF HTTP
NumTrustedHops uint32 `json:"numTrustedHops"`
davidalger marked this conversation as resolved.
Show resolved Hide resolved
davidalger marked this conversation as resolved.
Show resolved Hide resolved
}

// HTTP3Settings provides HTTP/3 configuration on the listener.
type HTTP3Settings struct {
}
Expand Down
90 changes: 90 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,74 @@ spec:
spec:
description: Spec defines the desired state of ClientTrafficPolicy.
properties:
clientIPDetection:
description: ClientIPDetectionSettings provides XFF and extension
configuration for client IP detection on the listener.
properties:
extensions:
description: 'Extensions provides configuration for supported
original IP detection extensions. Refer to: https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#envoy-v3-api-field-extensions-filters-network-http-connection-manager-v3-httpconnectionmanager-original-ip-detection-extensions
for more details.'
properties:
customHeader:
description: CustomHeader provides configuration for the custom
header original IP detection extension. Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/original_ip_detection/custom_header/v3/custom_header.proto
for more details.
properties:
allowExtensionToSetAddressAsTrusted:
description: AllowExtensionToSetAddressAsTrusted allows
the extension to mark the address as trusted by the
HCM, allowing the address to be used to determine if
the request is internal.
type: boolean
headerName:
description: HeaderName of the of the header containing
the original downstream remote address, if present.
maxLength: 255
minLength: 1
pattern: ^[A-Za-z0-9-]+$
type: string
rejectWithStatus:
description: RejectWithStatus is the HTTP response status
to use when detection fails, if present. May be any
valid HTTP response status code within the range 400-511
(inclusive).
format: int32
maximum: 511
minimum: 400
type: integer
required:
- headerName
type: object
xff:
description: Xff provides configuration for the XFF original
IP detection extension. Refer to https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/original_ip_detection/xff/v3/xff.proto
for more details.
properties:
numTrustedHops:
description: NumTrustedHops controls the number of additional
ingress proxy hops from the right side of XFF HTTP
format: int32
type: integer
required:
- numTrustedHops
type: object
type: object
x-kubernetes-validations:
- message: customHeader cannot be used in conjunction with xff
rule: '!(has(self.customHeader) && has(self.xff))'
xffNumTrustedHops:
description: XffNumTrustedHops controls the number of additional
ingress proxy hops from the right side of XFF HTTP headers to
trust when determining the origin client's IP address. Refer
to https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-forwarded-for
for more details.
format: int32
type: integer
type: object
x-kubernetes-validations:
- message: extensions cannot be used in conjunction with xffNumTrustedHops
rule: '!(has(self.xffNumTrustedHops) && has(self.extensions))'
enableProxyProtocol:
description: EnableProxyProtocol interprets the ProxyProtocol header
and adds the Client Address into the X-Forwarded-For header. Note
Expand Down
12 changes: 12 additions & 0 deletions internal/gatewayapi/clienttrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ func (t *Translator) translateClientTrafficPolicyForListener(policySpec *egv1a1.
// Translate Proxy Protocol
translateListenerProxyProtocol(policySpec.EnableProxyProtocol, httpIR)

// Translate Client IP Detection
translateClientIPDetection(policySpec.ClientIPDetection, httpIR)

// Translate Suppress Envoy Headers
translateListenerSuppressEnvoyHeaders(policySpec.SuppressEnvoyHeaders, httpIR)

Expand Down Expand Up @@ -375,6 +378,15 @@ func translateListenerProxyProtocol(enableProxyProtocol *bool, httpIR *ir.HTTPLi
}
}

func translateClientIPDetection(clientIPDetection *egv1a1.ClientIPDetectionSettings, httpIR *ir.HTTPListener) {
// Return early if not set
if clientIPDetection == nil {
return
}

httpIR.ClientIPDetection = (*ir.ClientIPDetectionSettings)(clientIPDetection)
}

func translateListenerSuppressEnvoyHeaders(suppressEnvoyHeaders *bool, httpIR *ir.HTTPListener) {
if suppressEnvoyHeaders != nil {
httpIR.SuppressEnvoyHeaders = *suppressEnvoyHeaders
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
clientTrafficPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
namespace: envoy-gateway
name: target-gateway-1-http-1
spec:
clientIPDetection:
xffNumTrustedHops: 2
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
namespace: envoy-gateway
sectionName: http-1
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
namespace: envoy-gateway
name: target-gateway-1-http-2
spec:
clientIPDetection:
extensions:
customHeader:
headerName: "x-client-ip-address"
rejectWithStatus: 500
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
namespace: envoy-gateway
sectionName: http-2
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
namespace: envoy-gateway
name: target-gateway-1-http-3
spec:
clientIPDetection:
extensions:
xff:
numTrustedHops: 1
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
namespace: envoy-gateway
sectionName: http-3
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: 8081
allowedRoutes:
namespaces:
from: Same
- name: http-2
protocol: HTTP
port: 8082
allowedRoutes:
namespaces:
from: Same
- name: http-3
protocol: HTTP
port: 8083
allowedRoutes:
namespaces:
from: Same
- name: http-4
protocol: HTTP
port: 8084
allowedRoutes:
namespaces:
from: Same
Loading
Loading