diff --git a/provider/kubernetes/fixtures/tLSSecretLoad_ingresses.yml b/provider/kubernetes/fixtures/tLSSecretLoad_ingresses.yml index b67366fde..228c1b0d8 100644 --- a/provider/kubernetes/fixtures/tLSSecretLoad_ingresses.yml +++ b/provider/kubernetes/fixtures/tLSSecretLoad_ingresses.yml @@ -38,3 +38,22 @@ spec: servicePort: 80 tls: - secretName: myUndefinedSecret + +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/frontend-entry-points: ep3 + name: badSecretIng + namespace: testing +spec: + rules: + - host: example.fail + http: + paths: + - backend: + serviceName: example-fail + servicePort: 80 + tls: + - secretName: badSecret diff --git a/provider/kubernetes/fixtures/tLSSecretLoad_secrets.yml b/provider/kubernetes/fixtures/tLSSecretLoad_secrets.yml index 32d547861..97ae2e1f7 100644 --- a/provider/kubernetes/fixtures/tLSSecretLoad_secrets.yml +++ b/provider/kubernetes/fixtures/tLSSecretLoad_secrets.yml @@ -6,3 +6,13 @@ kind: Secret metadata: name: myTlsSecret namespace: testing + +--- +apiVersion: v1 +data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXG5ceDAwXHgwMFx4MDAtLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tXG4= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0= +kind: Secret +metadata: + name: badSecret + namespace: testing diff --git a/provider/kubernetes/kubernetes.go b/provider/kubernetes/kubernetes.go index 1503ab547..225c94606 100644 --- a/provider/kubernetes/kubernetes.go +++ b/provider/kubernetes/kubernetes.go @@ -3,6 +3,7 @@ package kubernetes import ( "bufio" "bytes" + "encoding/pem" "errors" "flag" "fmt" @@ -835,6 +836,19 @@ func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) ( namespace, secretName, strings.Join(missingEntries, ", ")) } + if !isPem(tlsCrtData) { + missingEntries = append(missingEntries, "tls.crt") + } + + if !isPem(tlsKeyData) { + missingEntries = append(missingEntries, "tls.key") + } + + if len(missingEntries) > 0 { + return "", "", fmt.Errorf("secret %s/%s does not contain PEM formatted TLS data entries: %s", + namespace, secretName, strings.Join(missingEntries, ",")) + } + return cert, key, nil } @@ -1269,3 +1283,17 @@ func templateSafeString(value string) error { _, err := strconv.Unquote(`"` + value + `"`) return err } + +func isPem(data []byte) bool { + for { + block, rest := pem.Decode(data) + if block == nil { + return false + } + if len(rest) == 0 { + break + } + data = rest + } + return true +} diff --git a/provider/kubernetes/kubernetes_test.go b/provider/kubernetes/kubernetes_test.go index 394a524ce..3373ddda8 100644 --- a/provider/kubernetes/kubernetes_test.go +++ b/provider/kubernetes/kubernetes_test.go @@ -1915,8 +1915,8 @@ func TestGetTLS(t *testing.T) { Namespace: "testing", }, Data: map[string][]byte{ - "tls.crt": []byte("tls-crt"), - "tls.key": []byte("tls-key"), + "tls.crt": []byte("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"), + "tls.key": []byte("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n"), }, }, { @@ -1925,8 +1925,8 @@ func TestGetTLS(t *testing.T) { Namespace: "testing", }, Data: map[string][]byte{ - "tls.crt": []byte("tls-crt"), - "tls.key": []byte("tls-key"), + "tls.crt": []byte("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"), + "tls.key": []byte("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n"), }, }, }, @@ -1934,14 +1934,14 @@ func TestGetTLS(t *testing.T) { result: map[string]*tls.Configuration{ "testing/test-secret": { Certificate: &tls.Certificate{ - CertFile: tls.FileOrContent("tls-crt"), - KeyFile: tls.FileOrContent("tls-key"), + CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"), + KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n"), }, }, "testing/test-secret2": { Certificate: &tls.Certificate{ - CertFile: tls.FileOrContent("tls-crt"), - KeyFile: tls.FileOrContent("tls-key"), + CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"), + KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n"), }, }, }, @@ -1968,8 +1968,8 @@ func TestGetTLS(t *testing.T) { Namespace: "testing", }, Data: map[string][]byte{ - "tls.crt": []byte("tls-crt"), - "tls.key": []byte("tls-key"), + "tls.crt": []byte("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"), + "tls.key": []byte("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n"), }, }, }, @@ -1978,12 +1978,60 @@ func TestGetTLS(t *testing.T) { "testing/test-secret": { EntryPoints: []string{"api-secure", "https"}, Certificate: &tls.Certificate{ - CertFile: tls.FileOrContent("tls-crt"), - KeyFile: tls.FileOrContent("tls-key"), + CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"), + KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n"), }, }, }, }, + { + desc: "load bad certificate", + ingress: buildIngress( + iNamespace("testing"), + iAnnotation(annotationKubernetesFrontendEntryPoints, "https,api-secure"), + iRules(iRule(iHost("example.com"))), + iTLSes(iTLS("test-secret")), + ), + client: clientMock{ + secrets: []*corev1.Secret{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-secret", + Namespace: "testing", + }, + Data: map[string][]byte{ + "tls.crt": []byte("invalid"), + "tls.key": []byte("invalid"), + }, + }, + }, + }, + errResult: "secret testing/test-secret does not contain PEM formatted TLS data entries: tls.crt,tls.key", + }, + { + desc: "load nested bad certificate", + ingress: buildIngress( + iNamespace("testing"), + iAnnotation(annotationKubernetesFrontendEntryPoints, "https,api-secure"), + iRules(iRule(iHost("example.com"))), + iTLSes(iTLS("test-secret")), + ), + client: clientMock{ + secrets: []*corev1.Secret{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-secret", + Namespace: "testing", + }, + Data: map[string][]byte{ + "tls.crt": []byte("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n\x00\x00\x00-----END CERTIFICATE-----\n"), + "tls.key": []byte("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"), + }, + }, + }, + }, + errResult: "secret testing/test-secret does not contain PEM formatted TLS data entries: tls.crt", + }, } for _, test := range testCases {