Skip to content

Commit

Permalink
Adds configuration to retain client IP information (#2284)
Browse files Browse the repository at this point in the history
Problem: As a user, I want to be able to retain client IP information when a requests comes in to NGF.

Solution: Introduces configuration that allows retaining client IP information using the real_ip module.
  • Loading branch information
salonichf5 authored Sep 6, 2024
1 parent 6b9ad3a commit bf17bd5
Show file tree
Hide file tree
Showing 21 changed files with 1,549 additions and 150 deletions.
89 changes: 89 additions & 0 deletions apis/v1alpha1/nginxproxy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ type NginxProxySpec struct {
//
// +optional
Telemetry *Telemetry `json:"telemetry,omitempty"`
// RewriteClientIP defines configuration for rewriting the client IP to the original client's IP.
// +kubebuilder:validation:XValidation:message="if mode is set, trustedAddresses is a required field",rule="!(has(self.mode) && (!has(self.trustedAddresses) || size(self.trustedAddresses) == 0))"
//
// +optional
//nolint:lll
RewriteClientIP *RewriteClientIP `json:"rewriteClientIP,omitempty"`
// DisableHTTP2 defines if http2 should be disabled for all servers.
// Default is false, meaning http2 will be enabled for all servers.
//
Expand Down Expand Up @@ -114,3 +120,86 @@ type TelemetryExporter struct {
// +kubebuilder:validation:Pattern=`^(?:http?:\/\/)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*(?::\d{1,5})?$`
Endpoint string `json:"endpoint"`
}

// RewriteClientIP specifies the configuration for rewriting the client's IP address.
type RewriteClientIP struct {
// Mode defines how NGINX will rewrite the client's IP address.
// There are two possible modes:
// - ProxyProtocol: NGINX will rewrite the client's IP using the PROXY protocol header.
// - XForwardedFor: NGINX will rewrite the client's IP using the X-Forwarded-For header.
// Sets NGINX directive real_ip_header: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header
//
// +optional
Mode *RewriteClientIPModeType `json:"mode,omitempty"`

// SetIPRecursively configures whether recursive search is used when selecting the client's address from
// the X-Forwarded-For header. It is used in conjunction with TrustedAddresses.
// If enabled, NGINX will recurse on the values in X-Forwarded-Header from the end of array
// to start of array and select the first untrusted IP.
// For example, if X-Forwarded-For is [11.11.11.11, 22.22.22.22, 55.55.55.1],
// and TrustedAddresses is set to 55.55.55.1/32, NGINX will rewrite the client IP to 22.22.22.22.
// If disabled, NGINX will select the IP at the end of the array.
// In the previous example, 55.55.55.1 would be selected.
// Sets NGINX directive real_ip_recursive: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive
//
// +optional
SetIPRecursively *bool `json:"setIPRecursively,omitempty"`

// TrustedAddresses specifies the addresses that are trusted to send correct client IP information.
// If a request comes from a trusted address, NGINX will rewrite the client IP information,
// and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers.
// If the request does not come from a trusted address, NGINX will not rewrite the client IP information.
// TrustedAddresses only supports CIDR blocks: 192.33.21.1/24, fe80::1/64.
// To trust all addresses (not recommended for production), set to 0.0.0.0/0.
// If no addresses are provided, NGINX will not rewrite the client IP information.
// Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from
// This field is required if mode is set.
// +kubebuilder:validation:MaxItems=16
// +listType=map
// +listMapKey=type
//
// +optional
TrustedAddresses []Address `json:"trustedAddresses,omitempty"`
}

// RewriteClientIPModeType defines how NGINX Gateway Fabric will determine the client's original IP address.
// +kubebuilder:validation:Enum=ProxyProtocol;XForwardedFor
type RewriteClientIPModeType string

const (
// RewriteClientIPModeProxyProtocol configures NGINX to accept PROXY protocol and
// set the client's IP address to the IP address in the PROXY protocol header.
// Sets the proxy_protocol parameter on the listen directive of all servers and sets real_ip_header
// to proxy_protocol: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header.
RewriteClientIPModeProxyProtocol RewriteClientIPModeType = "ProxyProtocol"

// RewriteClientIPModeXForwardedFor configures NGINX to set the client's IP address to the
// IP address in the X-Forwarded-For HTTP header.
// https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header.
RewriteClientIPModeXForwardedFor RewriteClientIPModeType = "XForwardedFor"
)

// Address is a struct that specifies address type and value.
type Address struct {
// Type specifies the type of address.
// Default is "cidr" which specifies that the address is a CIDR block.
//
// +optional
// +kubebuilder:default:=cidr
Type AddressType `json:"type,omitempty"`

// Value specifies the address value.
//
// +optional
Value string `json:"value,omitempty"`
}

// AddressType specifies the type of address.
// +kubebuilder:validation:Enum=cidr
type AddressType string

const (
// AddressTypeCIDR specifies that the address is a CIDR block.
// kubebuilder:validation:Pattern=`^[\.a-zA-Z0-9:]*(\/([0-9]?[0-9]?[0-9]))$`
AddressTypeCIDR AddressType = "cidr"
)
50 changes: 50 additions & 0 deletions apis/v1alpha1/zz_generated.deepcopy.go

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

11 changes: 11 additions & 0 deletions charts/nginx-gateway-fabric/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ nginx:
{}
# disableHTTP2: false
# ipFamily: dual
# rewriteClientIP:
# mode: "ProxyProtocol"
# # -- The trusted addresses field needs to be replaced with the load balancer's address and type.
# trustedAddresses: [
# {
# # -- The CIDR block of the load balancer(s).
# value: "",
# type: "cidr",
# }
# ]
# setIPRecursively: true
# telemetry:
# exporter:
# endpoint: otel-collector.default.svc:4317
Expand Down
64 changes: 64 additions & 0 deletions config/crd/bases/gateway.nginx.org_nginxproxies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,70 @@ spec:
- ipv4
- ipv6
type: string
rewriteClientIP:
description: RewriteClientIP defines configuration for rewriting the
client IP to the original client's IP.
properties:
mode:
description: |-
Mode defines how NGINX will rewrite the client's IP address.
There are two possible modes:
- ProxyProtocol: NGINX will rewrite the client's IP using the PROXY protocol header.
- XForwardedFor: NGINX will rewrite the client's IP using the X-Forwarded-For header.
Sets NGINX directive real_ip_header: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header
enum:
- ProxyProtocol
- XForwardedFor
type: string
setIPRecursively:
description: |-
SetIPRecursively configures whether recursive search is used when selecting the client's address from
the X-Forwarded-For header. It is used in conjunction with TrustedAddresses.
If enabled, NGINX will recurse on the values in X-Forwarded-Header from the end of array
to start of array and select the first untrusted IP.
For example, if X-Forwarded-For is [11.11.11.11, 22.22.22.22, 55.55.55.1],
and TrustedAddresses is set to 55.55.55.1/32, NGINX will rewrite the client IP to 22.22.22.22.
If disabled, NGINX will select the IP at the end of the array.
In the previous example, 55.55.55.1 would be selected.
Sets NGINX directive real_ip_recursive: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive
type: boolean
trustedAddresses:
description: |-
TrustedAddresses specifies the addresses that are trusted to send correct client IP information.
If a request comes from a trusted address, NGINX will rewrite the client IP information,
and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers.
If the request does not come from a trusted address, NGINX will not rewrite the client IP information.
TrustedAddresses only supports CIDR blocks: 192.33.21.1/24, fe80::1/64.
To trust all addresses (not recommended for production), set to 0.0.0.0/0.
If no addresses are provided, NGINX will not rewrite the client IP information.
Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from
This field is required if mode is set.
items:
description: Address is a struct that specifies address type
and value.
properties:
type:
default: cidr
description: |-
Type specifies the type of address.
Default is "cidr" which specifies that the address is a CIDR block.
enum:
- cidr
type: string
value:
description: Value specifies the address value.
type: string
type: object
maxItems: 16
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
type: object
x-kubernetes-validations:
- message: if mode is set, trustedAddresses is a required field
rule: '!(has(self.mode) && (!has(self.trustedAddresses) || size(self.trustedAddresses)
== 0))'
telemetry:
description: Telemetry specifies the OpenTelemetry configuration.
properties:
Expand Down
64 changes: 64 additions & 0 deletions deploy/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,70 @@ spec:
- ipv4
- ipv6
type: string
rewriteClientIP:
description: RewriteClientIP defines configuration for rewriting the
client IP to the original client's IP.
properties:
mode:
description: |-
Mode defines how NGINX will rewrite the client's IP address.
There are two possible modes:
- ProxyProtocol: NGINX will rewrite the client's IP using the PROXY protocol header.
- XForwardedFor: NGINX will rewrite the client's IP using the X-Forwarded-For header.
Sets NGINX directive real_ip_header: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header
enum:
- ProxyProtocol
- XForwardedFor
type: string
setIPRecursively:
description: |-
SetIPRecursively configures whether recursive search is used when selecting the client's address from
the X-Forwarded-For header. It is used in conjunction with TrustedAddresses.
If enabled, NGINX will recurse on the values in X-Forwarded-Header from the end of array
to start of array and select the first untrusted IP.
For example, if X-Forwarded-For is [11.11.11.11, 22.22.22.22, 55.55.55.1],
and TrustedAddresses is set to 55.55.55.1/32, NGINX will rewrite the client IP to 22.22.22.22.
If disabled, NGINX will select the IP at the end of the array.
In the previous example, 55.55.55.1 would be selected.
Sets NGINX directive real_ip_recursive: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_recursive
type: boolean
trustedAddresses:
description: |-
TrustedAddresses specifies the addresses that are trusted to send correct client IP information.
If a request comes from a trusted address, NGINX will rewrite the client IP information,
and forward it to the backend in the X-Forwarded-For* and X-Real-IP headers.
If the request does not come from a trusted address, NGINX will not rewrite the client IP information.
TrustedAddresses only supports CIDR blocks: 192.33.21.1/24, fe80::1/64.
To trust all addresses (not recommended for production), set to 0.0.0.0/0.
If no addresses are provided, NGINX will not rewrite the client IP information.
Sets NGINX directive set_real_ip_from: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from
This field is required if mode is set.
items:
description: Address is a struct that specifies address type
and value.
properties:
type:
default: cidr
description: |-
Type specifies the type of address.
Default is "cidr" which specifies that the address is a CIDR block.
enum:
- cidr
type: string
value:
description: Value specifies the address value.
type: string
type: object
maxItems: 16
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
type: object
x-kubernetes-validations:
- message: if mode is set, trustedAddresses is a required field
rule: '!(has(self.mode) && (!has(self.trustedAddresses) || size(self.trustedAddresses)
== 0))'
telemetry:
description: Telemetry specifies the OpenTelemetry configuration.
properties:
Expand Down
12 changes: 8 additions & 4 deletions internal/mode/static/nginx/config/http/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package http

import "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config/shared"

const InternalRoutePathPrefix = "/_ngf-internal"
const (
InternalRoutePathPrefix = "/_ngf-internal"
HTTPSScheme = "https"
)

// Server holds all configuration for an HTTP server.
type Server struct {
Expand Down Expand Up @@ -109,9 +112,10 @@ type ProxySSLVerify struct {

// ServerConfig holds configuration for an HTTP server and IP family to be used by NGINX.
type ServerConfig struct {
Servers []Server
IPFamily shared.IPFamily
Plus bool
Servers []Server
RewriteClientIP shared.RewriteClientIPSettings
IPFamily shared.IPFamily
Plus bool
}

// Include defines a file that's included via the include directive.
Expand Down
Loading

0 comments on commit bf17bd5

Please sign in to comment.