diff --git a/apis/v1alpha1/nginxproxy_types.go b/apis/v1alpha1/nginxproxy_types.go index a05a73d32f..867e8113dd 100644 --- a/apis/v1alpha1/nginxproxy_types.go +++ b/apis/v1alpha1/nginxproxy_types.go @@ -167,7 +167,7 @@ type RewriteClientIP struct { type RewriteClientIPModeType string const ( - // RewriteClientIPModeProxyProtocol configures NGINX to accept PROXY protocol and, + // 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 to the listen directive on all servers, and sets real_ip_header // to proxy_protocol: https://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header. diff --git a/charts/nginx-gateway-fabric/values.yaml b/charts/nginx-gateway-fabric/values.yaml index 9c14104dd3..758b12fc35 100644 --- a/charts/nginx-gateway-fabric/values.yaml +++ b/charts/nginx-gateway-fabric/values.yaml @@ -94,7 +94,7 @@ nginx: # disableHTTP2: false # ipFamily: dual # rewriteClientIP: - # mode: "ProxyProtocol" + # mode: "XForwadedFor" # # -- The trusted addresses field needs to be replaced with the load balancer's IP address. # trustedAddresses: [] # setIPRecursively: true diff --git a/internal/mode/static/nginx/config/servers.go b/internal/mode/static/nginx/config/servers.go index 1d19ddae97..92a3dcb015 100644 --- a/internal/mode/static/nginx/config/servers.go +++ b/internal/mode/static/nginx/config/servers.go @@ -98,7 +98,7 @@ func (g GeneratorImpl) newExecuteServersFunc(generator policies.Generator) execu } func (g GeneratorImpl) executeServers(conf dataplane.Configuration, generator policies.Generator) []executeResult { - servers, httpMatchPairs := createServers(conf.HTTPServers, conf.SSLServers, conf.TLSPassthroughServers, generator) + servers, httpMatchPairs := createServers(conf, generator) serverConfig := http.ServerConfig{ Servers: servers, @@ -172,28 +172,23 @@ func createIncludeFileResults(servers []http.Server) []executeResult { return results } -func createServers( - httpServers, - sslServers []dataplane.VirtualServer, - tlsPassthroughServers []dataplane.Layer4VirtualServer, - generator policies.Generator, -) ([]http.Server, httpMatchPairs) { - servers := make([]http.Server, 0, len(httpServers)+len(sslServers)) +func createServers(conf dataplane.Configuration, generator policies.Generator) ([]http.Server, httpMatchPairs) { + servers := make([]http.Server, 0, len(conf.HTTPServers)+len(conf.SSLServers)) finalMatchPairs := make(httpMatchPairs) sharedTLSPorts := make(map[int32]struct{}) - for _, passthroughServer := range tlsPassthroughServers { + for _, passthroughServer := range conf.TLSPassthroughServers { sharedTLSPorts[passthroughServer.Port] = struct{}{} } - for idx, s := range httpServers { + for idx, s := range conf.HTTPServers { serverID := fmt.Sprintf("%d", idx) httpServer, matchPairs := createServer(s, serverID, generator) servers = append(servers, httpServer) maps.Copy(finalMatchPairs, matchPairs) } - for idx, s := range sslServers { + for idx, s := range conf.SSLServers { serverID := fmt.Sprintf("SSL_%d", idx) sslServer, matchPairs := createSSLServer(s, serverID, generator) @@ -909,11 +904,16 @@ func isNonSlashedPrefixPath(pathType dataplane.PathType, path string) bool { } // getRewriteClientIPSettings returns the configuration for the rewriting client IP settings. -func getRewriteClientIPSettings(rewriteIP dataplane.RewriteClientIPSettings) shared.RewriteClientIPSettings { +func getRewriteClientIPSettings(rewriteIPConfig dataplane.RewriteClientIPSettings) shared.RewriteClientIPSettings { + var proxyProtocol string + if rewriteIPConfig.Mode == dataplane.RewriteIPModeProxyProtocol { + proxyProtocol = shared.ProxyProtocolDirective + } + return shared.RewriteClientIPSettings{ - Recursive: rewriteIP.IPRecursive, - ProxyProtocol: rewriteIP.Mode == dataplane.RewriteIPModeProxyProtocol, - RealIPFrom: rewriteIP.TrustedCIDRs, - RealIPHeader: string(rewriteIP.Mode), + RealIPHeader: string(rewriteIPConfig.Mode), + RealIPFrom: rewriteIPConfig.TrustedCIDRs, + 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 7a6dded313..7437c62917 100644 --- a/internal/mode/static/nginx/config/servers_template.go +++ b/internal/mode/static/nginx/config/servers_template.go @@ -2,54 +2,44 @@ package config const serversTemplateText = ` js_preload_object matches from /etc/nginx/conf.d/matches.json; -{{ $proxyProtocol := "" }} -{{ if $.RewriteClientIP.ProxyProtocol }}{{ $proxyProtocol = " proxy_protocol" }}{{ end }} {{- range $s := .Servers -}} {{ if $s.IsDefaultSSL -}} server { {{- if or ($.IPFamily.IPv4) ($s.IsSocket) }} - listen {{ $s.Listen }} ssl default_server{{ $proxyProtocol }}; + listen {{ $s.Listen }} ssl default_server{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} {{- if and ($.IPFamily.IPv6) (not $s.IsSocket) }} - listen [::]:{{ $s.Listen }} ssl default_server{{ $proxyProtocol }}; + listen [::]:{{ $s.Listen }} ssl default_server{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} ssl_reject_handshake on; - {{- if and ($.RewriteClientIP.ProxyProtocol) ($s.IsSocket)}} - set_real_ip_from unix:; - {{- else if (not $s.IsSocket)}} - {{- range $cidr := $.RewriteClientIP.RealIPFrom }} + {{- range $cidr := $.RewriteClientIP.RealIPFrom }} set_real_ip_from {{ $cidr }}; - {{- end}} - {{ end }} - {{- if and ($.RewriteClientIP.RealIPHeader) (not $s.IsSocket)}} + {{- end}} + {{- if $.RewriteClientIP.RealIPHeader}} real_ip_header {{ $.RewriteClientIP.RealIPHeader }}; {{- end}} - {{- if and ($.RewriteClientIP.Recursive) (not $s.IsSocket)}} + {{- if $.RewriteClientIP.Recursive}} real_ip_recursive on; - {{ end }} + {{- end }} } {{- else if $s.IsDefaultHTTP }} server { {{- if $.IPFamily.IPv4 }} - listen {{ $s.Listen }} default_server{{ $proxyProtocol }}; + listen {{ $s.Listen }} default_server{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} {{- if $.IPFamily.IPv6 }} - listen [::]:{{ $s.Listen }} default_server{{ $proxyProtocol }}; + listen [::]:{{ $s.Listen }} default_server{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} - {{- if and ($.RewriteClientIP.ProxyProtocol) ($s.IsSocket)}} - set_real_ip_from unix:; - {{- else if (not $s.IsSocket)}} - {{- range $cidr := $.RewriteClientIP.RealIPFrom }} + {{- range $cidr := $.RewriteClientIP.RealIPFrom }} set_real_ip_from {{ $cidr }}; - {{- end}} - {{ end }} - {{- if and ($.RewriteClientIP.RealIPHeader) (not $s.IsSocket)}} + {{- end}} + {{- if $.RewriteClientIP.RealIPHeader}} real_ip_header {{ $.RewriteClientIP.RealIPHeader }}; {{- end}} - {{- if and ($.RewriteClientIP.Recursive) (not $s.IsSocket)}} + {{- if $.RewriteClientIP.Recursive}} real_ip_recursive on; - {{ end }} + {{- end }} default_type text/html; return 404; } @@ -57,10 +47,10 @@ server { server { {{- if $s.SSL }} {{- if or ($.IPFamily.IPv4) ($s.IsSocket) }} - listen {{ $s.Listen }} ssl{{ $proxyProtocol }}; + listen {{ $s.Listen }} ssl{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} {{- if and ($.IPFamily.IPv6) (not $s.IsSocket) }} - listen [::]:{{ $s.Listen }} ssl{{ $proxyProtocol }}; + listen [::]:{{ $s.Listen }} ssl{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} ssl_certificate {{ $s.SSL.Certificate }}; ssl_certificate_key {{ $s.SSL.CertificateKey }}; @@ -70,10 +60,10 @@ server { } {{- else }} {{- if $.IPFamily.IPv4 }} - listen {{ $s.Listen }}{{ $proxyProtocol }}; + listen {{ $s.Listen }}{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} {{- if $.IPFamily.IPv6 }} - listen [::]:{{ $s.Listen }}{{ $proxyProtocol }}; + listen [::]:{{ $s.Listen }}{{ $.RewriteClientIP.ProxyProtocol }}; {{- end }} {{- end }} @@ -87,19 +77,15 @@ server { include {{ $i.Name }}; {{- end }} - {{- if and ($.RewriteClientIP.ProxyProtocol) ($s.IsSocket)}} - set_real_ip_from unix:; - {{- else if (not $s.IsSocket)}} {{- range $cidr := $.RewriteClientIP.RealIPFrom }} set_real_ip_from {{ $cidr }}; {{- end}} - {{ end }} - {{- if and ($.RewriteClientIP.RealIPHeader) (not $s.IsSocket)}} + {{- if $.RewriteClientIP.RealIPHeader}} real_ip_header {{ $.RewriteClientIP.RealIPHeader }}; {{- end}} - {{- if and ($.RewriteClientIP.Recursive) (not $s.IsSocket)}} + {{- if $.RewriteClientIP.Recursive}} real_ip_recursive on; - {{ end }} + {{- end }} {{ range $l := $s.Locations }} location {{ $l.Path }} { diff --git a/internal/mode/static/nginx/config/servers_test.go b/internal/mode/static/nginx/config/servers_test.go index 5946106a56..b969ce7141 100644 --- a/internal/mode/static/nginx/config/servers_test.go +++ b/internal/mode/static/nginx/config/servers_test.go @@ -332,6 +332,7 @@ func TestExecuteServers_RewriteClientIP(t *testing.T) { "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, @@ -914,44 +915,44 @@ func TestCreateServers(t *testing.T) { }, } - httpServers := []dataplane.VirtualServer{ - { - IsDefault: true, - Port: 8080, - }, - { - Hostname: "cafe.example.com", - PathRules: cafePathRules, - Port: 8080, - Policies: []policies.Policy{ - &policiesfakes.FakePolicy{}, - &policiesfakes.FakePolicy{}, + conf := dataplane.Configuration{ + HTTPServers: []dataplane.VirtualServer{ + { + IsDefault: true, + Port: 8080, + }, + { + Hostname: "cafe.example.com", + PathRules: cafePathRules, + Port: 8080, + Policies: []policies.Policy{ + &policiesfakes.FakePolicy{}, + &policiesfakes.FakePolicy{}, + }, }, }, - } - - sslServers := []dataplane.VirtualServer{ - { - IsDefault: true, - Port: 8443, - }, - { - Hostname: "cafe.example.com", - SSL: &dataplane.SSL{KeyPairID: sslKeyPairID}, - PathRules: cafePathRules, - Port: 8443, - Policies: []policies.Policy{ - &policiesfakes.FakePolicy{}, - &policiesfakes.FakePolicy{}, + SSLServers: []dataplane.VirtualServer{ + { + IsDefault: true, + Port: 8443, + }, + { + Hostname: "cafe.example.com", + SSL: &dataplane.SSL{KeyPairID: sslKeyPairID}, + PathRules: cafePathRules, + Port: 8443, + Policies: []policies.Policy{ + &policiesfakes.FakePolicy{}, + &policiesfakes.FakePolicy{}, + }, }, }, - } - - tlsPassthroughServers := []dataplane.Layer4VirtualServer{ - { - Hostname: "app.example.com", - Port: 8443, - UpstreamName: "sup", + TLSPassthroughServers: []dataplane.Layer4VirtualServer{ + { + Hostname: "app.example.com", + Port: 8443, + UpstreamName: "sup", + }, }, } @@ -1481,7 +1482,7 @@ func TestCreateServers(t *testing.T) { }, }) - result, httpMatchPair := createServers(httpServers, sslServers, tlsPassthroughServers, fakeGenerator) + result, httpMatchPair := createServers(conf, fakeGenerator) g.Expect(httpMatchPair).To(Equal(allExpMatchPair)) g.Expect(helpers.Diff(expectedServers, result)).To(BeEmpty()) @@ -1696,12 +1697,7 @@ func TestCreateServersConflicts(t *testing.T) { g := NewWithT(t) - result, _ := createServers( - httpServers, - []dataplane.VirtualServer{}, - []dataplane.Layer4VirtualServer{}, - &policiesfakes.FakeGenerator{}, - ) + result, _ := createServers(dataplane.Configuration{HTTPServers: httpServers}, &policiesfakes.FakeGenerator{}) g.Expect(helpers.Diff(expectedServers, result)).To(BeEmpty()) }) } diff --git a/internal/mode/static/nginx/config/shared/config.go b/internal/mode/static/nginx/config/shared/config.go index eada321715..62ea4bec82 100644 --- a/internal/mode/static/nginx/config/shared/config.go +++ b/internal/mode/static/nginx/config/shared/config.go @@ -23,7 +23,11 @@ type IPFamily struct { // RewriteClientIP holds the configuration for the rewrite client IP settings. type RewriteClientIPSettings struct { RealIPHeader string + ProxyProtocol string RealIPFrom []string Recursive bool - ProxyProtocol bool } + +const ( + ProxyProtocolDirective = " proxy_protocol" +) diff --git a/internal/mode/static/nginx/config/stream/config.go b/internal/mode/static/nginx/config/stream/config.go index 0bbebadc20..ddc215eea7 100644 --- a/internal/mode/static/nginx/config/stream/config.go +++ b/internal/mode/static/nginx/config/stream/config.go @@ -4,12 +4,13 @@ import "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/conf // Server holds all configuration for a stream server. type Server struct { - Listen string - StatusZone string - ProxyPass string - Pass string - SSLPreread bool - IsSocket bool + Listen string + StatusZone string + ProxyPass string + Pass string + RewriteClientIP shared.RewriteClientIPSettings + SSLPreread bool + IsSocket bool } // Upstream holds all configuration for a stream upstream. @@ -26,8 +27,7 @@ type UpstreamServer struct { // ServerConfig holds configuration for a stream server and IP family to be used by NGINX. type ServerConfig struct { - Servers []Server - RewriteClientIP shared.RewriteClientIPSettings - IPFamily shared.IPFamily - Plus bool + Servers []Server + IPFamily shared.IPFamily + Plus bool } diff --git a/internal/mode/static/nginx/config/stream_servers.go b/internal/mode/static/nginx/config/stream_servers.go index 73d90a7de7..c6bad43002 100644 --- a/internal/mode/static/nginx/config/stream_servers.go +++ b/internal/mode/static/nginx/config/stream_servers.go @@ -5,6 +5,7 @@ import ( gotemplate "text/template" "github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers" + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config/shared" "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config/stream" "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/dataplane" ) @@ -15,10 +16,9 @@ func (g GeneratorImpl) executeStreamServers(conf dataplane.Configuration) []exec streamServers := createStreamServers(conf) streamServerConfig := stream.ServerConfig{ - Servers: streamServers, - IPFamily: getIPFamily(conf.BaseHTTPConfig), - Plus: g.plus, - RewriteClientIP: getRewriteClientIPSettings(conf.BaseHTTPConfig.RewriteClientIPSettings), + Servers: streamServers, + IPFamily: getIPFamily(conf.BaseHTTPConfig), + Plus: g.plus, } streamServerResult := executeResult{ @@ -37,6 +37,7 @@ 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) @@ -47,12 +48,17 @@ 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 { - streamServers = append(streamServers, stream.Server{ + streamServer = stream.Server{ Listen: getSocketNameTLS(server.Port, server.Hostname), StatusZone: server.Hostname, ProxyPass: server.UpstreamName, IsSocket: true, - }) + } + streamServer.RewriteClientIP = getRewriteClientIPSettingsForStream( + conf.BaseHTTPConfig.RewriteClientIPSettings, + streamServer.IsSocket, + ) + streamServers = append(streamServers, streamServer) } } @@ -61,13 +67,34 @@ func createStreamServers(conf dataplane.Configuration) []stream.Server { } portSet[server.Port] = struct{}{} - streamServers = append(streamServers, 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 { + return shared.RewriteClientIPSettings{ + ProxyProtocol: shared.ProxyProtocolDirective, + RealIPFrom: rewriteConfig.TrustedCIDRs, + } + } + + return shared.RewriteClientIPSettings{} +} diff --git a/internal/mode/static/nginx/config/stream_servers_template.go b/internal/mode/static/nginx/config/stream_servers_template.go index 2b98944df8..2944a28837 100644 --- a/internal/mode/static/nginx/config/stream_servers_template.go +++ b/internal/mode/static/nginx/config/stream_servers_template.go @@ -1,24 +1,20 @@ package config const streamServersTemplateText = ` -{{ $proxyProtocol := "" }} -{{ if $.RewriteClientIP.ProxyProtocol }}{{ $proxyProtocol = " proxy_protocol" }}{{ end }} {{- range $s := .Servers }} server { {{- if and ($.IPFamily.IPv4) (not $s.IsSocket) }} listen {{ $s.Listen }}; {{- else if $s.IsSocket }} - listen {{ $s.Listen }}{{ $proxyProtocol }}; + listen {{ $s.Listen }}{{ $s.RewriteClientIP.ProxyProtocol }}; {{- end }} {{- if and ($.IPFamily.IPv6) (not $s.IsSocket) }} listen [::]:{{ $s.Listen }}; {{- end }} - {{- if and ($s.IsSocket) ($.RewriteClientIP.ProxyProtocol) }} - {{- range $cidr := $.RewriteClientIP.RealIPFrom }} + {{- range $cidr := $s.RewriteClientIP.RealIPFrom }} set_real_ip_from {{ $cidr }}; - {{- end}} - {{- end }} + {{- end}} {{- if $.Plus }} status_zone {{ $s.StatusZone }}; {{- end }} diff --git a/internal/mode/static/nginx/config/stream_servers_test.go b/internal/mode/static/nginx/config/stream_servers_test.go index 9d7e0d9165..45bf3aa715 100644 --- a/internal/mode/static/nginx/config/stream_servers_test.go +++ b/internal/mode/static/nginx/config/stream_servers_test.go @@ -369,9 +369,10 @@ 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;": 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, }, }, } diff --git a/site/content/reference/api.md b/site/content/reference/api.md index 3518381a4a..e8e546ef5f 100644 --- a/site/content/reference/api.md +++ b/site/content/reference/api.md @@ -3,8 +3,11 @@ title: "API reference" weight: 100 toc: false --- + ## Overview + NGINX Gateway API Reference +

Packages: