diff --git a/internal/contour/listener.go b/internal/contour/listener.go index aee27890365..73e1d175ec4 100644 --- a/internal/contour/listener.go +++ b/internal/contour/listener.go @@ -194,6 +194,19 @@ func (lc *ListenerCache) httpsAddress() string { return DEFAULT_HTTPS_LISTENER_ADDRESS } +func (lc *listenerCache) HostHasTls(host string) bool { + for _, listener := range lc.Values() { + for _, filterChain := range listener.FilterChains { + for _, sniDomain := range filterChain.GetFilterChainMatch().GetSniDomains() { + if sniDomain == host { + return true + } + } + } + } + return false +} + // httpsPort returns the port for the HTTPS (TLS) listener // or DEFAULT_HTTPS_LISTENER_PORT if not configured. func (lc *ListenerCache) httpsPort() uint32 { diff --git a/internal/contour/translator.go b/internal/contour/translator.go index 2e818fa701d..cc2de033d07 100644 --- a/internal/contour/translator.go +++ b/internal/contour/translator.go @@ -287,7 +287,7 @@ func (t *Translator) addIngress(i *v1beta1.Ingress) { host = "*" } t.vhosts[host] = appendIfMissing(t.vhosts[host], i) - t.recomputevhost(host, t.vhosts[host]) + t.recomputevhost(host, t.listenerCache.HostHasTls(host), t.vhosts[host]) } } @@ -309,7 +309,7 @@ func (t *Translator) removeIngress(i *v1beta1.Ingress) { } for _, rule := range i.Spec.Rules { t.vhosts[rule.Host] = removeIfPresent(t.vhosts[rule.Host], i) - t.recomputevhost(rule.Host, t.vhosts[rule.Host]) + t.recomputevhost(rule.Host, t.listenerCache.HostHasTls(rule.Host), t.vhosts[rule.Host]) } } @@ -318,6 +318,8 @@ func (t *Translator) recomputeListeners() { } func (t *Translator) addSecret(s *v1.Secret) { + defer t.VirtualHostCache.Notify() + _, cert := s.Data[v1.TLSCertKey] _, key := s.Data[v1.TLSPrivateKeyKey] if !cert || !key { @@ -333,11 +335,39 @@ func (t *Translator) addSecret(s *v1.Secret) { t.secrets[metadata{name: s.Name, namespace: s.Namespace}] = s t.recomputeTLSListener(t.ingresses, t.secrets) + + if t.ingresses[metadata{name: s.Name, namespace: s.Namespace}] != nil { + i := t.ingresses[metadata{name: s.Name, namespace: s.Namespace}] + for _, rule := range i.Spec.Rules { + host := rule.Host + if host == "" { + // If the host is unspecified, the Ingress routes all traffic based on the specified IngressRuleValue. + host = "*" + } + t.vhosts[host] = appendIfMissing(t.vhosts[host], i) + t.recomputevhost(host, t.listenerCache.HostHasTls(host), t.vhosts[host]) + } + } } func (t *Translator) removeSecret(s *v1.Secret) { + defer t.VirtualHostCache.Notify() + delete(t.secrets, metadata{name: s.Name, namespace: s.Namespace}) t.recomputeTLSListener(t.ingresses, t.secrets) + if t.ingresses[metadata{name: s.Name, namespace: s.Namespace}] != nil { + i := t.ingresses[metadata{name: s.Name, namespace: s.Namespace}] + for _, rule := range i.Spec.Rules { + host := rule.Host + if host == "" { + // If the host is unspecified, the Ingress routes all traffic based on the specified IngressRuleValue. + host = "*" + } + t.vhosts[host] = appendIfMissing(t.vhosts[host], i) + t.Infof("%s is %t", host, t.listenerCache.HostHasTls(host)) + t.recomputevhost(host, t.listenerCache.HostHasTls(host), t.vhosts[host]) + } + } } // writeSecret writes the contents of the secret to a fixed location on diff --git a/internal/contour/virtualhost.go b/internal/contour/virtualhost.go index d0e0d7bb9ef..7ce8e076fcc 100644 --- a/internal/contour/virtualhost.go +++ b/internal/contour/virtualhost.go @@ -31,7 +31,7 @@ type VirtualHostCache struct { // recomputevhost recomputes the *v2.VirutalHost record from the list of ingresses // supplied and the cache updated. If ingresses is empty then the *v2.VirtualHost // record will be removed from the cache. -func (v *VirtualHostCache) recomputevhost(vhost string, ingresses []*v1beta1.Ingress) { +func (v *VirtualHostCache) recomputevhost(vhost string, tls bool, ingresses []*v1beta1.Ingress) { switch len(ingresses) { case 0: // there are no ingresses registered with this vhost any more @@ -55,6 +55,11 @@ func (v *VirtualHostCache) recomputevhost(vhost string, ingresses []*v1beta1.Ing // TODO(dfc) plumb a logger in here so we can log this error. continue } + if tls { + if sslRedirect(ing) { + vv.RequireTls = v2.VirtualHost_ALL + } + } for _, p := range rule.IngressRuleValue.HTTP.Paths { m := pathToRouteMatch(p) a := clusteraction(ingressBackendToClusterName(ing, &p.Backend)) @@ -145,3 +150,10 @@ func clusteraction(cluster string) *v2.Route_Route { }, } } + +func sslRedirect(i *v1beta1.Ingress) bool { + if i.Annotations["kubenetes.io/ingress.ssl-redirect"] == "false" { + return false + } + return true +}