kubernetes: sort and uniq TLS secrets

This commit is contained in:
zarqman 2018-12-20 12:08:03 -07:00 committed by Traefiker Bot
parent 60b5286f8c
commit a0b1d54012
2 changed files with 85 additions and 38 deletions

View file

@ -9,6 +9,7 @@ import (
"net" "net"
"os" "os"
"reflect" "reflect"
"sort"
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
@ -179,6 +180,8 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
Frontends: map[string]*types.Frontend{}, Frontends: map[string]*types.Frontend{},
} }
tlsConfigs := map[string]*tls.Configuration{}
for _, i := range ingresses { for _, i := range ingresses {
ingressClass, err := getStringSafeValue(i.Annotations, annotationKubernetesIngressClass, "") ingressClass, err := getStringSafeValue(i.Annotations, annotationKubernetesIngressClass, "")
if err != nil { if err != nil {
@ -190,12 +193,10 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
continue continue
} }
tlsSection, err := getTLS(i, k8sClient) if err = getTLS(i, k8sClient, tlsConfigs); err != nil {
if err != nil {
log.Errorf("Error configuring TLS for ingress %s/%s: %v", i.Namespace, i.Name, err) log.Errorf("Error configuring TLS for ingress %s/%s: %v", i.Namespace, i.Name, err)
continue continue
} }
templateObjects.TLS = append(templateObjects.TLS, tlsSection...)
if i.Spec.Backend != nil { if i.Spec.Backend != nil {
err := p.addGlobalBackend(k8sClient, i, templateObjects) 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) log.Errorf("Cannot update Ingress %s/%s due to error: %v", i.Namespace, i.Name, err)
} }
} }
templateObjects.TLS = getTLSConfig(tlsConfigs)
return templateObjects, nil return templateObjects, nil
} }
@ -636,37 +640,69 @@ func getRuleForHost(host string) string {
return "Host:" + host return "Host:" + host
} }
func getTLS(ingress *extensionsv1beta1.Ingress, k8sClient Client) ([]*tls.Configuration, error) { func getTLS(ingress *extensionsv1beta1.Ingress, k8sClient Client, tlsConfigs map[string]*tls.Configuration) error {
var tlsConfigs []*tls.Configuration
for _, t := range ingress.Spec.TLS { for _, t := range ingress.Spec.TLS {
newEntryPoints := getSliceStringValue(ingress.Annotations, annotationKubernetesFrontendEntryPoints)
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) secret, exists, err := k8sClient.GetSecret(ingress.Namespace, t.SecretName)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch secret %s/%s: %v", ingress.Namespace, t.SecretName, err) return fmt.Errorf("failed to fetch secret %s/%s: %v", ingress.Namespace, t.SecretName, err)
} }
if !exists { if !exists {
return nil, fmt.Errorf("secret %s/%s does not exist", ingress.Namespace, t.SecretName) return fmt.Errorf("secret %s/%s does not exist", ingress.Namespace, t.SecretName)
} }
cert, key, err := getCertificateBlocks(secret, ingress.Namespace, t.SecretName) cert, key, err := getCertificateBlocks(secret, ingress.Namespace, t.SecretName)
if err != nil { if err != nil {
return nil, err return err
} }
entryPoints := getSliceStringValue(ingress.Annotations, annotationKubernetesFrontendEntryPoints) sort.Strings(newEntryPoints)
tlsConfig := &tls.Configuration{ tlsConfig = &tls.Configuration{
EntryPoints: entryPoints, EntryPoints: newEntryPoints,
Certificate: &tls.Certificate{ Certificate: &tls.Certificate{
CertFile: tls.FileOrContent(cert), CertFile: tls.FileOrContent(cert),
KeyFile: tls.FileOrContent(key), KeyFile: tls.FileOrContent(key),
}, },
} }
tlsConfigs[configKey] = tlsConfig
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) { func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) (string, string, error) {

View file

@ -2830,7 +2830,7 @@ func TestGetTLS(t *testing.T) {
desc string desc string
ingress *extensionsv1beta1.Ingress ingress *extensionsv1beta1.Ingress
client Client client Client
result []*tls.Configuration result map[string]*tls.Configuration
errResult string errResult string
}{ }{
{ {
@ -2910,11 +2910,21 @@ func TestGetTLS(t *testing.T) {
), ),
iTLSes( iTLSes(
iTLS("test-secret"), iTLS("test-secret"),
iTLS("test-secret"), iTLS("test-secret2"),
), ),
), ),
client: clientMock{ client: clientMock{
secrets: []*corev1.Secret{ 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{ ObjectMeta: metav1.ObjectMeta{
Name: "test-secret", 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{ Certificate: &tls.Certificate{
CertFile: tls.FileOrContent("tls-crt"), CertFile: tls.FileOrContent("tls-crt"),
KeyFile: tls.FileOrContent("tls-key"), KeyFile: tls.FileOrContent("tls-key"),
}, },
}, },
{ "testing/test-secret2": {
Certificate: &tls.Certificate{ Certificate: &tls.Certificate{
CertFile: tls.FileOrContent("tls-crt"), CertFile: tls.FileOrContent("tls-crt"),
KeyFile: tls.FileOrContent("tls-key"), KeyFile: tls.FileOrContent("tls-key"),
@ -2964,9 +2974,9 @@ func TestGetTLS(t *testing.T) {
}, },
}, },
}, },
result: []*tls.Configuration{ result: map[string]*tls.Configuration{
{ "testing/test-secret": {
EntryPoints: []string{"https", "api-secure"}, EntryPoints: []string{"api-secure", "https"},
Certificate: &tls.Certificate{ Certificate: &tls.Certificate{
CertFile: tls.FileOrContent("tls-crt"), CertFile: tls.FileOrContent("tls-crt"),
KeyFile: tls.FileOrContent("tls-key"), KeyFile: tls.FileOrContent("tls-key"),
@ -2981,7 +2991,8 @@ func TestGetTLS(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
tlsConfigs, err := getTLS(test.ingress, test.client) tlsConfigs := map[string]*tls.Configuration{}
err := getTLS(test.ingress, test.client, tlsConfigs)
if test.errResult != "" { if test.errResult != "" {
assert.EqualError(t, err, test.errResult) assert.EqualError(t, err, test.errResult)