diff --git a/pkg/generator/ingress_translator.go b/pkg/generator/ingress_translator.go index 97106fb91..6d4f4b55e 100644 --- a/pkg/generator/ingress_translator.go +++ b/pkg/generator/ingress_translator.go @@ -80,48 +80,24 @@ func NewIngressTranslator( func (translator *IngressTranslator) translateIngress(ctx context.Context, ingress *v1alpha1.Ingress, extAuthzEnabled bool) (*translatedIngress, error) { logger := logging.FromContext(ctx) - localSNIMatches := make([]*envoy.SNIMatch, 0, len(ingress.Spec.TLS)) - externalSNIMatches := make([]*envoy.SNIMatch, 0, len(ingress.Spec.TLS)) - for _, ingressTLS := range ingress.Spec.TLS { - if err := trackSecret(translator.tracker, ingressTLS.SecretNamespace, ingressTLS.SecretName, ingress); err != nil { - return nil, err - } + localIngressTLS := ingress.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityClusterLocal) + externalIngressTLS := ingress.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP) - secret, err := translator.secretGetter(ingressTLS.SecretNamespace, ingressTLS.SecretName) + externalSNIMatches := make([]*envoy.SNIMatch, 0, len(externalIngressTLS)) + for _, t := range externalIngressTLS { + sniMatch, err := translator.translateIngressTLS(t, ingress) if err != nil { - return nil, fmt.Errorf("failed to fetch secret: %w", err) + return nil, fmt.Errorf("failed to translate ingressTLS: %w", err) } - - // Validate certificate here as these are defined by users. - // We should not send Gateway without validation. - _, err = tls.X509KeyPair( - secret.Data[certificates.CertName], - secret.Data[certificates.PrivateKeyName], - ) + externalSNIMatches = append(externalSNIMatches, sniMatch) + } + localSNIMatches := make([]*envoy.SNIMatch, 0, len(localIngressTLS)) + for _, t := range localIngressTLS { + sniMatch, err := translator.translateIngressTLS(t, ingress) if err != nil { - return nil, fmt.Errorf("invalid secret is specified: %w", err) - } - - secretRef := types.NamespacedName{ - Namespace: ingressTLS.SecretNamespace, - Name: ingressTLS.SecretName, - } - sniMatch := &envoy.SNIMatch{ - Hosts: ingressTLS.Hosts, - CertSource: secretRef, - CertificateChain: secret.Data[certificates.CertName], - PrivateKey: secret.Data[certificates.PrivateKeyName], - } - - switch ingressTLS.Visibility { - // Also handle empty string as external for backwards compatibility - case "", v1alpha1.IngressVisibilityExternalIP: - externalSNIMatches = append(externalSNIMatches, sniMatch) - case v1alpha1.IngressVisibilityClusterLocal: - localSNIMatches = append(localSNIMatches, sniMatch) - default: - return nil, fmt.Errorf("invalid value: %s for ingress.spec.rule.tls.visibility", ingressTLS.Visibility) + return nil, fmt.Errorf("failed to translate ingressTLS: %w", err) } + localSNIMatches = append(localSNIMatches, sniMatch) } localHosts := make([]*route.VirtualHost, 0, len(ingress.Spec.Rules)) @@ -315,6 +291,39 @@ func (translator *IngressTranslator) translateIngress(ctx context.Context, ingre }, nil } +func (translator *IngressTranslator) translateIngressTLS(ingressTLS v1alpha1.IngressTLS, ingress *v1alpha1.Ingress) (*envoy.SNIMatch, error) { + if err := trackSecret(translator.tracker, ingressTLS.SecretNamespace, ingressTLS.SecretName, ingress); err != nil { + return nil, err + } + + secret, err := translator.secretGetter(ingressTLS.SecretNamespace, ingressTLS.SecretName) + if err != nil { + return nil, fmt.Errorf("failed to fetch secret: %w", err) + } + + // Validate certificate here as these are defined by users. + // We should not send Gateway without validation. + _, err = tls.X509KeyPair( + secret.Data[certificates.CertName], + secret.Data[certificates.PrivateKeyName], + ) + if err != nil { + return nil, fmt.Errorf("invalid secret is specified: %w", err) + } + + secretRef := types.NamespacedName{ + Namespace: ingressTLS.SecretNamespace, + Name: ingressTLS.SecretName, + } + sniMatch := &envoy.SNIMatch{ + Hosts: ingressTLS.Hosts, + CertSource: secretRef, + CertificateChain: secret.Data[certificates.CertName], + PrivateKey: secret.Data[certificates.PrivateKeyName], + } + return sniMatch, nil +} + func (translator *IngressTranslator) createUpstreamTransportSocket(http2 bool, namespace string) (*envoycorev3.TransportSocket, error) { caSecret, err := translator.secretGetter(pkgconfig.ServingNamespace(), netconfig.ServingRoutingCertName) if err != nil { diff --git a/pkg/reconciler/ingress/lister.go b/pkg/reconciler/ingress/lister.go index 40543767d..9c22cc4bc 100644 --- a/pkg/reconciler/ingress/lister.go +++ b/pkg/reconciler/ingress/lister.go @@ -63,17 +63,10 @@ func (l *gatewayPodTargetLister) ListProbeTargets(ctx context.Context, ing *v1al func (l *gatewayPodTargetLister) getIngressUrls(ing *v1alpha1.Ingress, gatewayIps []string) ([]status.ProbeTarget, error) { ips := sets.NewString(gatewayIps...) - localTLS := false - externalTLS := false - for _, t := range ing.Spec.TLS { - // Also include empty for reverse compatibility - if t.Visibility == "" || t.Visibility == v1alpha1.IngressVisibilityExternalIP { - externalTLS = true - } - if t.Visibility == v1alpha1.IngressVisibilityClusterLocal { - localTLS = true - } - } + localIngressTLS := ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityClusterLocal) + externalIngressTLS := ing.GetIngressTLSForVisibility(v1alpha1.IngressVisibilityExternalIP) + localTLS := len(localIngressTLS) > 0 + externalTLS := len(externalIngressTLS) > 0 targets := make([]status.ProbeTarget, 0, len(ing.Spec.Rules)) for _, rule := range ing.Spec.Rules { diff --git a/vendor/knative.dev/networking/config/ingress.yaml b/vendor/knative.dev/networking/config/ingress.yaml index e284c2572..aafed926f 100644 --- a/vendor/knative.dev/networking/config/ingress.yaml +++ b/vendor/knative.dev/networking/config/ingress.yaml @@ -150,9 +150,6 @@ spec: secretNamespace: description: SecretNamespace is the namespace of the secret used to terminate SSL traffic. If not set the namespace should be assumed to be the same as the Ingress. If set the secret should have the same namespace as the Ingress otherwise the behaviour is undefined and not supported. type: string - visibility: - description: Visibility signifies whether the tls hosts should be considered `ClusterLocal`. If it's not specified then it defaults to `ExternalIP`. - type: string status: description: 'Status is the current state of the Ingress. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' type: object diff --git a/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_helpers.go b/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_helpers.go new file mode 100644 index 000000000..e8ea7c17b --- /dev/null +++ b/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_helpers.go @@ -0,0 +1,47 @@ +/* +Copyright 2023 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +// GetIngressTLSForVisibility returns a list of `Spec.TLS` where the `Hosts` field matches +// to `Spec.Rules.Hosts` and where the Rules have the defined ingress visibility. +// This method can be used in net-* implementations to select the correct `IngressTLS` entries +// for cluster-local and cluster-external gateways/listeners. +func (i *Ingress) GetIngressTLSForVisibility(visibility IngressVisibility) []IngressTLS { + ingressTLS := make([]IngressTLS, 0, len(i.Spec.TLS)) + + if i.Spec.TLS == nil || len(i.Spec.TLS) == 0 { + return ingressTLS + } + + for _, r := range i.Spec.Rules { + if r.Visibility == visibility { + for _, t := range i.Spec.TLS { + // Check if hosts slices are equal ignoring the order + if cmp.Diff(r.Hosts, t.Hosts, cmpopts.SortSlices(func(a, b string) bool { return a < b })) == "" { + ingressTLS = append(ingressTLS, t) + } + } + } + } + + return ingressTLS +} diff --git a/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_types.go b/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_types.go index 65d612cd9..44b0d74e2 100644 --- a/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_types.go +++ b/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_types.go @@ -149,10 +149,6 @@ type IngressTLS struct { // // +optional SecretNamespace string `json:"secretNamespace,omitempty"` - - // Visibility signifies whether the tls hosts should be considered `ClusterLocal`. - // If it's not specified then it defaults to `ExternalIP`. - Visibility IngressVisibility `json:"visibility,omitempty"` } // IngressRule represents the rules mapping the paths under a specified host to diff --git a/vendor/knative.dev/networking/pkg/config/config.go b/vendor/knative.dev/networking/pkg/config/config.go index 849753542..b9fca8585 100644 --- a/vendor/knative.dev/networking/pkg/config/config.go +++ b/vendor/knative.dev/networking/pkg/config/config.go @@ -146,7 +146,7 @@ const ( type CertificateType string const ( - // CertificateSystemInternal defines a certificate used for `system-internal-tls` + // CertificateSystemInternal defines a certificate used for `system-internal-tls`. CertificateSystemInternal CertificateType = "system-internal" // CertificateClusterLocalDomain defines a certificate used for `cluster-local-domain-tls`.