From 8354d4e6e262de3e77090c6837e61239e138b68a Mon Sep 17 00:00:00 2001 From: Julian Strobl Date: Wed, 2 Nov 2016 11:11:20 +0100 Subject: [PATCH] Add SSL services annotation If an application in a container requires HTTPS, one needs to set the 'proxy_path https://...' instead of 'proxy_pass http://...'. With this patch one can use the annotation: 'nginx.org/ssl-services: "service1[,service2,...]"' to specify, which services require HTTPS. Fixes #61 --- examples/ssl-services/README.md | 34 +++++++++++++++++++++ nginx-controller/nginx/configurator.go | 22 ++++++++++--- nginx-controller/nginx/ingress.tmpl | 4 +++ nginx-controller/nginx/nginx.go | 1 + nginx-plus-controller/nginx/configurator.go | 22 ++++++++++--- nginx-plus-controller/nginx/ingress.tmpl | 4 +++ nginx-plus-controller/nginx/nginx.go | 1 + 7 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 examples/ssl-services/README.md diff --git a/examples/ssl-services/README.md b/examples/ssl-services/README.md new file mode 100644 index 0000000000..22a357d2fe --- /dev/null +++ b/examples/ssl-services/README.md @@ -0,0 +1,34 @@ +# SSL Services Support + +To load balance an application that requires HTTPS with NGINX Ingress controllers, you need to add the **nginx.org/ssl-services** annotation to your Ingress resource definition. The annotation specifies which services are SSL services. The annotation syntax is as follows: +``` +nginx.org/ssl-services: "service1[,service2,...]" +``` + +In the following example we load balance three applications, one of which requires HTTPS: +```yaml +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: cafe-ingress + annotations: + nginx.org/ssl-services: "ssl-svc" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + backend: + serviceName: tea-svc + servicePort: 80 + - path: /coffee + backend: + serviceName: coffee-svc + servicePort: 80 + - path: /ssl + backend: + serviceName: ssl-svc + servicePort: 443 +``` +*ssl-svc* is a service for an HTTPS application. The service becomes available at the `/ssl` path. Note how we used the **nginx.org/ssl-services** annotation. diff --git a/nginx-controller/nginx/configurator.go b/nginx-controller/nginx/configurator.go index 3e32c6c8ce..5ca7c8750b 100644 --- a/nginx-controller/nginx/configurator.go +++ b/nginx-controller/nginx/configurator.go @@ -80,6 +80,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri upstreams := make(map[string]Upstream) wsServices := getWebsocketServices(ingEx) + sslServices := getSSLServices(ingEx) if ingEx.Ingress.Spec.Backend != nil { name := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName) @@ -119,7 +120,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri upstreams[upsName] = upstream } - loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName]) + loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName], sslServices[path.Backend.ServiceName]) locations = append(locations, loc) if loc.Path == "/" { @@ -129,7 +130,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri if rootLocation == false && ingEx.Ingress.Spec.Backend != nil { upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName) - loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName]) + loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName], sslServices[ingEx.Ingress.Spec.Backend.ServiceName]) locations = append(locations, loc) } @@ -150,7 +151,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName) - loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName]) + loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName], sslServices[ingEx.Ingress.Spec.Backend.ServiceName]) locations = append(locations, loc) server.Locations = locations @@ -187,7 +188,19 @@ func getWebsocketServices(ingEx *IngressEx) map[string]bool { return wsServices } -func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) Location { +func getSSLServices(ingEx *IngressEx) map[string]bool { + sslServices := make(map[string]bool) + + if services, exists := ingEx.Ingress.Annotations["nginx.org/ssl-services"]; exists { + for _, svc := range strings.Split(services, ",") { + sslServices[svc] = true + } + } + + return sslServices +} + +func createLocation(path string, upstream Upstream, cfg *Config, websocket bool, ssl bool) Location { loc := Location{ Path: path, Upstream: upstream, @@ -195,6 +208,7 @@ func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) ProxyReadTimeout: cfg.ProxyReadTimeout, ClientMaxBodySize: cfg.ClientMaxBodySize, Websocket: websocket, + SSL: ssl, } return loc diff --git a/nginx-controller/nginx/ingress.tmpl b/nginx-controller/nginx/ingress.tmpl index 09b18a0380..290b300759 100644 --- a/nginx-controller/nginx/ingress.tmpl +++ b/nginx-controller/nginx/ingress.tmpl @@ -39,6 +39,10 @@ server { proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Proto $scheme; + {{if $location.SSL}} + proxy_pass https://{{$location.Upstream.Name}}; + {{else}} proxy_pass http://{{$location.Upstream.Name}}; + {{end}} }{{end}} }{{end}} diff --git a/nginx-controller/nginx/nginx.go b/nginx-controller/nginx/nginx.go index 30b1875dfc..44e034246e 100644 --- a/nginx-controller/nginx/nginx.go +++ b/nginx-controller/nginx/nginx.go @@ -53,6 +53,7 @@ type Location struct { ProxyReadTimeout string ClientMaxBodySize string Websocket bool + SSL bool } // NginxMainConfig describe the main NGINX configuration file diff --git a/nginx-plus-controller/nginx/configurator.go b/nginx-plus-controller/nginx/configurator.go index 7768241348..e73e8bd4b2 100644 --- a/nginx-plus-controller/nginx/configurator.go +++ b/nginx-plus-controller/nginx/configurator.go @@ -87,6 +87,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri wsServices := getWebsocketServices(ingEx) spServices := getSessionPersistenceServices(ingEx) + sslServices := getSSLServices(ingEx) if ingEx.Ingress.Spec.Backend != nil { name := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName) @@ -128,7 +129,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri upstreams[upsName] = upstream } - loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName]) + loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName], sslServices[path.Backend.ServiceName]) locations = append(locations, loc) if loc.Path == "/" { @@ -138,7 +139,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri if rootLocation == false && ingEx.Ingress.Spec.Backend != nil { upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName) - loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName]) + loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName], sslServices[ingEx.Ingress.Spec.Backend.ServiceName]) locations = append(locations, loc) } @@ -163,7 +164,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName) - loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName]) + loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName], sslServices[ingEx.Ingress.Spec.Backend.ServiceName]) locations = append(locations, loc) server.Locations = locations @@ -200,6 +201,18 @@ func getWebsocketServices(ingEx *IngressEx) map[string]bool { return wsServices } +func getSSLServices(ingEx *IngressEx) map[string]bool { + sslServices := make(map[string]bool) + + if services, exists := ingEx.Ingress.Annotations["nginx.org/ssl-services"]; exists { + for _, svc := range strings.Split(services, ",") { + sslServices[svc] = true + } + } + + return sslServices +} + func getSessionPersistenceServices(ingEx *IngressEx) map[string]string { spServices := make(map[string]string) @@ -231,7 +244,7 @@ func parseStickyService(service string) (serviceName string, stickyCookie string return svcNameParts[1], parts[1], nil } -func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) Location { +func createLocation(path string, upstream Upstream, cfg *Config, websocket bool, ssl bool) Location { loc := Location{ Path: path, Upstream: upstream, @@ -239,6 +252,7 @@ func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) ProxyReadTimeout: cfg.ProxyReadTimeout, ClientMaxBodySize: cfg.ClientMaxBodySize, Websocket: websocket, + SSL: ssl, } return loc diff --git a/nginx-plus-controller/nginx/ingress.tmpl b/nginx-plus-controller/nginx/ingress.tmpl index 487490cdc5..c4f3c59946 100644 --- a/nginx-plus-controller/nginx/ingress.tmpl +++ b/nginx-plus-controller/nginx/ingress.tmpl @@ -44,6 +44,10 @@ server { proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Proto $scheme; + {{if $location.SSL}} + proxy_pass https://{{$location.Upstream.Name}}; + {{else}} proxy_pass http://{{$location.Upstream.Name}}; + {{end}} }{{end}} }{{end}} diff --git a/nginx-plus-controller/nginx/nginx.go b/nginx-plus-controller/nginx/nginx.go index 6586d4de0b..e2ae915c81 100644 --- a/nginx-plus-controller/nginx/nginx.go +++ b/nginx-plus-controller/nginx/nginx.go @@ -76,6 +76,7 @@ type Location struct { ProxyReadTimeout string ClientMaxBodySize string Websocket bool + SSL bool } // NginxMainConfig describe the main NGINX configuration file