From 03e3c34308641bd935fe75897843de27239b7f50 Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Mon, 6 Feb 2017 17:48:08 -0300 Subject: [PATCH 1/3] Change server initialization code to use certificates common names --- core/pkg/ingress/controller/util.go | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/core/pkg/ingress/controller/util.go b/core/pkg/ingress/controller/util.go index 7ff154d8f..6637d8142 100644 --- a/core/pkg/ingress/controller/util.go +++ b/core/pkg/ingress/controller/util.go @@ -114,3 +114,51 @@ func mergeLocationAnnotations(loc *ingress.Location, anns map[string]interface{} glog.Errorf("unexpected error merging extracted annotations in location type: %v", err) } } + +func isDomainName(s string) bool { + // See RFC 1035, RFC 3696. + if len(s) == 0 { + return false + } + if len(s) > 255 { + return false + } + if s[len(s)-1] != '.' { // simplify checking loop: make name end in dot + s += "." + } + + last := byte('.') + ok := false // ok once we've seen a letter + partlen := 0 + for i := 0; i < len(s); i++ { + c := s[i] + switch { + default: + return false + case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_': + ok = true + partlen++ + case '0' <= c && c <= '9': + // fine + partlen++ + case c == '-': + // byte before dash cannot be dot + if last == '.' { + return false + } + partlen++ + case c == '.': + // byte before dot cannot be dot, dash + if last == '.' || last == '-' { + return false + } + if partlen > 63 || partlen == 0 { + return false + } + partlen = 0 + } + last = c + } + + return ok +} From 51c2ff54a8e306c552f2b6b1018073e380c10ed2 Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Tue, 7 Feb 2017 11:10:44 -0300 Subject: [PATCH 2/3] continue work --- controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index 5088f0542..c5eecdfe2 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -208,7 +208,7 @@ http { listen [::]:80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $index 0 }} ipv6only=off{{end}}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}}; {{/* Listen on 442 because port 443 is used in the stream section */}} {{/* This listen cannot contains proxy_protocol directive because port 443 is in charge of decoding the protocol */}} - {{ if not (empty $server.SSLCertificate) }}listen 442 {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }}; + {{ if not (empty $server.SSLCertificate) }}listen 442{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }}; {{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}} # PEM sha: {{ $server.SSLPemChecksum }} ssl_certificate {{ $server.SSLCertificate }}; From 234277150a3d076ef89b9663594a753aa3e9e7b9 Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Thu, 16 Feb 2017 12:22:37 -0300 Subject: [PATCH 3/3] Sync --- core/pkg/ingress/controller/controller.go | 164 +++++++++++----------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/core/pkg/ingress/controller/controller.go b/core/pkg/ingress/controller/controller.go index 2c4d7c23d..c58b5ae42 100644 --- a/core/pkg/ingress/controller/controller.go +++ b/core/pkg/ingress/controller/controller.go @@ -588,30 +588,9 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress server = servers[defServerName] } - // use default upstream - defBackend := upstreams[defUpstreamName] - // we need to check if the spec contains the default backend - if ing.Spec.Backend != nil { - glog.V(3).Infof("ingress rule %v/%v defines a default Backend %v/%v", - ing.Namespace, - ing.Name, - ing.Spec.Backend.ServiceName, - ing.Spec.Backend.ServicePort.String()) - - name := fmt.Sprintf("%v-%v-%v", - ing.GetNamespace(), - ing.Spec.Backend.ServiceName, - ing.Spec.Backend.ServicePort.String()) - - if defUps, ok := upstreams[name]; ok { - defBackend = defUps - } - } - if rule.HTTP == nil && host != defServerName { glog.V(3).Infof("ingress rule %v/%v does not contains HTTP rules. using default backend", ing.Namespace, ing.Name) - server.Locations[0].Backend = defBackend.Name continue } @@ -806,7 +785,13 @@ func (ic *GenericController) serviceEndpoints(svcKey, backendPort string, return upstreams, nil } -func (ic *GenericController) createServers(data []interface{}, upstreams map[string]*ingress.Backend) map[string]*ingress.Server { +// createServers initializes a map that contains information about the list of +// FDQN referenced by ingress rules and the common name field in the referenced +// SSL certificates. Each server is configured with location / using a default +// backend specified by the user or the one inside the ingress spec. +func (ic *GenericController) createServers(data []interface{}, + upstreams map[string]*ingress.Backend) map[string]*ingress.Server { + servers := make(map[string]*ingress.Server) bdef := ic.GetDefaultBackend() @@ -818,11 +803,9 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str BufferSize: bdef.ProxyBufferSize, } - dun := ic.getDefaultUpstream().Name - // This adds the Default Certificate to Default Backend and also for vhosts missing the secret - var defaultPemFileName, defaultPemSHA string defaultCertificate, err := ic.getPemCertificate(ic.cfg.DefaultSSLCertificate) + var defaultPemFileName, defaultPemSHA string // If no default Certificate was supplied, tries to generate a new dumb one if err != nil { var cert *ingress.SSLCert @@ -839,7 +822,7 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str defaultPemSHA = defaultCertificate.PemSHA } - // default server + // initialize the default server servers[defServerName] = &ingress.Server{ Hostname: defServerName, SSLCertificate: defaultPemFileName, @@ -848,7 +831,7 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str { Path: rootLocation, IsDefBackend: true, - Backend: dun, + Backend: ic.getDefaultUpstream().Name, Proxy: ngxProxy, }, }} @@ -862,16 +845,86 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str // check if ssl passthrough is configured sslpt := ic.annotations.SSLPassthrough(ing) + dun := ic.getDefaultUpstream().Name + if ing.Spec.Backend != nil { + // replace default backend + defUpstream := fmt.Sprintf("%v-%v-%v", ing.GetNamespace(), ing.Spec.Backend.ServiceName, ing.Spec.Backend.ServicePort.String()) + if backendUpstream, ok := upstreams[defUpstream]; ok { + dun = backendUpstream.Name + } + } for _, rule := range ing.Spec.Rules { host := rule.Host if host == "" { - host = defServerName + if len(ing.Spec.TLS) == 0 { + // default host already initialized + continue + } + + for _, tls := range ing.Spec.TLS { + c, exists := ic.sslCertTracker.Get(fmt.Sprintf("%v/%v", ing.Namespace, tls.SecretName)) + if !exists { + continue + } + cert := c.(*ingress.SSLCert) + + // configure hosts defined in TLS section + for _, host := range tls.Hosts { + if _, ok := servers[host]; ok { + servers[host].SSLPassthrough = sslpt + // server already configured + continue + } + + servers[host] = &ingress.Server{ + Hostname: host, + SSLCertificate: cert.PemFileName, + SSLPemChecksum: cert.PemSHA, + Locations: []*ingress.Location{ + { + Path: rootLocation, + IsDefBackend: true, + Backend: dun, + Proxy: ngxProxy, + }, + }, SSLPassthrough: sslpt, + } + } + + for _, cn := range cert.CN { + if !isDomainName(cn) { + glog.Warningf("'%v' is not a valid domain name (%v/%v)", cn, cert.GetNamespace, cert.GetName) + continue + } + if _, ok := servers[cn]; ok { + // server already configured + continue + } + + servers[cn] = &ingress.Server{ + Hostname: cn, + SSLCertificate: cert.PemFileName, + SSLPemChecksum: cert.PemSHA, + Locations: []*ingress.Location{ + { + Path: rootLocation, + IsDefBackend: true, + Backend: dun, + Proxy: ngxProxy, + }, + }, + } + } + } } + if _, ok := servers[host]; ok { + servers[host].SSLPassthrough = sslpt // server already configured continue } + servers[host] = &ingress.Server{ Hostname: host, Locations: []*ingress.Location{ @@ -881,60 +934,7 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str Backend: dun, Proxy: ngxProxy, }, - }, SSLPassthrough: sslpt} - } - } - - // configure default location and SSL - for _, ingIf := range data { - ing := ingIf.(*extensions.Ingress) - if !IsValidClass(ing, ic.cfg.IngressClass) { - continue - } - - for _, rule := range ing.Spec.Rules { - host := rule.Host - if host == "" { - host = defServerName - } - - // only add a certificate if the server does not have one previously configured - // TODO: TLS without secret? - if len(ing.Spec.TLS) > 0 && servers[host].SSLCertificate == "" { - tlsSecretName := "" - for _, tls := range ing.Spec.TLS { - for _, tlsHost := range tls.Hosts { - if tlsHost == host { - tlsSecretName = tls.SecretName - break - } - } - } - - key := fmt.Sprintf("%v/%v", ing.Namespace, tlsSecretName) - bc, exists := ic.sslCertTracker.Get(key) - if exists { - cert := bc.(*ingress.SSLCert) - if isHostValid(host, cert) { - servers[host].SSLCertificate = cert.PemFileName - servers[host].SSLPemChecksum = cert.PemSHA - } - } else { - - servers[host].SSLCertificate = defaultPemFileName - servers[host].SSLPemChecksum = defaultPemSHA - } - } - - if ing.Spec.Backend != nil { - defUpstream := fmt.Sprintf("%v-%v-%v", ing.GetNamespace(), ing.Spec.Backend.ServiceName, ing.Spec.Backend.ServicePort.String()) - if backendUpstream, ok := upstreams[defUpstream]; ok { - if host == "" || host == defServerName { - ic.recorder.Eventf(ing, api.EventTypeWarning, "MAPPING", "error: rules with Spec.Backend are allowed only with hostnames") - continue - } - servers[host].Locations[0].Backend = backendUpstream.Name - } + }, SSLPassthrough: sslpt, } } }