From a0b1d5401250abf20b98d834bfcee17c277ba2b8 Mon Sep 17 00:00:00 2001 From: zarqman Date: Thu, 20 Dec 2018 12:08:03 -0700 Subject: [PATCH] kubernetes: sort and uniq TLS secrets --- old/provider/kubernetes/kubernetes.go | 94 +++++++++++++++------- old/provider/kubernetes/kubernetes_test.go | 29 ++++--- 2 files changed, 85 insertions(+), 38 deletions(-) diff --git a/old/provider/kubernetes/kubernetes.go b/old/provider/kubernetes/kubernetes.go index b201bd21c..9016e8ec8 100644 --- a/old/provider/kubernetes/kubernetes.go +++ b/old/provider/kubernetes/kubernetes.go @@ -9,6 +9,7 @@ import ( "net" "os" "reflect" + "sort" "strconv" "strings" "text/template" @@ -179,6 +180,8 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) Frontends: map[string]*types.Frontend{}, } + tlsConfigs := map[string]*tls.Configuration{} + for _, i := range ingresses { ingressClass, err := getStringSafeValue(i.Annotations, annotationKubernetesIngressClass, "") if err != nil { @@ -190,12 +193,10 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) continue } - tlsSection, err := getTLS(i, k8sClient) - if err != nil { + if err = getTLS(i, k8sClient, tlsConfigs); err != nil { log.Errorf("Error configuring TLS for ingress %s/%s: %v", i.Namespace, i.Name, err) continue } - templateObjects.TLS = append(templateObjects.TLS, tlsSection...) if i.Spec.Backend != nil { err := p.addGlobalBackend(k8sClient, i, templateObjects) @@ -416,6 +417,9 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) log.Errorf("Cannot update Ingress %s/%s due to error: %v", i.Namespace, i.Name, err) } } + + templateObjects.TLS = getTLSConfig(tlsConfigs) + return templateObjects, nil } @@ -636,37 +640,69 @@ func getRuleForHost(host string) string { return "Host:" + host } -func getTLS(ingress *extensionsv1beta1.Ingress, k8sClient Client) ([]*tls.Configuration, error) { - var tlsConfigs []*tls.Configuration - +func getTLS(ingress *extensionsv1beta1.Ingress, k8sClient Client, tlsConfigs map[string]*tls.Configuration) error { for _, t := range ingress.Spec.TLS { - secret, exists, err := k8sClient.GetSecret(ingress.Namespace, t.SecretName) - if err != nil { - return nil, fmt.Errorf("failed to fetch secret %s/%s: %v", ingress.Namespace, t.SecretName, err) - } - if !exists { - return nil, fmt.Errorf("secret %s/%s does not exist", ingress.Namespace, t.SecretName) - } + newEntryPoints := getSliceStringValue(ingress.Annotations, annotationKubernetesFrontendEntryPoints) - cert, key, err := getCertificateBlocks(secret, ingress.Namespace, t.SecretName) - if err != nil { - return nil, err + configKey := ingress.Namespace + "/" + t.SecretName + if tlsConfig, tlsExists := tlsConfigs[configKey]; tlsExists { + for _, entryPoint := range newEntryPoints { + tlsConfig.EntryPoints = mergeEntryPoint(tlsConfig.EntryPoints, entryPoint) + } + } else { + secret, exists, err := k8sClient.GetSecret(ingress.Namespace, t.SecretName) + if err != nil { + return fmt.Errorf("failed to fetch secret %s/%s: %v", ingress.Namespace, t.SecretName, err) + } + if !exists { + return fmt.Errorf("secret %s/%s does not exist", ingress.Namespace, t.SecretName) + } + + cert, key, err := getCertificateBlocks(secret, ingress.Namespace, t.SecretName) + if err != nil { + return err + } + + sort.Strings(newEntryPoints) + + tlsConfig = &tls.Configuration{ + EntryPoints: newEntryPoints, + Certificate: &tls.Certificate{ + CertFile: tls.FileOrContent(cert), + KeyFile: tls.FileOrContent(key), + }, + } + tlsConfigs[configKey] = tlsConfig } - - entryPoints := getSliceStringValue(ingress.Annotations, annotationKubernetesFrontendEntryPoints) - - tlsConfig := &tls.Configuration{ - EntryPoints: entryPoints, - Certificate: &tls.Certificate{ - CertFile: tls.FileOrContent(cert), - KeyFile: tls.FileOrContent(key), - }, - } - - tlsConfigs = append(tlsConfigs, tlsConfig) } - return tlsConfigs, nil + return nil +} + +func getTLSConfig(tlsConfigs map[string]*tls.Configuration) []*tls.Configuration { + var secretNames []string + for secretName := range tlsConfigs { + secretNames = append(secretNames, secretName) + } + sort.Strings(secretNames) + + var configs []*tls.Configuration + for _, secretName := range secretNames { + configs = append(configs, tlsConfigs[secretName]) + } + + return configs +} + +func mergeEntryPoint(entryPoints []string, newEntryPoint string) []string { + for _, ep := range entryPoints { + if ep == newEntryPoint { + return entryPoints + } + } + entryPoints = append(entryPoints, newEntryPoint) + sort.Strings(entryPoints) + return entryPoints } func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) (string, string, error) { diff --git a/old/provider/kubernetes/kubernetes_test.go b/old/provider/kubernetes/kubernetes_test.go index 941e88dff..a4eab689a 100644 --- a/old/provider/kubernetes/kubernetes_test.go +++ b/old/provider/kubernetes/kubernetes_test.go @@ -2830,7 +2830,7 @@ func TestGetTLS(t *testing.T) { desc string ingress *extensionsv1beta1.Ingress client Client - result []*tls.Configuration + result map[string]*tls.Configuration errResult string }{ { @@ -2910,11 +2910,21 @@ func TestGetTLS(t *testing.T) { ), iTLSes( iTLS("test-secret"), - iTLS("test-secret"), + iTLS("test-secret2"), ), ), client: clientMock{ secrets: []*corev1.Secret{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-secret2", + Namespace: "testing", + }, + Data: map[string][]byte{ + "tls.crt": []byte("tls-crt"), + "tls.key": []byte("tls-key"), + }, + }, { ObjectMeta: metav1.ObjectMeta{ Name: "test-secret", @@ -2927,14 +2937,14 @@ func TestGetTLS(t *testing.T) { }, }, }, - result: []*tls.Configuration{ - { + result: map[string]*tls.Configuration{ + "testing/test-secret": { Certificate: &tls.Certificate{ CertFile: tls.FileOrContent("tls-crt"), KeyFile: tls.FileOrContent("tls-key"), }, }, - { + "testing/test-secret2": { Certificate: &tls.Certificate{ CertFile: tls.FileOrContent("tls-crt"), KeyFile: tls.FileOrContent("tls-key"), @@ -2964,9 +2974,9 @@ func TestGetTLS(t *testing.T) { }, }, }, - result: []*tls.Configuration{ - { - EntryPoints: []string{"https", "api-secure"}, + result: map[string]*tls.Configuration{ + "testing/test-secret": { + EntryPoints: []string{"api-secure", "https"}, Certificate: &tls.Certificate{ CertFile: tls.FileOrContent("tls-crt"), KeyFile: tls.FileOrContent("tls-key"), @@ -2981,7 +2991,8 @@ func TestGetTLS(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - tlsConfigs, err := getTLS(test.ingress, test.client) + tlsConfigs := map[string]*tls.Configuration{} + err := getTLS(test.ingress, test.client, tlsConfigs) if test.errResult != "" { assert.EqualError(t, err, test.errResult)