From 2ed75b3362c64bcb29accf5a1da01029c6f306e3 Mon Sep 17 00:00:00 2001 From: Manuel Alejandro de Brito Fontes Date: Tue, 13 Aug 2019 14:04:31 -0400 Subject: [PATCH] Move listen logic to go --- .../ingress/controller/template/template.go | 168 +++++++++++++++++- rootfs/etc/nginx/template/nginx.tmpl | 49 +---- 2 files changed, 172 insertions(+), 45 deletions(-) diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index 214172ef16..fa09c9fd8c 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -37,13 +37,14 @@ import ( "github.com/pkg/errors" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog" + "k8s.io/ingress-nginx/internal/file" "k8s.io/ingress-nginx/internal/ingress" "k8s.io/ingress-nginx/internal/ingress/annotations/influxdb" "k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit" "k8s.io/ingress-nginx/internal/ingress/controller/config" ing_net "k8s.io/ingress-nginx/internal/net" - "k8s.io/klog" ) const ( @@ -178,6 +179,8 @@ var ( "opentracingPropagateContext": opentracingPropagateContext, "buildCustomErrorLocationsPerServer": buildCustomErrorLocationsPerServer, "shouldLoadModSecurityModule": shouldLoadModSecurityModule, + "buildHTTPListener": buildHTTPListener, + "buildHTTPSListener": buildHTTPSListener, } ) @@ -233,7 +236,6 @@ func shouldConfigureLuaRestyWAF(disableLuaRestyWAF bool, mode string) bool { } func buildLuaSharedDictionaries(c interface{}, s interface{}, disableLuaRestyWAF bool) string { - var out []string // Load config cfg, ok := c.(config.Configuration) @@ -344,7 +346,7 @@ func locationConfigForLua(l interface{}, s interface{}, a interface{}) string { return "{}" } - forceSSLRedirect := location.Rewrite.ForceSSLRedirect || (len(server.SSLCert.PemFileName) > 0 && location.Rewrite.SSLRedirect) + forceSSLRedirect := location.Rewrite.ForceSSLRedirect || len(server.SSLCert.PemFileName) > 0 && location.Rewrite.SSLRedirect forceSSLRedirect = forceSSLRedirect && !isLocationInLocationList(l, all.Cfg.NoTLSRedirectLocations) return fmt.Sprintf(`{ @@ -1121,3 +1123,163 @@ func shouldLoadModSecurityModule(c interface{}, s interface{}) bool { // Not enabled globally nor via annotation on a location, no need to load the module. return false } + +func buildHTTPListener(t interface{}, s interface{}) string { + var out []string + + tc, ok := t.(config.TemplateConfig) + if !ok { + klog.Errorf("expected a 'config.TemplateConfig' type but %T was returned", t) + return "" + } + + hostname, ok := s.(string) + if !ok { + klog.Errorf("expected a 'string' type but %T was returned", s) + return "" + } + + addrV4 := []string{""} + if len(tc.Cfg.BindAddressIpv4) > 0 { + addrV4 = tc.Cfg.BindAddressIpv4 + } + + co := commonListenOptions(tc, hostname) + + out = append(out, httpListener(addrV4, co, tc)...) + + if !tc.IsIPV6Enabled { + return strings.Join(out, "\n") + } + + addrV6 := []string{"[::]"} + if len(tc.Cfg.BindAddressIpv6) > 0 { + addrV6 = tc.Cfg.BindAddressIpv6 + } + + out = append(out, httpListener(addrV6, co, tc)...) + + return strings.Join(out, "\n") +} + +func buildHTTPSListener(t interface{}, s interface{}) string { + var out []string + + tc, ok := t.(config.TemplateConfig) + if !ok { + klog.Errorf("expected a 'config.TemplateConfig' type but %T was returned", t) + return "" + } + + hostname, ok := s.(string) + if !ok { + klog.Errorf("expected a 'string' type but %T was returned", s) + return "" + } + + co := commonListenOptions(tc, hostname) + + addrV4 := []string{""} + if len(tc.Cfg.BindAddressIpv4) > 0 { + addrV4 = tc.Cfg.BindAddressIpv4 + } + + out = append(out, httpsListener(addrV4, co, tc)...) + + if !tc.IsIPV6Enabled { + return strings.Join(out, "\n") + } + + addrV6 := []string{"[::]"} + if len(tc.Cfg.BindAddressIpv6) > 0 { + addrV6 = tc.Cfg.BindAddressIpv6 + } + + out = append(out, httpsListener(addrV6, co, tc)...) + + return strings.Join(out, "\n") +} + +func commonListenOptions(template config.TemplateConfig, hostname string) string { + var out []string + + if template.Cfg.UseProxyProtocol { + out = append(out, "proxy_protocol") + } + + if hostname != "_" { + return strings.Join(out, " ") + } + + // setup options that are valid only once per port + + out = append(out, "default_server") + + if template.Cfg.ReusePort { + out = append(out, "reuseport") + } + + out = append(out, fmt.Sprintf("backlog=%v", template.BacklogSize)) + + return strings.Join(out, " ") +} + +func httpListener(addresses []string, co string, tc config.TemplateConfig) []string { + out := make([]string, 0) + for _, address := range addresses { + l := make([]string, 0) + l = append(l, "listen") + + if address == "" { + l = append(l, fmt.Sprintf("%v", tc.ListenPorts.HTTP)) + } else { + l = append(l, fmt.Sprintf("%v:%v", address, tc.ListenPorts.HTTP)) + } + + l = append(l, co) + l = append(l, ";") + out = append(out, strings.Join(l, " ")) + } + + return out +} + +func httpsListener(addresses []string, co string, tc config.TemplateConfig) []string { + out := make([]string, 0) + for _, address := range addresses { + l := make([]string, 0) + l = append(l, "listen") + + if tc.IsSSLPassthroughEnabled { + if address == "" { + l = append(l, fmt.Sprintf("%v", tc.ListenPorts.SSLProxy)) + } else { + l = append(l, fmt.Sprintf("%v:%v", address, tc.ListenPorts.SSLProxy)) + } + + l = append(l, "proxy_protocol") + } else { + if address == "" { + l = append(l, fmt.Sprintf("%v", tc.ListenPorts.HTTPS)) + } else { + l = append(l, fmt.Sprintf("%v:%v", address, tc.ListenPorts.HTTPS)) + } + + if tc.Cfg.UseProxyProtocol { + l = append(l, "proxy_protocol") + } + } + + l = append(l, co) + l = append(l, "ssl") + + if tc.Cfg.UseHTTP2 { + l = append(l, "http2") + } + + l = append(l, ";") + out = append(out, strings.Join(l, " ")) + } + + return out +} diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 850f7f6638..252db4cd61 100755 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -469,24 +469,11 @@ http { {{ range $redirect := .RedirectServers }} ## start server {{ $redirect.From }} server { - {{ range $address := $all.Cfg.BindAddressIpv4 }} - listen {{ $address }}:{{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}; - listen {{ $address }}:{{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol{{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }} ssl; - {{ else }} - listen {{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}; - listen {{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol{{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }} ssl; - {{ end }} - {{ if $IsIPV6Enabled }} - {{ range $address := $all.Cfg.BindAddressIpv6 }} - listen {{ $address }}:{{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}; - listen {{ $address }}:{{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol{{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }}; - {{ else }} - listen [::]:{{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}; - listen [::]:{{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol{{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }}; - {{ end }} - {{ end }} server_name {{ $redirect.From }}; + {{ buildHTTPListener $all $redirect.From }} + {{ buildHTTPSListener $all $redirect.From }} + {{ if not (empty $redirect.SSLCert.PemFileName) }} {{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}} # PEM sha: {{ $redirect.SSLCert.PemSHA }} @@ -801,35 +788,13 @@ stream { {{ define "SERVER" }} {{ $all := .First }} {{ $server := .Second }} - {{ range $address := $all.Cfg.BindAddressIpv4 }} - listen {{ $address }}:{{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{end}}; - {{ else }} - listen {{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{end}}; - {{ end }} - {{ if $all.IsIPV6Enabled }} - {{ range $address := $all.Cfg.BindAddressIpv6 }} - listen {{ $address }}:{{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{ end }}; - {{ else }} - listen [::]:{{ $all.ListenPorts.HTTP }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{ end }}; - {{ end }} - {{ end }} + + {{ buildHTTPListener $all $server.Hostname }} + {{ buildHTTPSListener $all $server.Hostname }} + set $proxy_upstream_name "-"; - {{/* Listen on {{ $all.ListenPorts.SSLProxy }} because port {{ $all.ListenPorts.HTTPS }} is used in the TLS sni server */}} - {{/* This listener must always have proxy_protocol enabled, because the SNI listener forwards on source IP info in it. */}} {{ if not (empty $server.SSLCert.PemFileName) }} - {{ range $address := $all.Cfg.BindAddressIpv4 }} - listen {{ $address }}:{{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol {{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }} {{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }}; - {{ else }} - listen {{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol {{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }} {{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }}; - {{ end }} - {{ if $all.IsIPV6Enabled }} - {{ range $address := $all.Cfg.BindAddressIpv6 }} - {{ if not (empty $server.SSLCert.PemFileName) }}listen {{ $address }}:{{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol{{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }}{{ end }} {{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }}; - {{ else }} - {{ if not (empty $server.SSLCert.PemFileName) }}listen [::]:{{ if $all.IsSSLPassthroughEnabled }}{{ $all.ListenPorts.SSLProxy }} proxy_protocol{{ else }}{{ $all.ListenPorts.HTTPS }}{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }}{{ end }} {{ if eq $server.Hostname "_"}} default_server {{ if $all.Cfg.ReusePort }}reuseport{{ end }} backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }}; - {{ end }} - {{ end }} {{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}} # PEM sha: {{ $server.SSLCert.PemSHA }} ssl_certificate {{ $server.SSLCert.PemFileName }};