From 1984180756ed9a46d005250be7783340269df822 Mon Sep 17 00:00:00 2001 From: Saloni Date: Thu, 29 Aug 2024 15:22:38 -0600 Subject: [PATCH] updates based on reviews --- apis/v1alpha1/nginxproxy_types.go | 12 +- charts/nginx-gateway-fabric/values.yaml | 4 +- .../bases/gateway.nginx.org_nginxproxies.yaml | 13 ++- deploy/crds.yaml | 13 ++- .../mode/static/nginx/config/http/config.go | 5 +- internal/mode/static/nginx/config/servers.go | 34 ++++-- .../static/nginx/config/servers_template.go | 4 +- .../mode/static/nginx/config/servers_test.go | 64 +++++++++-- .../static/nginx/config/stream_servers.go | 17 +-- .../nginx/config/stream_servers_template.go | 6 +- .../nginx/config/stream_servers_test.go | 21 ++-- .../static/state/dataplane/configuration.go | 6 +- .../state/dataplane/configuration_test.go | 24 ++-- internal/mode/static/state/dataplane/types.go | 2 +- .../mode/static/state/graph/nginxproxy.go | 13 ++- .../static/state/graph/nginxproxy_test.go | 29 ++++- .../how-to/monitoring/troubleshooting.md | 106 +++++++++--------- site/content/reference/api.md | 13 +-- 18 files changed, 230 insertions(+), 156 deletions(-) diff --git a/apis/v1alpha1/nginxproxy_types.go b/apis/v1alpha1/nginxproxy_types.go index 867e8113dd..f1d03b9e54 100644 --- a/apis/v1alpha1/nginxproxy_types.go +++ b/apis/v1alpha1/nginxproxy_types.go @@ -54,7 +54,7 @@ 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))" + // +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 @@ -132,12 +132,12 @@ type RewriteClientIP struct { // +optional Mode *RewriteClientIPModeType `json:"mode,omitempty"` - // SetIPRecursively configures whether recursive search is used when selecting the client's address from. + // 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/0, NGINX will rewrite the client IP to 22.22.22.22. + // and TrustedAddresses is set to 55.55.55.1, 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 @@ -149,7 +149,7 @@ type RewriteClientIP struct { // 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. - // Addresses must be provided as CIDR blocks: 10.0.0.0/32, 192.33.21/0. + // Addresses must be provided as CIDR blocks or IP address: 10.0.0.0, 192.33.21/24, fe80::1/128. // To trust all addresses (not recommended), 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 @@ -179,8 +179,8 @@ const ( RewriteClientIPModeXForwardedFor RewriteClientIPModeType = "XForwardedFor" ) -// TrustedAddress is a string value representing a CIDR block. -// Examples: 0.0.0.0/0 +// TrustedAddress is a string value representing a CIDR block or an IP address. +// Examples: 10.0.0.2/32, 10.0.0.1, fe80::1/128, ::1/24. // // +kubebuilder:validation:Pattern=`^(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3}(?:\/(?:[0-9]|[12][0-9]|3[0-2]))?|(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}(?:\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?)$` // diff --git a/charts/nginx-gateway-fabric/values.yaml b/charts/nginx-gateway-fabric/values.yaml index 758b12fc35..322776125d 100644 --- a/charts/nginx-gateway-fabric/values.yaml +++ b/charts/nginx-gateway-fabric/values.yaml @@ -94,8 +94,8 @@ nginx: # disableHTTP2: false # ipFamily: dual # rewriteClientIP: - # mode: "XForwadedFor" - # # -- The trusted addresses field needs to be replaced with the load balancer's IP address. + # mode: "XForwardedFor" + # # -- Set to the CIDR range or IP of the proxy that sits in front of NGINX Gateway Fabric. # trustedAddresses: [] # setIPRecursively: true # telemetry: diff --git a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml index 81ea4c1bd9..3f9fd62e9f 100644 --- a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml +++ b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml @@ -79,12 +79,12 @@ spec: type: string setIPRecursively: description: |- - SetIPRecursively configures whether recursive search is used when selecting the client's address from. + 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/0, NGINX will rewrite the client IP to 22.22.22.22. + and TrustedAddresses is set to 55.55.55.1, 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 @@ -95,15 +95,15 @@ spec: 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. - Addresses must be provided as CIDR blocks: 10.0.0.0/32, 192.33.21/0. + Addresses must be provided as CIDR blocks or IP address: 10.0.0.0, 192.33.21/24, fe80::1/128. To trust all addresses (not recommended), 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: |- - TrustedAddress is a string value representing a CIDR block. - Examples: 0.0.0.0/0 + TrustedAddress is a string value representing a CIDR block or an IP address. + Examples: 10.0.0.2/32, 10.0.0.1, fe80::1/128, ::1/24. pattern: ^(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3}(?:\/(?:[0-9]|[12][0-9]|3[0-2]))?|(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}(?:\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?)$ type: string maxItems: 16 @@ -112,7 +112,8 @@ spec: type: object x-kubernetes-validations: - message: if mode is set, trustedAddresses is a required field - rule: '!(has(self.mode) && !has(self.trustedAddresses))' + rule: '!(has(self.mode) && (!has(self.trustedAddresses) || size(self.trustedAddresses) + == 0))' telemetry: description: Telemetry specifies the OpenTelemetry configuration. properties: diff --git a/deploy/crds.yaml b/deploy/crds.yaml index bd19100a3f..1c6163fb1c 100644 --- a/deploy/crds.yaml +++ b/deploy/crds.yaml @@ -664,12 +664,12 @@ spec: type: string setIPRecursively: description: |- - SetIPRecursively configures whether recursive search is used when selecting the client's address from. + 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/0, NGINX will rewrite the client IP to 22.22.22.22. + and TrustedAddresses is set to 55.55.55.1, 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 @@ -680,15 +680,15 @@ spec: 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. - Addresses must be provided as CIDR blocks: 10.0.0.0/32, 192.33.21/0. + Addresses must be provided as CIDR blocks or IP address: 10.0.0.0, 192.33.21/24, fe80::1/128. To trust all addresses (not recommended), 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: |- - TrustedAddress is a string value representing a CIDR block. - Examples: 0.0.0.0/0 + TrustedAddress is a string value representing a CIDR block or an IP address. + Examples: 10.0.0.2/32, 10.0.0.1, fe80::1/128, ::1/24. pattern: ^(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3}(?:\/(?:[0-9]|[12][0-9]|3[0-2]))?|(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}(?:\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?)$ type: string maxItems: 16 @@ -697,7 +697,8 @@ spec: type: object x-kubernetes-validations: - message: if mode is set, trustedAddresses is a required field - rule: '!(has(self.mode) && !has(self.trustedAddresses))' + rule: '!(has(self.mode) && (!has(self.trustedAddresses) || size(self.trustedAddresses) + == 0))' telemetry: description: Telemetry specifies the OpenTelemetry configuration. properties: diff --git a/internal/mode/static/nginx/config/http/config.go b/internal/mode/static/nginx/config/http/config.go index ee45daf98c..f17d51e5d5 100644 --- a/internal/mode/static/nginx/config/http/config.go +++ b/internal/mode/static/nginx/config/http/config.go @@ -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 { diff --git a/internal/mode/static/nginx/config/servers.go b/internal/mode/static/nginx/config/servers.go index 92a3dcb015..eeac39944f 100644 --- a/internal/mode/static/nginx/config/servers.go +++ b/internal/mode/static/nginx/config/servers.go @@ -800,14 +800,7 @@ func generateProxySetHeaders(filters *dataplane.HTTPFilters, grpc bool) []http.H copy(headers, grpcBaseHeaders) } - if filters != nil && filters.RequestURLRewrite != nil && filters.RequestURLRewrite.Hostname != nil { - for i, header := range headers { - if header.Name == "Host" { - headers[i].Value = *filters.RequestURLRewrite.Hostname - break - } - } - } + setHeaderForHTTPSRedirect(filters, headers) if filters == nil || filters.RequestHeaderModifiers == nil { return headers @@ -836,6 +829,29 @@ func generateProxySetHeaders(filters *dataplane.HTTPFilters, grpc bool) []http.H return append(proxySetHeaders, headers...) } +func setHeaderForHTTPSRedirect(filters *dataplane.HTTPFilters, headers []http.Header) { + if filters != nil { + if filters.RequestURLRewrite != nil && filters.RequestURLRewrite.Hostname != nil { + for i, header := range headers { + if header.Name == "Host" { + headers[i].Value = *filters.RequestURLRewrite.Hostname + break + } + } + } + if filters.RequestRedirect != nil && + filters.RequestRedirect.Scheme != nil && + *filters.RequestRedirect.Scheme == http.HTTPSScheme { + for i, header := range headers { + if header.Name == "X-Forwarded-Proto" { + headers[i].Value = http.HTTPSScheme + return + } + } + } + } +} + func generateResponseHeaders(filters *dataplane.HTTPFilters) http.ResponseHeaders { if filters == nil || filters.ResponseHeaderModifiers == nil { return http.ResponseHeaders{} @@ -912,7 +928,7 @@ func getRewriteClientIPSettings(rewriteIPConfig dataplane.RewriteClientIPSetting return shared.RewriteClientIPSettings{ RealIPHeader: string(rewriteIPConfig.Mode), - RealIPFrom: rewriteIPConfig.TrustedCIDRs, + RealIPFrom: rewriteIPConfig.TrustedAddresses, Recursive: rewriteIPConfig.IPRecursive, ProxyProtocol: proxyProtocol, } diff --git a/internal/mode/static/nginx/config/servers_template.go b/internal/mode/static/nginx/config/servers_template.go index 7437c62917..3c851457d2 100644 --- a/internal/mode/static/nginx/config/servers_template.go +++ b/internal/mode/static/nginx/config/servers_template.go @@ -13,7 +13,7 @@ server { listen [::]:{{ $s.Listen }} ssl default_server{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} ssl_reject_handshake on; - {{- range $cidr := $.RewriteClientIP.RealIPFrom }} + {{- range $cidr := $.RewriteClientIP.RealIPFrom }} set_real_ip_from {{ $cidr }}; {{- end}} {{- if $.RewriteClientIP.RealIPHeader}} @@ -77,7 +77,7 @@ server { include {{ $i.Name }}; {{- end }} - {{- range $cidr := $.RewriteClientIP.RealIPFrom }} + {{- range $cidr := $.RewriteClientIP.RealIPFrom }} set_real_ip_from {{ $cidr }}; {{- end}} {{- if $.RewriteClientIP.RealIPHeader}} diff --git a/internal/mode/static/nginx/config/servers_test.go b/internal/mode/static/nginx/config/servers_test.go index b969ce7141..1c21ec05d0 100644 --- a/internal/mode/static/nginx/config/servers_test.go +++ b/internal/mode/static/nginx/config/servers_test.go @@ -321,18 +321,15 @@ func TestExecuteServers_RewriteClientIP(t *testing.T) { BaseHTTPConfig: dataplane.BaseHTTPConfig{ IPFamily: dataplane.Dual, RewriteClientIPSettings: dataplane.RewriteClientIPSettings{ - Mode: dataplane.RewriteIPModeProxyProtocol, - TrustedCIDRs: []string{"0.0.0.0/0"}, - IPRecursive: true, + Mode: dataplane.RewriteIPModeProxyProtocol, + TrustedAddresses: []string{"10.56.73.51/32"}, + IPRecursive: false, }, }, }, expectedHTTPConfig: map[string]int{ - "set_real_ip_from 0.0.0.0/0;": 4, + "set_real_ip_from 10.56.73.51/32;": 4, "real_ip_header proxy_protocol;": 4, - "real_ip_recursive on;": 4, - "proxy_protocol on;": 0, - "set_real_ip_from unix:;": 0, "listen 8080 default_server proxy_protocol;": 1, "listen 8080 proxy_protocol;": 1, "listen 8443 ssl default_server proxy_protocol;": 1, @@ -355,17 +352,18 @@ func TestExecuteServers_RewriteClientIP(t *testing.T) { BaseHTTPConfig: dataplane.BaseHTTPConfig{ IPFamily: dataplane.Dual, RewriteClientIPSettings: dataplane.RewriteClientIPSettings{ - Mode: dataplane.RewriteIPModeXForwardedFor, - TrustedCIDRs: []string{"0.0.0.0/0"}, - IPRecursive: true, + Mode: dataplane.RewriteIPModeXForwardedFor, + TrustedAddresses: []string{"10.1.1.3/32", "2.2.2.2", "2001:db8::/32"}, + IPRecursive: true, }, }, }, expectedHTTPConfig: map[string]int{ - "set_real_ip_from 0.0.0.0/0;": 4, + "set_real_ip_from 10.1.1.3/32;": 4, + "set_real_ip_from 2.2.2.2;": 4, + "set_real_ip_from 2001:db8::/32;": 4, "real_ip_header X-Forwarded-For;": 4, "real_ip_recursive on;": 4, - "proxy_protocol on;": 0, "listen 8080 default_server;": 1, "listen 8080;": 1, "listen 8443 ssl default_server;": 1, @@ -2682,6 +2680,48 @@ func TestGenerateProxySetHeaders(t *testing.T) { }, }, }, + { + msg: "request redirect filter with https scheme", + filters: &dataplane.HTTPFilters{ + RequestRedirect: &dataplane.HTTPRequestRedirectFilter{ + Scheme: helpers.GetPointer("https"), + }, + }, + expectedHeaders: []http.Header{ + { + Name: "Host", + Value: "$gw_api_compliant_host", + }, + { + Name: "X-Forwarded-For", + Value: "$proxy_add_x_forwarded_for", + }, + { + Name: "Upgrade", + Value: "$http_upgrade", + }, + { + Name: "Connection", + Value: "$connection_upgrade", + }, + { + Name: "X-Real-IP", + Value: "$remote_addr", + }, + { + Name: "X-Forwarded-Proto", + Value: "https", + }, + { + Name: "X-Forwarded-Host", + Value: "$host", + }, + { + Name: "X-Forwarded-Port", + Value: "$server_port", + }, + }, + }, } for _, tc := range tests { diff --git a/internal/mode/static/nginx/config/stream_servers.go b/internal/mode/static/nginx/config/stream_servers.go index c6bad43002..4cef5de2f1 100644 --- a/internal/mode/static/nginx/config/stream_servers.go +++ b/internal/mode/static/nginx/config/stream_servers.go @@ -37,7 +37,6 @@ func createStreamServers(conf dataplane.Configuration) []stream.Server { } streamServers := make([]stream.Server, 0, len(conf.TLSPassthroughServers)*2) - var streamServer stream.Server portSet := make(map[int32]struct{}) upstreams := make(map[string]dataplane.Upstream) @@ -48,15 +47,15 @@ func createStreamServers(conf dataplane.Configuration) []stream.Server { for _, server := range conf.TLSPassthroughServers { if u, ok := upstreams[server.UpstreamName]; ok && server.UpstreamName != "" { if server.Hostname != "" && len(u.Endpoints) > 0 { - streamServer = stream.Server{ + streamServer := stream.Server{ Listen: getSocketNameTLS(server.Port, server.Hostname), StatusZone: server.Hostname, ProxyPass: server.UpstreamName, IsSocket: true, } + // set rewriteClientIP settings as this is a socket stream server streamServer.RewriteClientIP = getRewriteClientIPSettingsForStream( conf.BaseHTTPConfig.RewriteClientIPSettings, - streamServer.IsSocket, ) streamServers = append(streamServers, streamServer) } @@ -68,31 +67,25 @@ func createStreamServers(conf dataplane.Configuration) []stream.Server { portSet[server.Port] = struct{}{} - streamServer = stream.Server{ + streamServer := stream.Server{ Listen: fmt.Sprint(server.Port), StatusZone: server.Hostname, Pass: getTLSPassthroughVarName(server.Port), SSLPreread: true, } - streamServer.RewriteClientIP = getRewriteClientIPSettingsForStream( - conf.BaseHTTPConfig.RewriteClientIPSettings, - streamServer.IsSocket, - ) streamServers = append(streamServers, streamServer) } - return streamServers } func getRewriteClientIPSettingsForStream( rewriteConfig dataplane.RewriteClientIPSettings, - isSocket bool, ) shared.RewriteClientIPSettings { proxyEnabled := rewriteConfig.Mode == dataplane.RewriteIPModeProxyProtocol - if isSocket && proxyEnabled { + if proxyEnabled { return shared.RewriteClientIPSettings{ ProxyProtocol: shared.ProxyProtocolDirective, - RealIPFrom: rewriteConfig.TrustedCIDRs, + RealIPFrom: rewriteConfig.TrustedAddresses, } } diff --git a/internal/mode/static/nginx/config/stream_servers_template.go b/internal/mode/static/nginx/config/stream_servers_template.go index 2944a28837..0a84e02338 100644 --- a/internal/mode/static/nginx/config/stream_servers_template.go +++ b/internal/mode/static/nginx/config/stream_servers_template.go @@ -3,10 +3,8 @@ package config const streamServersTemplateText = ` {{- range $s := .Servers }} server { - {{- if and ($.IPFamily.IPv4) (not $s.IsSocket) }} - listen {{ $s.Listen }}; - {{- else if $s.IsSocket }} - listen {{ $s.Listen }}{{ $s.RewriteClientIP.ProxyProtocol }}; + {{- if or ($.IPFamily.IPv4) ($s.IsSocket) }} + listen {{ $s.Listen }}{{ $s.RewriteClientIP.ProxyProtocol }}; {{- end }} {{- if and ($.IPFamily.IPv6) (not $s.IsSocket) }} listen [::]:{{ $s.Listen }}; diff --git a/internal/mode/static/nginx/config/stream_servers_test.go b/internal/mode/static/nginx/config/stream_servers_test.go index 45bf3aa715..322e474e2f 100644 --- a/internal/mode/static/nginx/config/stream_servers_test.go +++ b/internal/mode/static/nginx/config/stream_servers_test.go @@ -337,9 +337,9 @@ func TestExecuteStreamServers_RewriteClientIP(t *testing.T) { config: dataplane.Configuration{ BaseHTTPConfig: dataplane.BaseHTTPConfig{ RewriteClientIPSettings: dataplane.RewriteClientIPSettings{ - Mode: dataplane.RewriteIPModeProxyProtocol, - TrustedCIDRs: []string{"1.1.1.1/32"}, - IPRecursive: true, + Mode: dataplane.RewriteIPModeProxyProtocol, + TrustedAddresses: []string{"10.1.1.22/32", "::1/128", "3.4.5.6"}, + IPRecursive: false, }, }, TLSPassthroughServers: passThroughServers, @@ -349,7 +349,9 @@ func TestExecuteStreamServers_RewriteClientIP(t *testing.T) { "listen 8443;": 1, "listen [::]:8443;": 1, "listen unix:/var/run/nginx/cafe.example.com-8443.sock proxy_protocol;": 1, - "set_real_ip_from 1.1.1.1/32;": 1, + "set_real_ip_from 10.1.1.22/32;": 1, + "set_real_ip_from ::1/128;": 1, + "set_real_ip_from 3.4.5.6;": 1, "real_ip_recursive on;": 0, }, }, @@ -358,9 +360,9 @@ func TestExecuteStreamServers_RewriteClientIP(t *testing.T) { config: dataplane.Configuration{ BaseHTTPConfig: dataplane.BaseHTTPConfig{ RewriteClientIPSettings: dataplane.RewriteClientIPSettings{ - Mode: dataplane.RewriteIPModeXForwardedFor, - TrustedCIDRs: []string{"1.1.1.1/32"}, - IPRecursive: true, + Mode: dataplane.RewriteIPModeXForwardedFor, + TrustedAddresses: []string{"1.1.1.1/32"}, + IPRecursive: true, }, }, TLSPassthroughServers: passThroughServers, @@ -369,10 +371,7 @@ func TestExecuteStreamServers_RewriteClientIP(t *testing.T) { expectedStreamConfig: map[string]int{ "listen 8443;": 1, "listen [::]:8443;": 1, - "listen unix:/var/run/nginx/cafe.example.com-8443.sock;": 1, - "set_real_ip_from 1.1.1.1/32;": 0, - "real_ip_recursive on;": 0, - "listen unix:/var/run/nginx/cafe.example.com-8443.sock proxy_protocol;": 0, + "listen unix:/var/run/nginx/cafe.example.com-8443.sock;": 1, }, }, } diff --git a/internal/mode/static/state/dataplane/configuration.go b/internal/mode/static/state/dataplane/configuration.go index 54e40232ee..44479f87dd 100644 --- a/internal/mode/static/state/dataplane/configuration.go +++ b/internal/mode/static/state/dataplane/configuration.go @@ -863,8 +863,8 @@ func buildBaseHTTPConfig(g *graph.Graph) BaseHTTPConfig { } if len(g.NginxProxy.Source.Spec.RewriteClientIP.TrustedAddresses) > 0 { - trustedAddresses := convertTrustedCIDRs(g) - baseConfig.RewriteClientIPSettings.TrustedCIDRs = trustedAddresses + trustedAddresses := convertTrustedAddresses(g) + baseConfig.RewriteClientIPSettings.TrustedAddresses = trustedAddresses } if g.NginxProxy.Source.Spec.RewriteClientIP.SetIPRecursively != nil { @@ -893,7 +893,7 @@ func buildPolicies(graphPolicies []*graph.Policy) []policies.Policy { return finalPolicies } -func convertTrustedCIDRs(g *graph.Graph) []string { +func convertTrustedAddresses(g *graph.Graph) []string { trustedAddresses := make([]string, len(g.NginxProxy.Source.Spec.RewriteClientIP.TrustedAddresses)) for i, addr := range g.NginxProxy.Source.Spec.RewriteClientIP.TrustedAddresses { trustedAddresses[i] = string(addr) diff --git a/internal/mode/static/state/dataplane/configuration_test.go b/internal/mode/static/state/dataplane/configuration_test.go index b5144b03d4..170e18eb9f 100644 --- a/internal/mode/static/state/dataplane/configuration_test.go +++ b/internal/mode/static/state/dataplane/configuration_test.go @@ -2213,9 +2213,9 @@ func TestBuildConfiguration(t *testing.T) { HTTP2: true, IPFamily: Dual, RewriteClientIPSettings: RewriteClientIPSettings{ - IPRecursive: true, - TrustedCIDRs: []string{"0.0.0.0/0"}, - Mode: RewriteIPModeProxyProtocol, + IPRecursive: true, + TrustedAddresses: []string{"0.0.0.0/0"}, + Mode: RewriteIPModeProxyProtocol, }, } return conf @@ -3628,9 +3628,9 @@ func TestBuildRewriteIPSettings(t *testing.T) { }, }, expRewriteIPSettings: RewriteClientIPSettings{ - Mode: RewriteIPModeProxyProtocol, - TrustedCIDRs: []string{"0.0.0.0/0"}, - IPRecursive: true, + Mode: RewriteIPModeProxyProtocol, + TrustedAddresses: []string{"0.0.0.0/0"}, + IPRecursive: true, }, }, { @@ -3650,9 +3650,9 @@ func TestBuildRewriteIPSettings(t *testing.T) { }, }, expRewriteIPSettings: RewriteClientIPSettings{ - Mode: RewriteIPModeXForwardedFor, - TrustedCIDRs: []string{"0.0.0.0/0"}, - IPRecursive: true, + Mode: RewriteIPModeXForwardedFor, + TrustedAddresses: []string{"0.0.0.0/0"}, + IPRecursive: true, }, }, { @@ -3672,9 +3672,9 @@ func TestBuildRewriteIPSettings(t *testing.T) { }, }, expRewriteIPSettings: RewriteClientIPSettings{ - Mode: RewriteIPModeXForwardedFor, - TrustedCIDRs: []string{"0.0.0.0/0", "1.1.1.1/32", "2.2.2.2/32", "3.3.3.3/24"}, - IPRecursive: false, + Mode: RewriteIPModeXForwardedFor, + TrustedAddresses: []string{"0.0.0.0/0", "1.1.1.1/32", "2.2.2.2/32", "3.3.3.3/24"}, + IPRecursive: false, }, }, } diff --git a/internal/mode/static/state/dataplane/types.go b/internal/mode/static/state/dataplane/types.go index 0ae4b3b2a2..2b18fc004b 100644 --- a/internal/mode/static/state/dataplane/types.go +++ b/internal/mode/static/state/dataplane/types.go @@ -320,7 +320,7 @@ type RewriteClientIPSettings struct { // Mode specifies the mode for rewriting the client IP. Mode RewriteIPModeType // TrustedCIDRs specifies the CIDRs that are trusted to provide the client IP. - TrustedCIDRs []string + TrustedAddresses []string // IPRecursive specifies whether a recursive search is used when selecting the client IP. IPRecursive bool } diff --git a/internal/mode/static/state/graph/nginxproxy.go b/internal/mode/static/state/graph/nginxproxy.go index 67b36c87a6..42993c1347 100644 --- a/internal/mode/static/state/graph/nginxproxy.go +++ b/internal/mode/static/state/graph/nginxproxy.go @@ -172,8 +172,17 @@ func validateRewriteClientIP(npCfg *ngfAPI.NginxProxy) field.ErrorList { } for _, addr := range rewriteClientIP.TrustedAddresses { - if err := k8svalidation.IsValidCIDR(trustedAddressesPath, string(addr)); err != nil { - allErrs = append(allErrs, field.Invalid(trustedAddressesPath.Child(string(addr)), addr, err.ToAggregate().Error())) + cidrError := k8svalidation.IsValidCIDR(trustedAddressesPath, string(addr)) + ipError := k8svalidation.IsValidIP(trustedAddressesPath, string(addr)) + + if cidrError != nil && ipError != nil { + allErrs = append( + allErrs, + field.Invalid(trustedAddressesPath.Child(string(addr)), + addr, + "must be a valid IP address or CIDR range", + ), + ) } } } diff --git a/internal/mode/static/state/graph/nginxproxy_test.go b/internal/mode/static/state/graph/nginxproxy_test.go index 816e21086c..2e01d27f4a 100644 --- a/internal/mode/static/state/graph/nginxproxy_test.go +++ b/internal/mode/static/state/graph/nginxproxy_test.go @@ -2,6 +2,7 @@ package graph import ( "errors" + "fmt" "testing" . "github.com/onsi/gomega" @@ -268,7 +269,7 @@ func TestValidateNginxProxy(t *testing.T) { IPFamily: helpers.GetPointer[ngfAPI.IPFamilyType](ngfAPI.Dual), RewriteClientIP: &ngfAPI.RewriteClientIP{ SetIPRecursively: helpers.GetPointer(true), - TrustedAddresses: []ngfAPI.TrustedAddress{"2001:db8:a0b:12f0::1/32", "0.0.0.0/0"}, + TrustedAddresses: []ngfAPI.TrustedAddress{"2001:db8:a0b:12f0::1/32", "1.1.1.1"}, Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol), }, }, @@ -377,7 +378,7 @@ func TestValidateRewriteClientIP(t *testing.T) { Spec: ngfAPI.NginxProxySpec{ RewriteClientIP: &ngfAPI.RewriteClientIP{ SetIPRecursively: helpers.GetPointer(true), - TrustedAddresses: []ngfAPI.TrustedAddress{"2001:db8:a0b:12f0::1/32", "0.0.0.0/0"}, + TrustedAddresses: []ngfAPI.TrustedAddress{"2001:db8:a0b:12f0::1/32", "10.56.32.11/32"}, Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol), }, }, @@ -391,15 +392,30 @@ func TestValidateRewriteClientIP(t *testing.T) { Spec: ngfAPI.NginxProxySpec{ RewriteClientIP: &ngfAPI.RewriteClientIP{ SetIPRecursively: helpers.GetPointer(true), - TrustedAddresses: []ngfAPI.TrustedAddress{"2001:db8:a0b:12f0::1"}, + TrustedAddresses: []ngfAPI.TrustedAddress{"2001:db8::/129", "10.0.0.1"}, + Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol), + }, + }, + }, + expectErrCount: 1, + errorString: "spec.rewriteClientIP.trustedAddresses.2001:db8::/129: " + + "Invalid value: \"2001:db8::/129\": must be a valid IP address or CIDR range", + }, + { + name: "invalid IP and CIDR in trustedAddresses", + validator: createInvalidValidator(), + np: &ngfAPI.NginxProxy{ + Spec: ngfAPI.NginxProxySpec{ + RewriteClientIP: &ngfAPI.RewriteClientIP{ + SetIPRecursively: helpers.GetPointer(true), + TrustedAddresses: []ngfAPI.TrustedAddress{"2001:db8::1/48", "256.100.50.25"}, Mode: helpers.GetPointer(ngfAPI.RewriteClientIPModeProxyProtocol), }, }, }, expectErrCount: 1, - errorString: "spec.rewriteClientIP.trustedAddresses.2001:db8:a0b:12f0::1: " + - "Invalid value: \"2001:db8:a0b:12f0::1\": spec.rewriteClientIP.trustedAddresses: " + - "Invalid value: \"2001:db8:a0b:12f0::1\": must be a valid CIDR value, (e.g. 10.9.8.0/24 or 2001:db8::/64)", + errorString: "spec.rewriteClientIP.trustedAddresses.256.100.50.25: " + + "Invalid value: \"256.100.50.25\": must be a valid IP address or CIDR range", }, { name: "invalid when mode is set and trustedAddresses is empty", @@ -474,6 +490,7 @@ func TestValidateRewriteClientIP(t *testing.T) { allErrs := validateRewriteClientIP(test.np) g.Expect(allErrs).To(HaveLen(test.expectErrCount)) if len(allErrs) > 0 { + fmt.Println(allErrs.ToAggregate().Error()) g.Expect(allErrs.ToAggregate().Error()).To(Equal(test.errorString)) } }) diff --git a/site/content/how-to/monitoring/troubleshooting.md b/site/content/how-to/monitoring/troubleshooting.md index 54da2f2128..1783832432 100644 --- a/site/content/how-to/monitoring/troubleshooting.md +++ b/site/content/how-to/monitoring/troubleshooting.md @@ -83,56 +83,56 @@ You can see logs for a crashed or killed container by adding the `-p` flag to th 1. Container Logs - To see logs for the control plane container: + To see logs for the control plane container: - ```shell - kubectl -n nginx-gateway logs -c nginx-gateway - ``` + ```shell + kubectl -n nginx-gateway logs -c nginx-gateway + ``` - To see logs for the data plane container: + To see logs for the data plane container: - ```shell - kubectl -n nginx-gateway logs -c nginx - ``` + ```shell + kubectl -n nginx-gateway logs -c nginx + ``` 1. Error Logs - For the _nginx-gateway_ container, you can `grep` the logs for the word `error`: + For the _nginx-gateway_ container, you can `grep` the logs for the word `error`: - ```shell - kubectl -n nginx-gateway logs -c nginx-gateway | grep error - ``` + ```shell + kubectl -n nginx-gateway logs -c nginx-gateway | grep error + ``` - For example, an error message when telemetry is not enabled for NGINX Plus installations: + For example, an error message when telemetry is not enabled for NGINX Plus installations: - ```text - kubectl logs -n nginx-gateway nginx-gateway-nginx-gateway-fabric-77f8746996-j6z6v | grep error - Defaulted container "nginx-gateway" out of: nginx-gateway, nginx - {"level":"error","ts":"2024-06-13T18:22:16Z","logger":"usageReporter","msg":"Usage reporting must be enabled when using NGINX Plus; redeploy with usage reporting enabled","error":"usage reporting not enabled","stacktrace":"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static.createUsageWarningJob.func1\n\tgithub.com/nginxinc/nginx-gateway-fabric/internal/mode/static/manager.go:616\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:259\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:226\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:227\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:204\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:259\ngithub.com/nginxinc/nginx-gateway-fabric/internal/framework/runnables.(*CronJob).Start\n\tgithub.com/nginxinc/nginx-gateway-fabric/internal/framework/runnables/cronjob.go:53\nsigs.k8s.io/controller-runtime/pkg/manager.(*runnableGroup).reconcile.func1\n\tsigs.k8s.io/controller-runtime@v0.18.4/pkg/manager/runnable_group.go:226"} - ``` + ```text + kubectl logs -n nginx-gateway nginx-gateway-nginx-gateway-fabric-77f8746996-j6z6v | grep error + Defaulted container "nginx-gateway" out of: nginx-gateway, nginx + {"level":"error","ts":"2024-06-13T18:22:16Z","logger":"usageReporter","msg":"Usage reporting must be enabled when using NGINX Plus; redeploy with usage reporting enabled","error":"usage reporting not enabled","stacktrace":"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static.createUsageWarningJob.func1\n\tgithub.com/nginxinc/nginx-gateway-fabric/internal/mode/static/manager.go:616\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext.func1\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:259\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:226\nk8s.io/apimachinery/pkg/util/wait.BackoffUntil\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:227\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:204\nk8s.io/apimachinery/pkg/util/wait.JitterUntilWithContext\n\tk8s.io/apimachinery@v0.30.1/pkg/util/wait/backoff.go:259\ngithub.com/nginxinc/nginx-gateway-fabric/internal/framework/runnables.(*CronJob).Start\n\tgithub.com/nginxinc/nginx-gateway-fabric/internal/framework/runnables/cronjob.go:53\nsigs.k8s.io/controller-runtime/pkg/manager.(*runnableGroup).reconcile.func1\n\tsigs.k8s.io/controller-runtime@v0.18.4/pkg/manager/runnable_group.go:226"} + ``` - For the _nginx_ container you can `grep` for various [error](https://nginx.org/en/docs/ngx_core_module.html#error_log) logs. For example, to search for all logs logged at the `emerg` level: + For the _nginx_ container you can `grep` for various [error](https://nginx.org/en/docs/ngx_core_module.html#error_log) logs. For example, to search for all logs logged at the `emerg` level: - ```shell - kubectl -n nginx-gateway logs -c nginx | grep emerg - ``` + ```shell + kubectl -n nginx-gateway logs -c nginx | grep emerg + ``` - For example, if a variable is too long, NGINX may display such an error message: + For example, if a variable is too long, NGINX may display such an error message: - ```text - kubectl logs -n nginx-gateway ngf-nginx-gateway-fabric-bb8598998-jwk2m -c nginx | grep emerg - 2024/06/13 20:04:17 [emerg] 27#27: too long parameter, probably missing terminating """ character in /etc/nginx/conf.d/http.conf:78 - ``` + ```text + kubectl logs -n nginx-gateway ngf-nginx-gateway-fabric-bb8598998-jwk2m -c nginx | grep emerg + 2024/06/13 20:04:17 [emerg] 27#27: too long parameter, probably missing terminating """ character in /etc/nginx/conf.d/http.conf:78 + ``` 1. Access Logs - NGINX access logs record all requests processed by the NGINX server. These logs provide detailed information about each request, which can be useful for troubleshooting and analyzing web traffic. - Access logs can be viewed with the above method of using `kubectl logs`, or by viewing the access log file directly. To do that, get shell access to your NGINX container using these [steps](#get-shell-access-to-nginx-container). The access logs are located in the file `/var/log/nginx/access.log` in the NGINX container. + NGINX access logs record all requests processed by the NGINX server. These logs provide detailed information about each request, which can be useful for troubleshooting and analyzing web traffic. + Access logs can be viewed with the above method of using `kubectl logs`, or by viewing the access log file directly. To do that, get shell access to your NGINX container using these [steps](#get-shell-access-to-nginx-container). The access logs are located in the file `/var/log/nginx/access.log` in the NGINX container. 1. Modify Log Levels - To modify log levels for the control plane in NGINX Gateway Fabric, edit the `NginxGateway` configuration. This can be done either before or after deploying NGINX Gateway Fabric. Refer to this [guide](https://docs.nginx.com/nginx-gateway-fabric/how-to/configuration/control-plane-configuration) to do so. - To check error logs, modify the log level to `error` to view error logs. Similarly, change the log level to `debug` and `grep` for the word `debug` to view debug logs. + To modify log levels for the control plane in NGINX Gateway Fabric, edit the `NginxGateway` configuration. This can be done either before or after deploying NGINX Gateway Fabric. Refer to this [guide](https://docs.nginx.com/nginx-gateway-fabric/how-to/configuration/control-plane-configuration) to do so. + To check error logs, modify the log level to `error` to view error logs. Similarly, change the log level to `debug` and `grep` for the word `debug` to view debug logs. #### Understanding the generated NGINX configuration @@ -167,18 +167,18 @@ metadata: name: coffee spec: parentRefs: - - name: gateway - sectionName: http + - name: gateway + sectionName: http hostnames: - - "cafe.example.com" + - "cafe.example.com" rules: - - matches: - - path: - type: PathPrefix - value: /coffee - backendRefs: - - name: coffee - port: 80 + - matches: + - path: + type: PathPrefix + value: /coffee + backendRefs: + - name: coffee + port: 80 ``` The modified `nginx.conf`: @@ -231,7 +231,7 @@ upstream default_coffee_80 { Key information to note is: 1. A new `server` block is created with the hostname of the HTTPRoute. When a request is sent to this hostname, it will be handled by this `server` block. -2. Within the `server` block, three new `location` blocks are added for *coffee*, each with distinct prefix and exact paths. Requests directed to the *coffee* application with a path prefix `/coffee/hello` will be managed by the first location block, while those with an exact path `/coffee` will be handled by the second location block. Any other requests not recognized by the server block for this hostname will default to the third location block, returning a 404 Not Found status. +2. Within the `server` block, three new `location` blocks are added for _coffee_, each with distinct prefix and exact paths. Requests directed to the _coffee_ application with a path prefix `/coffee/hello` will be managed by the first location block, while those with an exact path `/coffee` will be handled by the second location block. Any other requests not recognized by the server block for this hostname will default to the third location block, returning a 404 Not Found status. 3. Each `location` block has headers and directives that configure the NGINX proxy to forward requests to the `/coffee` path correctly, preserving important client information and ensuring compatibility with the upstream server. 4. The `upstream` block in the given NGINX configuration defines a group of backend servers and configures how NGINX should load balance requests among them. @@ -294,19 +294,19 @@ Verify that the port number (for example, `8080`) matches the port number you ha ### Common errors {{< bootstrap-table "table table-striped table-bordered" >}} -| Problem Area | Symptom | Troubleshooting Method | Common Cause | +| Problem Area | Symptom | Troubleshooting Method | Common Cause | |------------------------------|----------------------------------------|---------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| -| Startup | NGINX Gateway Fabric fails to start. | Check logs for _nginx_ and _nginx-gateway_ containers. | Readiness probe failed. | -| Resources not configured | Status missing on resources. | Check referenced resources. | Referenced resources do not belong to NGINX Gateway Fabric. | -| NGINX errors | Reload failures on NGINX | Fix permissions for control plane. | Security context not configured. | -| Usage reporting | Errors logs related to usage reporting | Enable usage reporting. Refer to [Usage Reporting]({{< relref "installation/usage-reporting.md" >}}) | Usage reporting disabled. | -| Client Settings | Request entity too large error | Adjust client settings. Refer to [Client Settings Policy]({{< relref "../traffic-management/client-settings.md" >}}) | Payload is greater than the [`client_max_body_size`](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) value.| +| Startup | NGINX Gateway Fabric fails to start. | Check logs for _nginx_ and _nginx-gateway_ containers. | Readiness probe failed. | +| Resources not configured | Status missing on resources. | Check referenced resources. | Referenced resources do not belong to NGINX Gateway Fabric. | +| NGINX errors | Reload failures on NGINX | Fix permissions for control plane. | Security context not configured. | +| Usage reporting | Errors logs related to usage reporting | Enable usage reporting. Refer to [Usage Reporting]({{< relref "installation/usage-reporting.md" >}}) | Usage reporting disabled. | +| Client Settings | Request entity too large error | Adjust client settings. Refer to [Client Settings Policy]({{< relref "../traffic-management/client-settings.md" >}}) | Payload is greater than the [`client_max_body_size`](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) value.| {{< /bootstrap-table >}} ##### NGINX fails to reload NGINX reload errors can occur for various reasons, including syntax errors in configuration files, permission issues, and more. To determine if NGINX has failed to reload, check logs for your _nginx-gateway_ and _nginx_ containers. -You will see the following error in the _nginx-gateway_ logs: `failed to reload NGINX:`, followed by the reason for the failure. Similarly, error logs in _nginx_ container start with `emerg`. For example, `2024/06/12 14:25:11 [emerg] 12345#0: open() "/var/run/nginx.pid" failed (13: Permission denied)` shows a critical error, such as a permission problem preventing NGINX from accessing necessary files. +You will see the following error in the _nginx-gateway_ logs: `failed to reload NGINX:`, followed by the reason for the failure. Similarly, error logs in _nginx_ container start with `emerg`. For example, `2024/06/12 14:25:11 [emerg] 12345#0: open() "/var/run/nginx.pid" failed (13: Permission denied)` shows a critical error, such as a permission problem preventing NGINX from accessing necessary files. To debug why your reload has failed, start with verifying the syntax of your configuration files by opening a shell in the NGINX container following these [steps](#get-shell-access-to-nginx-container) and running `nginx -T`. If there are errors in your configuration file, the reload will fail and specify the reason for it. @@ -459,13 +459,13 @@ This means you are attempting to attach a Policy to a Route that has an overlapp If you check your _nginx_ container logs and see the following error: - ```text - 2024/07/25 00:50:45 [error] 211#211: *22 broken header: "GET /coffee HTTP/1.1" while reading PROXY protocol, client: 127.0.0.1, server: 0.0.0.0:80 - ``` +```text + 2024/07/25 00:50:45 [error] 211#211: *22 broken header: "GET /coffee HTTP/1.1" while reading PROXY protocol, client: 127.0.0.1, server: 0.0.0.0:80 +``` It indicates that `proxy_protocol` is enabled for the gateway listeners, but the request sent to the application endpoint does not contain proxy information. To **resolve** this, you can do one of the following: -- Update field [`rewriteClientIP.mode`](({{< relref "reference/api.md" >}})) to `ProxyProtocol` in the NginxProxy configuration. +- Disable field [`rewriteClientIP.mode`](({{< relref "reference/api.md" >}})) in the NginxProxy configuration. - Send valid proxy information with requests being handled by your application. diff --git a/site/content/reference/api.md b/site/content/reference/api.md index e8e546ef5f..53a27d1926 100644 --- a/site/content/reference/api.md +++ b/site/content/reference/api.md @@ -3,11 +3,8 @@ title: "API reference" weight: 100 toc: false --- - ## Overview - NGINX Gateway API Reference -

Packages:

  • @@ -1089,12 +1086,12 @@ bool (Optional) -

    SetIPRecursively configures whether recursive search is used when selecting the client’s address from. +

    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.10, NGINX will rewrite the client IP to 22.22.22.22. +and TrustedAddresses is set to 55.55.55.1, 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

    @@ -1115,7 +1112,7 @@ Sets NGINX directive real_ip_recursive: https://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from @@ -1502,8 +1499,8 @@ Examples of invalid names: some-$value, quoted-“value”-name, unescap RewriteClientIP)

    -

    TrustedAddress is a string value representing a CIDR block. -Examples: 0.0.0.0/0

    +

    TrustedAddress is a string value representing a CIDR block or an IP address. +Examples: 10.0.0.232, 10.0.0.1, fe80::1128, ::124.