From a85cfd10b53868b35f9aa59737117b3c9d2f75fc Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Fri, 25 Aug 2017 20:49:44 -0300 Subject: [PATCH] Add additional headers when custom default backend is used --- controllers/nginx/pkg/template/template.go | 51 ++++++++++++ .../rootfs/etc/nginx/template/nginx.tmpl | 77 +++++++++++++++---- .../annotations/defaultbackend/main.go | 2 +- core/pkg/ingress/controller/controller.go | 4 +- 4 files changed, 115 insertions(+), 19 deletions(-) diff --git a/controllers/nginx/pkg/template/template.go b/controllers/nginx/pkg/template/template.go index cb7d64cfa..327c430f4 100644 --- a/controllers/nginx/pkg/template/template.go +++ b/controllers/nginx/pkg/template/template.go @@ -32,6 +32,7 @@ import ( "github.com/golang/glog" "github.com/pborman/uuid" + extensions "k8s.io/api/extensions/v1beta1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/ingress/controllers/nginx/pkg/config" "k8s.io/ingress/core/pkg/ingress" @@ -150,6 +151,7 @@ var ( "toLower": strings.ToLower, "formatIP": formatIP, "buildNextUpstream": buildNextUpstream, + "getIngressInformation": getIngressInformation, "serverConfig": func(all config.TemplateConfig, server *ingress.Server) interface{} { return struct{ First, Second interface{} }{all, server} }, @@ -588,3 +590,52 @@ func isValidClientBodyBufferSize(input interface{}) bool { return true } + +type ingressInformation struct { + Namespace string + Rule string + Service string +} + +func getIngressInformation(i, p interface{}) *ingressInformation { + ing, ok := i.(*extensions.Ingress) + if !ok { + glog.Errorf("expected an Ingress type but %T was returned", i) + return &ingressInformation{} + } + + path, ok := p.(string) + if !ok { + glog.Errorf("expected a string type but %T was returned", p) + return &ingressInformation{} + } + + if ing == nil { + glog.Errorf("expected an Ingress") + return &ingressInformation{} + } + + info := &ingressInformation{ + Namespace: ing.GetNamespace(), + Rule: ing.GetName(), + } + + if ing.Spec.Backend != nil { + info.Service = ing.Spec.Backend.ServiceName + } + + for _, rule := range ing.Spec.Rules { + if rule.HTTP == nil { + continue + } + + for _, rPath := range rule.HTTP.Paths { + if path == rPath.Path { + info.Service = rPath.Backend.ServiceName + return info + } + } + } + + return info +} diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index af93fac3a..607217e64 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -105,6 +105,10 @@ http { # disable warnings uninitialized_variable_warn off; + # Additional available variables: + # $namespace + # $ingress_name + # $service_name log_format upstreaminfo {{ if $cfg.LogFormatEscapeJSON }}escape=json {{ end }}'{{ buildLogFormatUpstream $cfg }}'; {{/* map urls that should not appear in access.log */}} @@ -258,6 +262,7 @@ http { {{ range $server := $upstream.Endpoints }}server {{ $server.Address | formatIP }}:{{ $server.Port }} max_fails={{ $server.MaxFails }} fail_timeout={{ $server.FailTimeout }}; {{ end }} } + {{ end }} upstream {{ $upstream.Name }} { @@ -273,6 +278,7 @@ http { {{ range $server := $upstream.Endpoints }}server {{ $server.Address | formatIP }}:{{ $server.Port }} max_fails={{ $server.MaxFails }} fail_timeout={{ $server.FailTimeout }}; {{ end }} } + {{ end }} {{/* build the maps that will be use to validate the Whitelist */}} @@ -344,12 +350,32 @@ http { server { server_name {{ $server.Hostname }}; {{ template "SERVER" serverConfig $all $server }} + + + fastcgi_param HTTP_X_Code 503; + fastcgi_param HTTP_X_Format $http_accept; + fastcgi_param HTTP_X_Original_URI $request_uri; + fastcgi_param HTTP_X_Namespace $namespace; + fastcgi_param HTTP_X_Ingress_Name $ingress_name; + fastcgi_param HTTP_X_Service_Name $service_name; + fastcgi_param HTTP_X_Endpoints {{ $all.DefaultBackendEndpoints }}; + {{ template "CUSTOM_ERRORS" $all }} } {{ if $server.Alias }} server { server_name {{ $server.Alias }}; {{ template "SERVER" serverConfig $all $server }} + + + fastcgi_param HTTP_X_Code 503; + fastcgi_param HTTP_X_Format $http_accept; + fastcgi_param HTTP_X_Original_URI $request_uri; + fastcgi_param HTTP_X_Namespace $namespace; + fastcgi_param HTTP_X_Ingress_Name $ingress_name; + fastcgi_param HTTP_X_Service_Name $service_name; + fastcgi_param HTTP_X_Endpoints {{ $all.DefaultBackendEndpoints }}; + {{ template "CUSTOM_ERRORS" $all }} } {{ end }} @@ -395,30 +421,34 @@ http { stub_status on; } - location / { - set $proxy_upstream_name "upstream-default-backend"; - proxy_pass http://upstream-default-backend; - } - {{ template "CUSTOM_ERRORS" $all }} - } - # default server for services without endpoints - server { - listen 127.0.0.1:{{ $all.ListenPorts.Default }}; - set $proxy_upstream_name "-"; + fastcgi_param HTTP_X_Code 404; + fastcgi_param HTTP_X_Format $http_accept; + fastcgi_param HTTP_X_Original_URI $request_uri; + fastcgi_param HTTP_X_Namespace $namespace; + fastcgi_param HTTP_X_Ingress_Name $ingress_name; + fastcgi_param HTTP_X_Service_Name $service_name; + fastcgi_param HTTP_X_Endpoints {{ $all.DefaultBackendEndpoints }}; location / { {{ if .CustomErrors }} include /etc/nginx/fastcgi_params; - fastcgi_param HTTP_X_Code 404; - fastcgi_param HTTP_X_Format $http_accept; - fastcgi_param HTTP_X_Endpoints {{ .DefaultBackendEndpoints }}; fastcgi_pass unix:/var/run/go-fastcgi.sock; {{ else }} set $proxy_upstream_name "upstream-default-backend"; proxy_pass http://upstream-default-backend; {{ end }} } + + fastcgi_param HTTP_X_Code 404; + fastcgi_param HTTP_X_Format $http_accept; + fastcgi_param HTTP_X_Original_URI $request_uri; + fastcgi_param HTTP_X_Namespace $namespace; + fastcgi_param HTTP_X_Ingress_Name $ingress_name; + fastcgi_param HTTP_X_Service_Name $service_name; + fastcgi_param HTTP_X_Endpoints {{ $all.DefaultBackendEndpoints }}; + + {{ template "CUSTOM_ERRORS" $all }} } } @@ -484,6 +514,7 @@ stream { proxy_timeout {{ $cfg.ProxyStreamTimeout }}; proxy_pass udp-{{ $udpServer.Port }}-{{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }}; } + {{ end }} } @@ -494,9 +525,6 @@ stream { location @custom_{{ $errCode }} { internal; include /etc/nginx/fastcgi_params; - fastcgi_param HTTP_X_Code {{ $errCode }}; - fastcgi_param HTTP_X_Format $http_accept; - fastcgi_param HTTP_X_Endpoints {{ $defaultBackendEndpoints }}; fastcgi_pass unix:/var/run/go-fastcgi.sock; } {{ end }} @@ -633,11 +661,17 @@ stream { set $target {{ $location.ExternalAuth.URL }}; proxy_pass $target; } + {{ end }} location {{ $path }} { set $proxy_upstream_name "{{ buildUpstreamName $server.Hostname $all.Backends $location }}"; + {{ $ing := (getIngressInformation $location.Ingress $path) }} + set $namespace "{{ $ing.Namespace }}"; + set $ingress_name "{{ $ing.Rule }}"; + set $service_name "{{ $ing.Service }}"; + {{ if (or $location.Rewrite.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Rewrite.SSLRedirect)) }} # enforce ssl on server side if ($pass_access_scheme = http) { @@ -752,9 +786,18 @@ stream { {{/* Add any additional configuration defined */}} {{ $location.ConfigurationSnippet }} + {{/* if we are sending the request to a custom default backend, we add the required headers */}} + {{ if (hasPrefix $location.Backend "custom-default-backend-") }} + proxy_set_header X-Code 503; + proxy_set_header X-Format $http_accept; + proxy_set_header X-Namespace $namespace; + proxy_set_header X-Ingress-Name $ingress_name; + proxy_set_header X-Service-Name $service_name; + {{ end }} + {{ buildProxyPass $server.Hostname $all.Backends $location }} {{ else }} - #{{ $location.Denied }} + # Location denied. Reason: {{ $location.Denied }} return 503; {{ end }} } diff --git a/core/pkg/ingress/annotations/defaultbackend/main.go b/core/pkg/ingress/annotations/defaultbackend/main.go index 0120e7d7a..f9bb440c2 100644 --- a/core/pkg/ingress/annotations/defaultbackend/main.go +++ b/core/pkg/ingress/annotations/defaultbackend/main.go @@ -48,7 +48,7 @@ func (db backend) Parse(ing *extensions.Ingress) (interface{}, error) { } name := fmt.Sprintf("%v/%v", ing.Namespace, s) - svc, err := db.serviceResolver.GetService(s) + svc, err := db.serviceResolver.GetService(name) if err != nil { return nil, errors.Wrapf(err, "unexpected error reading service %v", name) } diff --git a/core/pkg/ingress/controller/controller.go b/core/pkg/ingress/controller/controller.go index f1e9f90ee..41fa8ddc0 100644 --- a/core/pkg/ingress/controller/controller.go +++ b/core/pkg/ingress/controller/controller.go @@ -769,7 +769,9 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress glog.V(3).Infof("using custom default backend in server %v location %v (service %v/%v)", server.Hostname, location.Path, location.DefaultBackend.Namespace, location.DefaultBackend.Name) b, err := cloner.DeepCopy(upstream) - if err == nil { + if err != nil { + glog.Errorf("unexpected error copying Upstream: %v", err) + } else { name := fmt.Sprintf("custom-default-backend-%v", upstream.Name) nb := b.(*ingress.Backend) nb.Name = name