diff --git a/provider/kubernetes/annotations.go b/provider/kubernetes/annotations.go index e85211b2f..03805a4a7 100644 --- a/provider/kubernetes/annotations.go +++ b/provider/kubernetes/annotations.go @@ -1,6 +1,8 @@ package kubernetes import ( + "strconv" + "github.com/containous/traefik/provider/label" ) @@ -106,6 +108,13 @@ func getStringValue(annotations map[string]string, annotation string, defaultVal return label.GetStringValue(annotations, annotationName, defaultValue) } +func getStringSafeValue(annotations map[string]string, annotation string, defaultValue string) (string, error) { + annotationName := getAnnotationName(annotations, annotation) + value := label.GetStringValue(annotations, annotationName, defaultValue) + _, err := strconv.Unquote(`"` + value + `"`) + return value, err +} + func getBoolValue(annotations map[string]string, annotation string, defaultValue bool) bool { annotationName := getAnnotationName(annotations, annotation) return label.GetBoolValue(annotations, annotationName, defaultValue) diff --git a/provider/kubernetes/kubernetes.go b/provider/kubernetes/kubernetes.go index 54af7caad..8f3d1d01a 100644 --- a/provider/kubernetes/kubernetes.go +++ b/provider/kubernetes/kubernetes.go @@ -179,8 +179,11 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) } for _, i := range ingresses { - annotationIngressClass := getAnnotationName(i.Annotations, annotationKubernetesIngressClass) - ingressClass := i.Annotations[annotationIngressClass] + ingressClass, err := getStringSafeValue(i.Annotations, annotationKubernetesIngressClass, "") + if err != nil { + log.Errorf("Misconfigured ingress class for ingress %s/%s: %v", i.Namespace, i.Name, err) + continue + } if !p.shouldProcessIngress(ingressClass) { continue @@ -221,6 +224,19 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) for _, pa := range r.HTTP.Paths { priority := getIntValue(i.Annotations, annotationKubernetesPriority, 0) + + err := templateSafeString(r.Host) + if err != nil { + log.Errorf("failed to validate host %q for ingress %s/%s: %v", r.Host, i.Namespace, i.Name, err) + continue + } + + err = templateSafeString(pa.Path) + if err != nil { + log.Errorf("failed to validate path %q for ingress %s/%s: %v", pa.Path, i.Namespace, i.Name, err) + continue + } + baseName := r.Host + pa.Path if priority > 0 { baseName = strconv.Itoa(priority) + "-" + baseName @@ -882,15 +898,13 @@ func getFrontendRedirect(i *extensionsv1beta1.Ingress, baseName, path string) *t } } - redirectRegex := getStringValue(i.Annotations, annotationKubernetesRedirectRegex, "") - _, err := strconv.Unquote(`"` + redirectRegex + `"`) + redirectRegex, err := getStringSafeValue(i.Annotations, annotationKubernetesRedirectRegex, "") if err != nil { log.Debugf("Skipping Redirect on Ingress %s/%s due to invalid regex: %s", i.Namespace, i.Name, redirectRegex) return nil } - redirectReplacement := getStringValue(i.Annotations, annotationKubernetesRedirectReplacement, "") - _, err = strconv.Unquote(`"` + redirectReplacement + `"`) + redirectReplacement, err := getStringSafeValue(i.Annotations, annotationKubernetesRedirectReplacement, "") if err != nil { log.Debugf("Skipping Redirect on Ingress %s/%s due to invalid replacement: %q", i.Namespace, i.Name, redirectRegex) return nil @@ -1053,3 +1067,8 @@ func getRateLimit(i *extensionsv1beta1.Ingress) *types.RateLimit { return rateLimit } + +func templateSafeString(value string) error { + _, err := strconv.Unquote(`"` + value + `"`) + return err +} diff --git a/provider/kubernetes/kubernetes_test.go b/provider/kubernetes/kubernetes_test.go index 754e21841..329ebcde5 100644 --- a/provider/kubernetes/kubernetes_test.go +++ b/provider/kubernetes/kubernetes_test.go @@ -3431,3 +3431,48 @@ func TestAddGlobalBackendEndpointAPIError(t *testing.T) { err := provider.addGlobalBackend(client, ingresses, config) assert.Error(t, err) } + +func TestTemplateBreakingIngresssValues(t *testing.T) { + ingresses := []*extensionsv1beta1.Ingress{ + buildIngress( + iNamespace("testing"), + iAnnotation(annotationKubernetesIngressClass, "testing-\"foo\""), + iRules( + iRule( + iHost("foo"), + iPaths(onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))))), + ), + ), + buildIngress( + iNamespace("testing"), + iRules( + iRule( + iHost("testing-\"foo\""), + iPaths(onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))))), + ), + ), + buildIngress( + iNamespace("testing"), + iRules( + iRule( + iHost("foo"), + iPaths(onePath(iPath("/testing-\"foo\""), iBackend("service1", intstr.FromInt(80))))), + ), + ), + } + + client := clientMock{ + ingresses: ingresses, + } + provider := Provider{} + + actual, err := provider.loadIngresses(client) + require.NoError(t, err, "error loading ingresses") + + expected := buildConfiguration( + backends(), + frontends(), + ) + + assert.Equal(t, expected, actual) +}