diff --git a/nginx-controller/controller/controller.go b/nginx-controller/controller/controller.go index 266dc1e74d..5405e15e4d 100644 --- a/nginx-controller/controller/controller.go +++ b/nginx-controller/controller/controller.go @@ -364,6 +364,33 @@ func (lbc *LoadBalancerController) syncCfgm(key string) { } } + if proxyProtocol, exists, err := nginx.GetMapKeyAsBool(cfgm.Data, "proxy-protocol", cfgm); exists { + if err != nil { + glog.Error(err) + } else { + cfg.ProxyProtocol = proxyProtocol + } + } + + // ngx_http_realip_module + if realIPHeader, exists := cfgm.Data["real-ip-header"]; exists { + cfg.RealIPHeader = realIPHeader + } + if setRealIPFrom, exists, err := nginx.GetMapKeyAsStringSlice(cfgm.Data, "set-real-ip-from", cfgm); exists { + if err != nil { + glog.Error(err) + } else { + cfg.SetRealIPFrom = setRealIPFrom + } + } + if realIPRecursive, exists, err := nginx.GetMapKeyAsBool(cfgm.Data, "real-ip-recursive", cfgm); exists { + if err != nil { + glog.Error(err) + } else { + cfg.RealIPRecursive = realIPRecursive + } + } + if logFormat, exists := cfgm.Data["log-format"]; exists { cfg.MainLogFormat = logFormat } diff --git a/nginx-controller/nginx/config.go b/nginx-controller/nginx/config.go index 90837ec919..25e2c31adf 100644 --- a/nginx-controller/nginx/config.go +++ b/nginx-controller/nginx/config.go @@ -13,9 +13,15 @@ type Config struct { ProxyBuffers string ProxyBufferSize string ProxyMaxTempFileSize string + ProxyProtocol bool HSTS bool HSTSMaxAge int64 HSTSIncludeSubdomains bool + + // http://nginx.org/en/docs/http/ngx_http_realip_module.html + RealIPHeader string + SetRealIPFrom []string + RealIPRecursive bool } // NewDefaultConfig creates a Config with default values diff --git a/nginx-controller/nginx/configurator.go b/nginx-controller/nginx/configurator.go index 3ca905853f..e88dd15080 100644 --- a/nginx-controller/nginx/configurator.go +++ b/nginx-controller/nginx/configurator.go @@ -105,9 +105,13 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri server := Server{ Name: serverName, HTTP2: ingCfg.HTTP2, + ProxyProtocol: ingCfg.ProxyProtocol, HSTS: ingCfg.HSTS, HSTSMaxAge: ingCfg.HSTSMaxAge, HSTSIncludeSubdomains: ingCfg.HSTSIncludeSubdomains, + RealIPHeader: ingCfg.RealIPHeader, + SetRealIPFrom: ingCfg.SetRealIPFrom, + RealIPRecursive: ingCfg.RealIPRecursive, } if pemFile, ok := pems[serverName]; ok { @@ -149,9 +153,13 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri server := Server{ Name: emptyHost, HTTP2: ingCfg.HTTP2, + ProxyProtocol: ingCfg.ProxyProtocol, HSTS: ingCfg.HSTS, HSTSMaxAge: ingCfg.HSTSMaxAge, HSTSIncludeSubdomains: ingCfg.HSTSIncludeSubdomains, + RealIPHeader: ingCfg.RealIPHeader, + SetRealIPFrom: ingCfg.SetRealIPFrom, + RealIPRecursive: ingCfg.RealIPRecursive, } if pemFile, ok := pems[emptyHost]; ok { diff --git a/nginx-controller/nginx/convert.go b/nginx-controller/nginx/convert.go index c5033b7c81..adbede444e 100644 --- a/nginx-controller/nginx/convert.go +++ b/nginx-controller/nginx/convert.go @@ -3,6 +3,7 @@ package nginx import ( "fmt" "strconv" + "strings" "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/runtime" @@ -38,3 +39,12 @@ func GetMapKeyAsInt(m map[string]string, key string, context apiObject) (int64, } return 0, false, nil } + +// GetMapKeyAsStringSlice tries to find and parse a key in the map as string slice splitting it on ',' +func GetMapKeyAsStringSlice(m map[string]string, key string, context apiObject) ([]string, bool, error) { + if str, exists := m[key]; exists { + slice := strings.Split(str, ",") + return slice, exists, nil + } + return nil, false, nil +} diff --git a/nginx-controller/nginx/convert_test.go b/nginx-controller/nginx/convert_test.go index d37ce72554..01719efb20 100644 --- a/nginx-controller/nginx/convert_test.go +++ b/nginx-controller/nginx/convert_test.go @@ -1,6 +1,7 @@ package nginx import ( + "reflect" "testing" "k8s.io/kubernetes/pkg/api" @@ -153,3 +154,36 @@ func TestGetMapKeyAsIntErrorMessage(t *testing.T) { t.Errorf("The error message does not match expectations:\nGot: %v\nExpected: %v", err, expected) } } + +// +// GetMapKeyAsStringSlice +// +func TestGetMapKeyAsStringSlice(t *testing.T) { + configMap := configMap + configMap.Data = map[string]string{ + "key": "1.String,2.String,3.String", + } + + slice, exists, err := GetMapKeyAsStringSlice(configMap.Data, "key", &configMap) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if !exists { + t.Errorf("The key 'key' must exist in the configMap") + } + expected := []string{"1.String", "2.String", "3.String"} + t.Log(expected) + if !reflect.DeepEqual(expected, slice) { + t.Errorf("Unexpected return value:\nGot: %#v\nExpected: %#v", slice, expected) + } +} + +func TestGetMapKeyAsStringSliceNotFound(t *testing.T) { + configMap := configMap + configMap.Data = map[string]string{} + + _, exists, _ := GetMapKeyAsStringSlice(configMap.Data, "key", &configMap) + if exists { + t.Errorf("The key 'key' must not exist in the configMap") + } +} diff --git a/nginx-controller/nginx/ingress.tmpl b/nginx-controller/nginx/ingress.tmpl index 78c2278561..d32ac2f1fd 100644 --- a/nginx-controller/nginx/ingress.tmpl +++ b/nginx-controller/nginx/ingress.tmpl @@ -6,12 +6,16 @@ upstream {{$upstream.Name}} { {{range $server := .Servers}} server { - listen 80; + listen 80{{if $server.ProxyProtocol}} proxy_protocol{{end}}; {{if $server.SSL}} - listen 443 ssl{{if $server.HTTP2}} http2{{end}}; + listen 443 ssl{{if $server.HTTP2}} http2{{end}}{{if $server.ProxyProtocol}} proxy_protocol{{end}}; ssl_certificate {{$server.SSLCertificate}}; ssl_certificate_key {{$server.SSLCertificateKey}}; {{end}} + {{range $setRealIPFrom := $server.SetRealIPFrom}} + set_real_ip_from {{$setRealIPFrom}};{{end}} + {{if $server.RealIPHeader}}real_ip_header {{$server.RealIPHeader}};{{end}} + {{if $server.RealIPRecursive}}real_ip_recursive on;{{end}} {{if $server.Name}} server_name {{$server.Name}}; diff --git a/nginx-controller/nginx/nginx.go b/nginx-controller/nginx/nginx.go index 2d2fb17050..909e0a1dc6 100644 --- a/nginx-controller/nginx/nginx.go +++ b/nginx-controller/nginx/nginx.go @@ -44,9 +44,15 @@ type Server struct { SSLCertificate string SSLCertificateKey string HTTP2 bool + ProxyProtocol bool HSTS bool HSTSMaxAge int64 HSTSIncludeSubdomains bool + + // http://nginx.org/en/docs/http/ngx_http_realip_module.html + RealIPHeader string + SetRealIPFrom []string + RealIPRecursive bool } // Location describes an NGINX location