diff --git a/.github/workflows/kind-e2e.yaml b/.github/workflows/kind-e2e.yaml index 7f59f0eb3d0b..d610757f0b27 100644 --- a/.github/workflows/kind-e2e.yaml +++ b/.github/workflows/kind-e2e.yaml @@ -87,17 +87,17 @@ jobs: fail-fast: false # Keep running if one leg fails. matrix: k8s-version: - - v1.26.x - - v1.27.x +# - v1.26.x +# - v1.27.x - v1.28.x ingress: - kourier - kourier-tls - - istio - - istio-tls - - istio-ambient - - contour +# - istio +# - istio-tls +# - istio-ambient +# - contour # Disabled due to consistent failures # - gateway_istio @@ -113,21 +113,21 @@ jobs: # test-flags: -enable-alpha # namespace-resources: httproute - - ingress: contour - namespace-resources: httpproxy - - - ingress: istio - namespace-resources: virtualservices - - - ingress: istio-tls - ingress-class: istio - namespace-resources: virtualservices - enable-tls: 1 - - - ingress: istio-ambient - namespace-resources: virtualservices - ingress-class: istio - ambient: 1 +# - ingress: contour +# namespace-resources: httpproxy +# +# - ingress: istio +# namespace-resources: virtualservices +# +# - ingress: istio-tls +# ingress-class: istio +# namespace-resources: virtualservices +# enable-tls: 1 + +# - ingress: istio-ambient +# namespace-resources: virtualservices +# ingress-class: istio +# ambient: 1 - ingress: kourier-tls ingress-class: kourier diff --git a/cmd/activator/main.go b/cmd/activator/main.go index b765ed1c2247..86626710988c 100644 --- a/cmd/activator/main.go +++ b/cmd/activator/main.go @@ -167,8 +167,11 @@ func main() { // At this moment activator with TLS does not disable HTTP. // See also https://github.com/knative/serving/issues/12808. if tlsEnabled { - logger.Info("Knative Internal TLS is enabled") - certCache = certificate.NewCertCache(ctx) + logger.Info("Knative system-internal-tls is enabled") + certCache, err = certificate.NewCertCache(ctx) + if err != nil { + logger.Fatalw("Failed to create certificate cache", zap.Error(err)) + } transport = pkgnet.NewProxyAutoTLSTransport(env.MaxIdleProxyConns, env.MaxIdleProxyConnsPerHost, certCache.TLSContext()) } diff --git a/cmd/controller/main.go b/cmd/controller/main.go index a0140315620f..440637d0b218 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -20,7 +20,6 @@ import ( // The set of controllers this controller process runs. "flag" - certificate "knative.dev/networking/pkg/certificates/reconciler" "knative.dev/pkg/reconciler" "knative.dev/pkg/signals" "knative.dev/serving/pkg/reconciler/configuration" @@ -32,18 +31,11 @@ import ( "knative.dev/serving/pkg/reconciler/serverlessservice" "knative.dev/serving/pkg/reconciler/service" - // This defines the shared main for injected controllers. - filteredFactory "knative.dev/pkg/client/injection/kube/informers/factory/filtered" "knative.dev/pkg/injection" "knative.dev/pkg/injection/sharedmain" - "knative.dev/serving/pkg/networking" "knative.dev/serving/pkg/reconciler/domainmapping" ) -const ( - secretLabelNamePostfix = "-ctrl" -) - var ctors = []injection.ControllerConstructor{ configuration.NewController, labeler.NewController, @@ -53,7 +45,6 @@ var ctors = []injection.ControllerConstructor{ service.NewController, gc.NewController, nscert.NewController, - certificate.NewControllerFactory(networking.ServingCertName), domainmapping.NewController, } @@ -62,7 +53,5 @@ func main() { "reconciliation-timeout", reconciler.DefaultTimeout, "The amount of time to give each reconciliation of a resource to complete before its context is canceled.") - labelName := networking.ServingCertName + secretLabelNamePostfix - ctx := filteredFactory.WithSelectors(signals.NewContext(), labelName) - sharedmain.MainWithContext(ctx, "controller", ctors...) + sharedmain.MainWithContext(signals.NewContext(), "controller", ctors...) } diff --git a/config/core/300-knativecertificate.yaml b/config/core/300-knativecertificate.yaml new file mode 100644 index 000000000000..b97c94623c9f --- /dev/null +++ b/config/core/300-knativecertificate.yaml @@ -0,0 +1,14 @@ +apiVersion: networking.internal.knative.dev/v1alpha1 +kind: Certificate +metadata: + annotations: + networking.knative.dev/certificate.class: cert-manager.certificate.networking.knative.dev + labels: + networking.knative.dev/certificate-type: system-internal + name: routing-serving-certs + namespace: knative-serving +spec: + dnsNames: + - kn-routing + - data-plane.knative.dev # for reverse-compatibility with net-* implementations that do not work with multi-SANs + secretName: routing-serving-certs diff --git a/config/core/300-secret.yaml b/config/core/300-secret.yaml deleted file mode 100644 index 3b40510a2a7e..000000000000 --- a/config/core/300-secret.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2022 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 -# -# https://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. - -apiVersion: v1 -kind: Secret -metadata: - # Do not drop -ctrl-ca suffix as certificate creation requires it - # https://github.com/knative/networking/blob/main/pkg/certificates/reconciler/controller.go#L38 - name: serving-certs-ctrl-ca - namespace: knative-serving - labels: - serving-certs-ctrl: "data-plane" - networking.internal.knative.dev/certificate-uid: "serving-certs" -# The data is populated when knative-internal-tls is enabled. ---- -apiVersion: v1 -kind: Secret -metadata: - # this is the legacy secret - # we can drop this once all net-* implementations are using the new `routing-serving-certs` secret - name: knative-serving-certs - namespace: knative-serving - labels: - serving-certs-ctrl: "data-plane" - networking.internal.knative.dev/certificate-uid: "serving-certs" -# The data is populated when knative-internal-tls is enabled. ---- -apiVersion: v1 -kind: Secret -metadata: - name: routing-serving-certs - namespace: knative-serving - labels: - serving-certs-ctrl: "data-plane-routing" - networking.internal.knative.dev/certificate-uid: "serving-certs" -# The data is populated when knative-internal-tls is enabled. diff --git a/go.mod b/go.mod index 5b8a7601b557..77f08d52527a 100644 --- a/go.mod +++ b/go.mod @@ -156,3 +156,5 @@ require ( // TODO: https://github.com/knative/serving/issues/14597 replace github.com/gorilla/websocket => github.com/gorilla/websocket v1.5.0 + +replace knative.dev/networking => /Users/rlehmann/code/knative/networking diff --git a/go.sum b/go.sum index 017e50f6135d..b45992ca80b2 100644 --- a/go.sum +++ b/go.sum @@ -930,8 +930,6 @@ knative.dev/caching v0.0.0-20231108204433-b3781bc47aeb h1:9kuTebXS3SuSxWLGr/5epl knative.dev/caching v0.0.0-20231108204433-b3781bc47aeb/go.mod h1:owQX47ghEY9OIaxvoTZ9KyJTfEiwLgwY94tyHoUlLUU= knative.dev/hack v0.0.0-20231109190034-5deaddeb51a7 h1:HXf7M7n9jwn+Hp904r0HXRSymf+DLXSciFpXVpCg+Bs= knative.dev/hack v0.0.0-20231109190034-5deaddeb51a7/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q= -knative.dev/networking v0.0.0-20231108061732-e0bee342a97e h1:IFZuDN6IA3lzGt3zVgQ1VbTPSdDcCkdvD0SmxZ3blBM= -knative.dev/networking v0.0.0-20231108061732-e0bee342a97e/go.mod h1:cu01aODvz01sLC80d7Md6M8pSFi7RMurQnCubeeVH40= knative.dev/pkg v0.0.0-20231108014432-35011d423d4b h1:WrDo9M6vkJ4xnTBodWOT2koXjKqr7dOqJH4RWBq4kBw= knative.dev/pkg v0.0.0-20231108014432-35011d423d4b/go.mod h1:zkycL49skv31nWKvT1XAsSMFO6mUu33Qhpv0xDvdVGY= pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= diff --git a/pkg/activator/certificate/cache.go b/pkg/activator/certificate/cache.go index 4140b71d58b7..4ece6408c63c 100644 --- a/pkg/activator/certificate/cache.go +++ b/pkg/activator/certificate/cache.go @@ -21,6 +21,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/pem" + "fmt" "sync" "go.uber.org/zap" @@ -47,8 +48,8 @@ type CertCache struct { certificatesMux sync.RWMutex } -// NewCertCache starts secretInformer. -func NewCertCache(ctx context.Context) *CertCache { +// NewCertCache creates and starts the certificate cache that watches Activators certificate. +func NewCertCache(ctx context.Context) (*CertCache, error) { secretInformer := secretinformer.Get(ctx) cr := &CertCache{ @@ -58,8 +59,8 @@ func NewCertCache(ctx context.Context) *CertCache { secret, err := cr.secretInformer.Lister().Secrets(system.Namespace()).Get(netcfg.ServingRoutingCertName) if err != nil { - cr.logger.Warnw("failed to get secret", zap.Error(err)) - return nil + return nil, fmt.Errorf("failed to get activator certificate, secret %s/%s was not found: %w. Enabling system-internal-tls requires the secret to be present and populated with a valid certificate and CA", + system.Namespace(), netcfg.ServingRoutingCertName, err) } cr.updateCache(secret) @@ -72,7 +73,7 @@ func NewCertCache(ctx context.Context) *CertCache { }, }) - return cr + return cr, nil } func (cr *CertCache) handleCertificateAdd(added interface{}) { diff --git a/pkg/apis/serving/v1/route_lifecycle.go b/pkg/apis/serving/v1/route_lifecycle.go index 5a75031eb4f6..52653d114e20 100644 --- a/pkg/apis/serving/v1/route_lifecycle.go +++ b/pkg/apis/serving/v1/route_lifecycle.go @@ -195,11 +195,6 @@ const ( // RouteConditionCertificateProvisioned condition when it is set to True // because external-domain-tls was not enabled. ExternalDomainTLSNotEnabledMessage = "external-domain-tls is not enabled" - - // TLSNotEnabledForClusterLocalMessage is the message which is set on the - // RouteConditionCertificateProvisioned condition when it is set to True - // because the domain is cluster-local. - TLSNotEnabledForClusterLocalMessage = "TLS is not enabled for cluster-local" ) // MarkTLSNotEnabled sets RouteConditionCertificateProvisioned to true when diff --git a/pkg/queue/certificate/watcher_test.go b/pkg/queue/certificate/watcher_test.go index f5fea36e0381..6ecb94cd9f91 100644 --- a/pkg/queue/certificate/watcher_test.go +++ b/pkg/queue/certificate/watcher_test.go @@ -17,9 +17,15 @@ limitations under the License. package certificate import ( + "bytes" "context" + "crypto/rand" + "crypto/rsa" "crypto/tls" "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" "os" "testing" "time" @@ -94,26 +100,47 @@ func TestCertificateRotation(t *testing.T) { } func createAndSaveCertificate(san, dir string) error { - ca, err := certificates.CreateCACerts(1 * time.Hour) - if err != nil { - return err + cert := &x509.Certificate{ + SerialNumber: big.NewInt(2019), + Subject: pkix.Name{ + Organization: []string{"Knative"}, + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + IsCA: false, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, } + cert.DNSNames = []string{san} - caCert, caKey, err := ca.Parse() + pk, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { return err } - cert, err := certificates.CreateCert(caKey, caCert, 1*time.Hour, san) + certBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, &pk.PublicKey, pk) if err != nil { return err } - if err := os.WriteFile(dir+"/"+certificates.CertName, cert.CertBytes(), 0644); err != nil { + caPEM := new(bytes.Buffer) + pem.Encode(caPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + }) + + caPrivKeyPEM := new(bytes.Buffer) + pem.Encode(caPrivKeyPEM, &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(pk), + }) + + if err := os.WriteFile(dir+"/"+certificates.CertName, caPEM.Bytes(), 0644); err != nil { return err } - return os.WriteFile(dir+"/"+certificates.PrivateKeyName, cert.PrivateKeyBytes(), 0644) + return os.WriteFile(dir+"/"+certificates.PrivateKeyName, caPrivKeyPEM.Bytes(), 0644) } func getSAN(c *tls.Certificate) (string, error) { diff --git a/pkg/reconciler/accessor/networking/certificate.go b/pkg/reconciler/accessor/networking/certificate.go index d491e96869eb..d843175223c7 100644 --- a/pkg/reconciler/accessor/networking/certificate.go +++ b/pkg/reconciler/accessor/networking/certificate.go @@ -63,10 +63,15 @@ func ReconcileCertificate(ctx context.Context, owner kmeta.Accessor, desired *v1 return nil, kaccessor.NewAccessorError( fmt.Errorf("owner: %s with Type %T does not own Certificate: %q", owner.GetName(), owner, cert.Name), kaccessor.NotOwnResource) - } else if !equality.Semantic.DeepEqual(cert.Spec, desired.Spec) { + } else if !equality.Semantic.DeepEqual(cert.Spec, desired.Spec) || + !equality.Semantic.DeepEqual(cert.Annotations, desired.Annotations) || + !equality.Semantic.DeepEqual(cert.Labels, desired.Labels) { + // Don't modify the informers copy existing := cert.DeepCopy() existing.Spec = desired.Spec + existing.Annotations = desired.Annotations + existing.Labels = desired.Labels cert, err = certAccessor.GetNetworkingClient().NetworkingV1alpha1().Certificates(existing.Namespace).Update(ctx, existing, metav1.UpdateOptions{}) if err != nil { recorder.Eventf(owner, corev1.EventTypeWarning, "UpdateFailed", diff --git a/pkg/reconciler/domainmapping/reconciler.go b/pkg/reconciler/domainmapping/reconciler.go index 3a9dbfc23f90..eda8858ac35d 100644 --- a/pkg/reconciler/domainmapping/reconciler.go +++ b/pkg/reconciler/domainmapping/reconciler.go @@ -228,7 +228,7 @@ func (r *Reconciler) tls(ctx context.Context, dm *v1beta1.DomainMapping) ([]netv } if cert.IsReady() { dm.Status.MarkCertificateReady(cert.Name) - return []netv1alpha1.IngressTLS{routeresources.MakeIngressTLS(cert, desiredCert.Spec.DNSNames)}, nil, nil + return []netv1alpha1.IngressTLS{routeresources.MakeIngressTLS(cert, desiredCert.Spec.DNSNames, netv1alpha1.IngressVisibilityExternalIP)}, nil, nil } if config.FromContext(ctx).Network.HTTPProtocol == netcfg.HTTPEnabled { // When httpProtocol is enabled, downgrade http scheme. diff --git a/pkg/reconciler/domainmapping/resources/certificate_test.go b/pkg/reconciler/domainmapping/resources/certificate_test.go index 7145bc0ca061..aa5aaded703a 100644 --- a/pkg/reconciler/domainmapping/resources/certificate_test.go +++ b/pkg/reconciler/domainmapping/resources/certificate_test.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/networking/pkg/config" "knative.dev/networking/pkg/apis/networking" networkingv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1" @@ -58,7 +59,8 @@ func TestMakeCertificate(t *testing.T) { Namespace: "the-namespace", Annotations: map[string]string{networking.CertificateClassAnnotationKey: certClass}, Labels: map[string]string{ - serving.DomainMappingUIDLabelKey: "mapping.com", + serving.DomainMappingUIDLabelKey: "mapping.com", + networking.CertificateTypeLabelKey: string(config.CertificateExternalDomain), }, }, Spec: networkingv1alpha1.CertificateSpec{ @@ -96,7 +98,8 @@ func TestMakeCertificate(t *testing.T) { "others": "kept", }, Labels: map[string]string{ - serving.DomainMappingUIDLabelKey: "mapping.com", + serving.DomainMappingUIDLabelKey: "mapping.com", + networking.CertificateTypeLabelKey: string(config.CertificateExternalDomain), }, }, Spec: networkingv1alpha1.CertificateSpec{ diff --git a/pkg/reconciler/domainmapping/table_test.go b/pkg/reconciler/domainmapping/table_test.go index 65cad5ca667f..3b41c3e4cd38 100644 --- a/pkg/reconciler/domainmapping/table_test.go +++ b/pkg/reconciler/domainmapping/table_test.go @@ -967,6 +967,7 @@ func TestReconcileTLSEnabled(t *testing.T) { }, Labels: map[string]string{ serving.DomainMappingUIDLabelKey: "becomes.ready.run", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ @@ -997,6 +998,7 @@ func TestReconcileTLSEnabled(t *testing.T) { Hosts: []string{"becomes.ready.run"}, SecretName: "becomes.ready.run", SecretNamespace: "default", + Visibility: netv1alpha1.IngressVisibilityExternalIP, })), }}, WantPatches: []clientgotesting.PatchActionImpl{ @@ -1114,6 +1116,7 @@ func TestReconcileTLSEnabled(t *testing.T) { }, Labels: map[string]string{ serving.DomainMappingUIDLabelKey: "challenged.com", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ diff --git a/pkg/reconciler/revision/controller.go b/pkg/reconciler/revision/controller.go index 87a442a09cee..4318cec05968 100644 --- a/pkg/reconciler/revision/controller.go +++ b/pkg/reconciler/revision/controller.go @@ -26,6 +26,8 @@ import ( "golang.org/x/time/rate" cachingclient "knative.dev/caching/pkg/client/injection/client" imageinformer "knative.dev/caching/pkg/client/injection/informers/caching/v1alpha1/image" + networkingclient "knative.dev/networking/pkg/client/injection/client" + certificateinformer "knative.dev/networking/pkg/client/injection/informers/networking/v1alpha1/certificate" "knative.dev/pkg/changeset" kubeclient "knative.dev/pkg/client/injection/kube/client" deploymentinformer "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment" @@ -73,15 +75,18 @@ func newControllerWithOptions( deploymentInformer := deploymentinformer.Get(ctx) imageInformer := imageinformer.Get(ctx) paInformer := painformer.Get(ctx) + certificateInformer := certificateinformer.Get(ctx) c := &Reconciler{ - kubeclient: kubeclient.Get(ctx), - client: servingclient.Get(ctx), - cachingclient: cachingclient.Get(ctx), + kubeclient: kubeclient.Get(ctx), + client: servingclient.Get(ctx), + networkingclient: networkingclient.Get(ctx), + cachingclient: cachingclient.Get(ctx), podAutoscalerLister: paInformer.Lister(), imageLister: imageInformer.Lister(), deploymentLister: deploymentInformer.Lister(), + certificateLister: certificateInformer.Lister(), } impl := revisionreconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options { diff --git a/pkg/reconciler/revision/cruds.go b/pkg/reconciler/revision/cruds.go index 100591179019..2fe0a0a9f161 100644 --- a/pkg/reconciler/revision/cruds.go +++ b/pkg/reconciler/revision/cruds.go @@ -21,7 +21,6 @@ import ( "fmt" appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -31,7 +30,6 @@ import ( "knative.dev/pkg/logging" autoscalingv1alpha1 "knative.dev/serving/pkg/apis/autoscaling/v1alpha1" v1 "knative.dev/serving/pkg/apis/serving/v1" - "knative.dev/serving/pkg/networking" "knative.dev/serving/pkg/reconciler/revision/config" "knative.dev/serving/pkg/reconciler/revision/resources" ) @@ -48,20 +46,6 @@ func (c *Reconciler) createDeployment(ctx context.Context, rev *v1.Revision) (*a return c.kubeclient.AppsV1().Deployments(deployment.Namespace).Create(ctx, deployment, metav1.CreateOptions{}) } -func (c *Reconciler) createSecret(ctx context.Context, ns *corev1.Namespace) (*corev1.Secret, error) { - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: networking.ServingCertName, - Namespace: ns.Name, - OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(ns, corev1.SchemeGroupVersion.WithKind("Namespace"))}, - Labels: map[string]string{ - networking.ServingCertName + "-ctrl": "data-plane-user", - }, - }, - } - return c.kubeclient.CoreV1().Secrets(secret.Namespace).Create(ctx, secret, metav1.CreateOptions{}) -} - func (c *Reconciler) checkAndUpdateDeployment(ctx context.Context, rev *v1.Revision, have *appsv1.Deployment) (*appsv1.Deployment, error) { logger := logging.FromContext(ctx) cfgs := config.FromContext(ctx) diff --git a/pkg/reconciler/revision/reconcile_resources.go b/pkg/reconciler/revision/reconcile_resources.go index 1bef83c102b0..c40bf976f61b 100644 --- a/pkg/reconciler/revision/reconcile_resources.go +++ b/pkg/reconciler/revision/reconcile_resources.go @@ -21,6 +21,8 @@ import ( "fmt" "go.uber.org/zap" + kaccessor "knative.dev/serving/pkg/reconciler/accessor" + networkingaccessor "knative.dev/serving/pkg/reconciler/accessor/networking" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -28,6 +30,7 @@ import ( apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + networkingApi "knative.dev/networking/pkg/apis/networking" "knative.dev/networking/pkg/certificates" "knative.dev/pkg/kmeta" "knative.dev/pkg/kmp" @@ -35,6 +38,7 @@ import ( "knative.dev/pkg/logging/logkey" v1 "knative.dev/serving/pkg/apis/serving/v1" "knative.dev/serving/pkg/networking" + "knative.dev/serving/pkg/reconciler/revision/config" "knative.dev/serving/pkg/reconciler/revision/resources" resourcenames "knative.dev/serving/pkg/reconciler/revision/resources/names" ) @@ -206,31 +210,39 @@ func hasDeploymentTimedOut(deployment *appsv1.Deployment) bool { return false } -func (c *Reconciler) reconcileSecret(ctx context.Context, rev *v1.Revision) error { +func (c *Reconciler) reconcileQueueProxyCertificate(ctx context.Context, rev *v1.Revision) error { ns := rev.Namespace logger := logging.FromContext(ctx) - logger.Info("Reconciling Secret for system-internal-tls: ", networking.ServingCertName, " at namespace: ", ns) + logger.Infof("Reconciling queue-proxy Knative Certificate for system-internal-tls: %s/%s", ns, networking.ServingCertName) + certClass := config.FromContext(ctx).Network.DefaultCertificateClass + if class := networkingApi.GetCertificateClass(rev.Annotations); class != "" { + certClass = class + } + + desiredCert := resources.MakeQueueProxyCertificate(rev, certClass) + + _, err := networkingaccessor.ReconcileCertificate(ctx, rev, desiredCert, c) + if kaccessor.IsNotOwned(err) { + logger.Debugf("Skipping reconciling Knative certificate %s/%s as it already exists (from another Knative Service in the same namespace)", + ns, networking.ServingCertName) + } else if err != nil { + return fmt.Errorf("failed to reconcile Knative certificate %s/%s: %w", ns, networking.ServingCertName, err) + } + + // Verify the secret is created and has been added the certificates secret, err := c.kubeclient.CoreV1().Secrets(ns).Get(ctx, networking.ServingCertName, metav1.GetOptions{}) if apierrs.IsNotFound(err) { - namespace, err := c.kubeclient.CoreV1().Namespaces().Get(ctx, ns, metav1.GetOptions{}) - if err != nil { - return fmt.Errorf("failed to get Namespace %s: %w", ns, err) - } - if secret, err = c.createSecret(ctx, namespace); err != nil { - return fmt.Errorf("failed to create Secret %s/%s: %w", networking.ServingCertName, ns, err) - } - logger.Info("Created Secret: ", networking.ServingCertName, "at namespace: ", ns) + return fmt.Errorf("secret %s/%s is not ready yet: secret could not be found", ns, networking.ServingCertName) } else if err != nil { - return fmt.Errorf("failed to get secret %s/%s: %w", networking.ServingCertName, ns, err) + return fmt.Errorf("secret %s/%s is not ready yet: %w", ns, networking.ServingCertName, err) } - // Verify if secret has been added the data. if _, ok := secret.Data[certificates.CertName]; !ok { - return fmt.Errorf("public cert in the secret is not ready yet") + return fmt.Errorf("certificate in secret %s/%s is not ready yet: public cert not found", ns, networking.ServingCertName) } if _, ok := secret.Data[certificates.PrivateKeyName]; !ok { - return fmt.Errorf("private key in the secret is not ready yet") + return fmt.Errorf("certificate in secret %s/%s is not ready yet: private key not found", ns, networking.ServingCertName) } return nil diff --git a/pkg/reconciler/revision/resources/certificate.go b/pkg/reconciler/revision/resources/certificate.go new file mode 100644 index 000000000000..357814b16d82 --- /dev/null +++ b/pkg/reconciler/revision/resources/certificate.go @@ -0,0 +1,53 @@ +/* +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 resources + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/networking/pkg/apis/networking" + "knative.dev/networking/pkg/apis/networking/v1alpha1" + "knative.dev/networking/pkg/certificates" + "knative.dev/networking/pkg/config" + "knative.dev/pkg/kmeta" + v1 "knative.dev/serving/pkg/apis/serving/v1" + servingnetworking "knative.dev/serving/pkg/networking" +) + +// MakeQueueProxyCertificate creates a KnativeCertificate to be used by Queue-Proxy for system-internal-tls. +func MakeQueueProxyCertificate(rev *v1.Revision, certClass string) *v1alpha1.Certificate { + return &v1alpha1.Certificate{ + ObjectMeta: metav1.ObjectMeta{ + Name: servingnetworking.ServingCertName, + Namespace: rev.Namespace, + OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef(rev)}, + Annotations: map[string]string{ + networking.CertificateClassAnnotationKey: certClass, + }, + Labels: map[string]string{ + networking.CertificateTypeLabelKey: string(config.CertificateSystemInternal), + }, + }, + Spec: v1alpha1.CertificateSpec{ + DNSNames: []string{ + certificates.DataPlaneUserSAN(rev.Namespace), + // added for reverse-compatibility with net-* implementations that do not work with multi-SANs + certificates.LegacyFakeDnsName, + }, + SecretName: servingnetworking.ServingCertName, + }, + } +} diff --git a/pkg/reconciler/revision/revision.go b/pkg/reconciler/revision/revision.go index d4228b8a8838..44a4e77e488a 100644 --- a/pkg/reconciler/revision/revision.go +++ b/pkg/reconciler/revision/revision.go @@ -25,17 +25,21 @@ import ( "github.com/google/go-containerregistry/pkg/authn/k8schain" "go.uber.org/zap" "go.uber.org/zap/zapcore" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/kubernetes" appsv1listers "k8s.io/client-go/listers/apps/v1" cachingclientset "knative.dev/caching/pkg/client/clientset/versioned" + networkingclientset "knative.dev/networking/pkg/client/clientset/versioned" + "knative.dev/networking/pkg/client/listers/networking/v1alpha1" clientset "knative.dev/serving/pkg/client/clientset/versioned" + revisionreconciler "knative.dev/serving/pkg/client/injection/reconciler/serving/v1/revision" cachinglisters "knative.dev/caching/pkg/client/listers/caching/v1alpha1" + networkinglisters "knative.dev/networking/pkg/client/listers/networking/v1alpha1" + "knative.dev/pkg/controller" "knative.dev/pkg/logging" pkgreconciler "knative.dev/pkg/reconciler" @@ -52,14 +56,16 @@ type resolver interface { // Reconciler implements controller.Reconciler for Revision resources. type Reconciler struct { - kubeclient kubernetes.Interface - client clientset.Interface - cachingclient cachingclientset.Interface + kubeclient kubernetes.Interface + client clientset.Interface + networkingclient networkingclientset.Interface + cachingclient cachingclientset.Interface // lister indexes properties about Revision podAutoscalerLister palisters.PodAutoscalerLister imageLister cachinglisters.ImageLister deploymentLister appsv1listers.DeploymentLister + certificateLister networkinglisters.CertificateLister resolver resolver } @@ -138,9 +144,9 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, rev *v1.Revision) pkgrec logger.Debug("Revision meta: " + spew.Sdump(rev.ObjectMeta)) } - // Deploy certificate when system-internal-tls is enabled. + // Deploy Knative Certificate for queue-proxy when system-internal-tls is enabled. if config.FromContext(ctx).Network.SystemInternalTLSEnabled() { - if err := c.reconcileSecret(ctx, rev); err != nil { + if err := c.reconcileQueueProxyCertificate(ctx, rev); err != nil { return err } } @@ -184,3 +190,11 @@ func (c *Reconciler) ObserveDeletion(ctx context.Context, key types.NamespacedNa c.resolver.Forget(key) return nil } + +func (c *Reconciler) GetNetworkingClient() networkingclientset.Interface { + return c.networkingclient +} + +func (c *Reconciler) GetCertificateLister() v1alpha1.CertificateLister { + return c.certificateLister +} diff --git a/pkg/reconciler/revision/revision_test.go b/pkg/reconciler/revision/revision_test.go index 462cff4e8581..d93e654da6e3 100644 --- a/pkg/reconciler/revision/revision_test.go +++ b/pkg/reconciler/revision/revision_test.go @@ -28,6 +28,7 @@ import ( "go.uber.org/zap" fakecachingclient "knative.dev/caching/pkg/client/injection/client/fake" fakeimageinformer "knative.dev/caching/pkg/client/injection/informers/caching/v1alpha1/image/fake" + _ "knative.dev/networking/pkg/client/injection/informers/networking/v1alpha1/certificate/fake" fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" fakedeploymentinformer "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment/fake" _ "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap/fake" diff --git a/pkg/reconciler/route/domains/domains.go b/pkg/reconciler/route/domains/domains.go index 0ca76e1931a4..deebac2f77c4 100644 --- a/pkg/reconciler/route/domains/domains.go +++ b/pkg/reconciler/route/domains/domains.go @@ -24,11 +24,13 @@ import ( "text/template" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" netapi "knative.dev/networking/pkg/apis/networking" netv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1" netcfg "knative.dev/networking/pkg/config" + "knative.dev/networking/pkg/ingress" "knative.dev/pkg/apis" pkgnet "knative.dev/pkg/network" "knative.dev/serving/pkg/apis/serving" @@ -63,6 +65,28 @@ func GetAllDomainsAndTags(ctx context.Context, r *v1.Route, names []string, visi return domainTagMap, nil } +// GetDomainsForVisibility return all domains for the specified visibility. +func GetDomainsForVisibility(ctx context.Context, targetName string, r *v1.Route, visibility netv1alpha1.IngressVisibility) (sets.String, error) { + hostname, err := HostnameFromTemplate(ctx, r.Name, targetName) + if err != nil { + return nil, err + } + + meta := r.ObjectMeta.DeepCopy() + isClusterLocal := visibility == netv1alpha1.IngressVisibilityClusterLocal + labels.SetVisibility(meta, isClusterLocal) + + domain, err := DomainNameFromTemplate(ctx, *meta, hostname) + if err != nil { + return nil, err + } + domains := []string{domain} + if isClusterLocal { + domains = ingress.ExpandedHosts(sets.NewString(domains...)).List() + } + return sets.NewString(domains...), err +} + // DomainNameFromTemplate generates domain name base on the template specified in the `config-network` ConfigMap. // name is the "subdomain" which will be referred as the "name" in the template func DomainNameFromTemplate(ctx context.Context, r metav1.ObjectMeta, name string) (string, error) { diff --git a/pkg/reconciler/route/resources/certificate.go b/pkg/reconciler/route/resources/certificate.go index 959ad17a86d1..086f0b9d1e4f 100644 --- a/pkg/reconciler/route/resources/certificate.go +++ b/pkg/reconciler/route/resources/certificate.go @@ -21,7 +21,11 @@ import ( "hash/adler32" "sort" + "k8s.io/apimachinery/pkg/util/sets" "knative.dev/networking/pkg/apis/networking" + "knative.dev/networking/pkg/config" + "knative.dev/pkg/kmap" + "knative.dev/pkg/network" "knative.dev/serving/pkg/apis/serving" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -31,6 +35,10 @@ import ( "knative.dev/serving/pkg/reconciler/route/resources/names" ) +const ( + localDomainSuffix = "-local" +) + // MakeCertificate creates a Certificate, inheriting the certClass // annotations from the owner, as well as the namespaces. If owner // does not have a certClass, use the provided `certClass` parameter. @@ -45,7 +53,8 @@ func MakeCertificate(owner kmeta.OwnerRefableAccessor, ownerLabelKey string, dns networking.CertificateClassAnnotationKey: certClass, }, owner.GetAnnotations()), ExcludedAnnotations.Has), Labels: map[string]string{ - ownerLabelKey: owner.GetName(), + ownerLabelKey: owner.GetName(), + networking.CertificateTypeLabelKey: string(config.CertificateExternalDomain), }, }, Spec: networkingv1alpha1.CertificateSpec{ @@ -72,17 +81,53 @@ func MakeCertificates(route *v1.Route, domainTagMap map[string]string, certClass certs := make([]*networkingv1alpha1.Certificate, 0, len(order)) for _, dnsName := range order { tag := domainTagMap[dnsName] - - // k8s supports cert name only up to 63 chars and so is constructed as route-[UID]-[tag digest] - // where route-[UID] will take 42 characters and leaves 20 characters for tag digest (need to include `-`). - // We use https://golang.org/pkg/hash/adler32/#Checksum to compute the digest which returns a uint32. - // We represent the digest in unsigned integer format with maximum value of 4,294,967,295 which are 10 digits. - // The "-[tag digest]" is computed only if there's a tag - certName := names.Certificate(route) - if tag != "" { - certName += fmt.Sprint("-", adler32.Checksum([]byte(tag))) - } - certs = append(certs, MakeCertificate(route, serving.RouteLabelKey, dnsName, certName, certClass, domain)) + certs = append(certs, MakeCertificate(route, serving.RouteLabelKey, dnsName, certNameFromRouteAndTag(route, tag), certClass, domain)) } return certs } + +// MakeClusterLocalCertificate creates a Knative Certificate +// for cluster-local-domain-tls. +func MakeClusterLocalCertificate(route *v1.Route, tag string, domains sets.String, certClass string) *networkingv1alpha1.Certificate { + domainsOrdered := make(sort.StringSlice, 0, len(domains)) + for dnsName := range domains { + domainsOrdered = append(domainsOrdered, dnsName) + } + domainsOrdered.Sort() + + certName := certNameFromRouteAndTag(route, tag) + localDomainSuffix + + return &networkingv1alpha1.Certificate{ + ObjectMeta: metav1.ObjectMeta{ + Name: certName, + Namespace: route.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef(route)}, + Annotations: kmap.Filter(kmap.Union(map[string]string{ + networking.CertificateClassAnnotationKey: certClass, + }, route.GetAnnotations()), ExcludedAnnotations.Has), + Labels: map[string]string{ + serving.RouteLabelKey: route.GetName(), + networking.CertificateTypeLabelKey: string(config.CertificateClusterLocalDomain), + }, + }, + Spec: networkingv1alpha1.CertificateSpec{ + DNSNames: domainsOrdered, + Domain: "svc." + network.GetClusterDomainName(), + SecretName: certName, + }, + } +} + +// certNameFromRouteAndTag returns a possibly shortended certName as +// k8s supports cert name only up to 63 chars and so is constructed as route-[UID]-[tag digest] +// where route-[UID] will take 42 characters and leaves 20 characters for tag digest (need to include `-`). +// We use https://golang.org/pkg/hash/adler32/#Checksum to compute the digest which returns a uint32. +// We represent the digest in unsigned integer format with maximum value of 4,294,967,295 which are 10 digits. +// The "-[tag digest]" is computed only if there's a tag +func certNameFromRouteAndTag(route *v1.Route, tag string) string { + certName := names.Certificate(route) + if tag != "" { + certName += fmt.Sprint("-", adler32.Checksum([]byte(tag))) + } + return certName +} diff --git a/pkg/reconciler/route/resources/certificate_test.go b/pkg/reconciler/route/resources/certificate_test.go index ab86deb6d41d..671ed147e9bb 100644 --- a/pkg/reconciler/route/resources/certificate_test.go +++ b/pkg/reconciler/route/resources/certificate_test.go @@ -20,6 +20,7 @@ import ( "testing" "knative.dev/networking/pkg/apis/networking" + "knative.dev/networking/pkg/config" "knative.dev/serving/pkg/apis/serving" "knative.dev/pkg/kmeta" @@ -52,7 +53,8 @@ func TestMakeCertificates(t *testing.T) { networking.CertificateClassAnnotationKey: "foo-cert", }, Labels: map[string]string{ - serving.RouteLabelKey: "route", + serving.RouteLabelKey: "route", + networking.CertificateTypeLabelKey: string(config.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ @@ -70,7 +72,8 @@ func TestMakeCertificates(t *testing.T) { networking.CertificateClassAnnotationKey: "foo-cert", }, Labels: map[string]string{ - serving.RouteLabelKey: "route", + serving.RouteLabelKey: "route", + networking.CertificateTypeLabelKey: string(config.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ @@ -99,7 +102,8 @@ func TestMakeCertificates_FilterLastAppliedAnno(t *testing.T) { networking.CertificateClassAnnotationKey: "passdown-cert", }, Labels: map[string]string{ - serving.RouteLabelKey: "route", + serving.RouteLabelKey: "route", + networking.CertificateTypeLabelKey: string(config.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ @@ -117,7 +121,8 @@ func TestMakeCertificates_FilterLastAppliedAnno(t *testing.T) { networking.CertificateClassAnnotationKey: "passdown-cert", }, Labels: map[string]string{ - serving.RouteLabelKey: "route", + serving.RouteLabelKey: "route", + networking.CertificateTypeLabelKey: string(config.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ diff --git a/pkg/reconciler/route/resources/ingress.go b/pkg/reconciler/route/resources/ingress.go index 4d866c5ea846..4422763136ea 100644 --- a/pkg/reconciler/route/resources/ingress.go +++ b/pkg/reconciler/route/resources/ingress.go @@ -26,11 +26,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" + "knative.dev/serving/pkg/reconciler/route/domains" "knative.dev/networking/pkg/apis/networking" netv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1" netheader "knative.dev/networking/pkg/http/header" - ingress "knative.dev/networking/pkg/ingress" "knative.dev/pkg/kmeta" "knative.dev/pkg/logging" "knative.dev/serving/pkg/activator" @@ -39,16 +39,15 @@ import ( servingv1 "knative.dev/serving/pkg/apis/serving/v1" servingnetworking "knative.dev/serving/pkg/networking" "knative.dev/serving/pkg/reconciler/route/config" - "knative.dev/serving/pkg/reconciler/route/domains" - "knative.dev/serving/pkg/reconciler/route/resources/labels" "knative.dev/serving/pkg/reconciler/route/resources/names" "knative.dev/serving/pkg/reconciler/route/traffic" ) // MakeIngressTLS creates IngressTLS to configure the ingress TLS. -func MakeIngressTLS(cert *netv1alpha1.Certificate, hostNames []string) netv1alpha1.IngressTLS { +func MakeIngressTLS(cert *netv1alpha1.Certificate, hostNames []string, visibility netv1alpha1.IngressVisibility) netv1alpha1.IngressTLS { return netv1alpha1.IngressTLS{ Hosts: hostNames, + Visibility: visibility, SecretName: cert.Spec.SecretName, SecretNamespace: cert.Namespace, } @@ -144,7 +143,7 @@ func makeIngressSpec( visibilities = append(visibilities, netv1alpha1.IngressVisibilityExternalIP) } for _, visibility := range visibilities { - domains, err := routeDomain(ctx, name, r, visibility) + domains, err := domains.GetDomainsForVisibility(ctx, name, r, visibility) if err != nil { return netv1alpha1.IngressSpec{}, err } @@ -205,27 +204,6 @@ func makeIngressSpec( }, nil } -func routeDomain(ctx context.Context, targetName string, r *servingv1.Route, visibility netv1alpha1.IngressVisibility) (sets.String, error) { - hostname, err := domains.HostnameFromTemplate(ctx, r.Name, targetName) - if err != nil { - return nil, err - } - - meta := r.ObjectMeta.DeepCopy() - isClusterLocal := visibility == netv1alpha1.IngressVisibilityClusterLocal - labels.SetVisibility(meta, isClusterLocal) - - domain, err := domains.DomainNameFromTemplate(ctx, *meta, hostname) - if err != nil { - return nil, err - } - domains := []string{domain} - if isClusterLocal { - domains = ingress.ExpandedHosts(sets.NewString(domains...)).List() - } - return sets.NewString(domains...), err -} - // MakeACMEIngressPaths returns a set of netv1alpha1.HTTPIngressPath // that can be used to perform ACME challenges. func MakeACMEIngressPaths(acmeChallenges []netv1alpha1.HTTP01Challenge, domains sets.String) ([]netv1alpha1.HTTPIngressPath, []string) { diff --git a/pkg/reconciler/route/resources/ingress_test.go b/pkg/reconciler/route/resources/ingress_test.go index f268ba72f2d6..f99603077bbe 100644 --- a/pkg/reconciler/route/resources/ingress_test.go +++ b/pkg/reconciler/route/resources/ingress_test.go @@ -1228,9 +1228,10 @@ func TestMakeIngressTLS(t *testing.T) { Hosts: []string{"test.default.example.com", "v1.test.default.example.com"}, SecretName: "route-1234", SecretNamespace: system.Namespace(), + Visibility: netv1alpha1.IngressVisibilityExternalIP, } hostNames := []string{"test.default.example.com", "v1.test.default.example.com"} - got := MakeIngressTLS(cert, hostNames) + got := MakeIngressTLS(cert, hostNames, netv1alpha1.IngressVisibilityExternalIP) if diff := cmp.Diff(want, got); diff != "" { t.Error("Unexpected IngressTLS (-want, +got):", diff) } diff --git a/pkg/reconciler/route/route.go b/pkg/reconciler/route/route.go index 22b170c56a53..5f33a23b3def 100644 --- a/pkg/reconciler/route/route.go +++ b/pkg/reconciler/route/route.go @@ -137,10 +137,19 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, r *v1.Route) pkgreconcil return err } - tls, acmeChallenges, err := c.tls(ctx, r.Status.URL.Host, r, traffic) + tls, acmeChallenges, err := c.externalDomainTLS(ctx, r.Status.URL.Host, r, traffic) if err != nil { return err } + + if config.FromContext(ctx).Network.ClusterLocalDomainTLS == netcfg.EncryptionEnabled { + internalTLS, err := c.clusterLocalDomainTLS(ctx, r, traffic) + if err != nil { + return err + } + tls = append(tls, internalTLS...) + } + // Reconcile ingress and its children resources. ingress, effectiveRO, err := c.reconcileIngress(ctx, r, traffic, tls, ingressClassForRoute(ctx, r), acmeChallenges...) if err != nil { @@ -180,7 +189,7 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, r *v1.Route) pkgreconcil return nil } -func (c *Reconciler) tls(ctx context.Context, host string, r *v1.Route, traffic *traffic.Config) ([]netv1alpha1.IngressTLS, []netv1alpha1.HTTP01Challenge, error) { +func (c *Reconciler) externalDomainTLS(ctx context.Context, host string, r *v1.Route, traffic *traffic.Config) ([]netv1alpha1.IngressTLS, []netv1alpha1.HTTP01Challenge, error) { logger := logging.FromContext(ctx) tls := []netv1alpha1.IngressTLS{} @@ -195,8 +204,8 @@ func (c *Reconciler) tls(ctx context.Context, host string, r *v1.Route, traffic } for domain := range domainToTagMap { + // Ignore cluster local domains here, as their TLS is handled in clusterLocalDomainTLS() if domains.IsClusterLocal(domain) { - r.Status.MarkTLSNotEnabled(v1.TLSNotEnabledForClusterLocalMessage) delete(domainToTagMap, domain) } } @@ -262,7 +271,7 @@ func (c *Reconciler) tls(ctx context.Context, host string, r *v1.Route, traffic } } r.Status.MarkCertificateReady(cert.Name) - tls = append(tls, resources.MakeIngressTLS(cert, dnsNames.List())) + tls = append(tls, resources.MakeIngressTLS(cert, dnsNames.List(), netv1alpha1.IngressVisibilityExternalIP)) } else { acmeChallenges = append(acmeChallenges, cert.Status.HTTP01Challenges...) r.Status.MarkCertificateNotReady(cert) @@ -285,28 +294,69 @@ func (c *Reconciler) tls(ctx context.Context, host string, r *v1.Route, traffic return acmeChallenges[i].URL.String() < acmeChallenges[j].URL.String() }) - orphanCerts, err := c.getOrphanRouteCerts(r, domainToTagMap) + orphanCerts, err := c.getOrphanRouteCerts(r, domainToTagMap, netcfg.CertificateExternalDomain) if err != nil { return nil, nil, err } - recorder := controller.GetEventRecorder(ctx) - for _, cert := range orphanCerts { - err = c.GetNetworkingClient().NetworkingV1alpha1().Certificates(cert.Namespace).Delete(ctx, cert.Name, metav1.DeleteOptions{}) + c.deleteOrphanedCerts(ctx, orphanCerts) + + return tls, acmeChallenges, nil +} + +func (c *Reconciler) clusterLocalDomainTLS(ctx context.Context, r *v1.Route, tc *traffic.Config) ([]netv1alpha1.IngressTLS, error) { + tls := []netv1alpha1.IngressTLS{} + usedDomains := make(map[string]string) + + for name := range tc.Targets { + localDomains, err := domains.GetDomainsForVisibility(ctx, name, r, netv1alpha1.IngressVisibilityClusterLocal) if err != nil { - recorder.Eventf(cert, corev1.EventTypeNormal, "DeleteFailed", - "Failed to delete orphaned Knative Certificate %s/%s: %v", cert.Namespace, cert.Name, err) + return nil, err + } + + desiredCert := resources.MakeClusterLocalCertificate(r, name, localDomains, certClass(ctx, r)) + cert, err := networkaccessor.ReconcileCertificate(ctx, r, desiredCert, c) + if err != nil { + if kaccessor.IsNotOwned(err) { + r.Status.MarkCertificateNotOwned(desiredCert.Name) + } else { + r.Status.MarkCertificateProvisionFailed(desiredCert.Name) + } + return nil, err + } + + if cert.IsReady() { + r.Status.Address.URL.Scheme = "https" + + // r.Status.URL contains the major domain, + // so only change if the cert is for the major domain + if localDomains.Has(r.Status.URL.Host) { + r.Status.URL.Scheme = "https" + } + + r.Status.MarkCertificateReady(cert.Name) + tls = append(tls, resources.MakeIngressTLS(cert, localDomains.List(), netv1alpha1.IngressVisibilityClusterLocal)) } else { - recorder.Eventf(cert, corev1.EventTypeNormal, "Deleted", - "Deleted orphaned Knative Certificate %s/%s", cert.Namespace, cert.Name) + r.Status.MarkCertificateNotReady(cert) + } + + for s, _ := range localDomains { + usedDomains[s] = s } } - return tls, acmeChallenges, nil + orphanCerts, err := c.getOrphanRouteCerts(r, usedDomains, netcfg.CertificateClusterLocalDomain) + if err != nil { + return nil, nil + } + + c.deleteOrphanedCerts(ctx, orphanCerts) + + return tls, nil } -// Returns a slice of certificates that used to belong route's old tags and are currently not in use. -func (c *Reconciler) getOrphanRouteCerts(r *v1.Route, domainToTagMap map[string]string) ([]*netv1alpha1.Certificate, error) { +// Returns a slice of certificates that used to belong route's old domains/tags for a specific visibility that are currently not in use. +func (c *Reconciler) getOrphanRouteCerts(r *v1.Route, domainToTagMap map[string]string, certificateType netcfg.CertificateType) ([]*netv1alpha1.Certificate, error) { labelSelector := kubelabels.SelectorFromSet(kubelabels.Set{ serving.RouteLabelKey: r.Name, }) @@ -318,21 +368,37 @@ func (c *Reconciler) getOrphanRouteCerts(r *v1.Route, domainToTagMap map[string] var unusedCerts []*netv1alpha1.Certificate for _, cert := range certs { - var shouldKeepCert bool - for _, dn := range cert.Spec.DNSNames { - if _, used := domainToTagMap[dn]; used { - shouldKeepCert = true + if v, ok := cert.ObjectMeta.Labels[networking.CertificateTypeLabelKey]; ok && v == string(certificateType) { + var shouldKeepCert bool + for _, dn := range cert.Spec.DNSNames { + if _, used := domainToTagMap[dn]; used { + shouldKeepCert = true + } } - } - if !shouldKeepCert { - unusedCerts = append(unusedCerts, cert) + if !shouldKeepCert { + unusedCerts = append(unusedCerts, cert) + } } } return unusedCerts, nil } +func (c *Reconciler) deleteOrphanedCerts(ctx context.Context, orphanCerts []*netv1alpha1.Certificate) { + recorder := controller.GetEventRecorder(ctx) + for _, cert := range orphanCerts { + err := c.GetNetworkingClient().NetworkingV1alpha1().Certificates(cert.Namespace).Delete(ctx, cert.Name, metav1.DeleteOptions{}) + if err != nil { + recorder.Eventf(cert, corev1.EventTypeNormal, "DeleteFailed", + "Failed to delete orphaned Knative Certificate %s/%s: %v", cert.Namespace, cert.Name, err) + } else { + recorder.Eventf(cert, corev1.EventTypeNormal, "Deleted", + "Deleted orphaned Knative Certificate %s/%s", cert.Namespace, cert.Name) + } + } +} + // configureTraffic attempts to configure traffic based on the RouteSpec. If there are missing // targets (e.g. Configurations without a Ready Revision, or Revision that isn't Ready or Inactive), // no traffic will be configured. diff --git a/pkg/reconciler/route/table_test.go b/pkg/reconciler/route/table_test.go index d96b647aacd0..572f4cb938cf 100644 --- a/pkg/reconciler/route/table_test.go +++ b/pkg/reconciler/route/table_test.go @@ -2373,6 +2373,7 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { Hosts: []string{"becomes-ready.default.example.com"}, SecretName: "default", SecretNamespace: "default", + Visibility: netv1alpha1.IngressVisibilityExternalIP, }}, nil, ), @@ -2480,6 +2481,7 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { Hosts: []string{"becomes-ready.default.example.com"}, SecretName: "route-12-34", SecretNamespace: "default", + Visibility: netv1alpha1.IngressVisibilityExternalIP, }}, nil, ), @@ -2526,7 +2528,8 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { netapi.CertificateClassAnnotationKey: netcfg.CertManagerCertificateClassName, }, Labels: map[string]string{ - serving.RouteLabelKey: "becomes-ready", + serving.RouteLabelKey: "becomes-ready", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ @@ -2555,6 +2558,7 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { Hosts: []string{"becomes-ready.default.example.com"}, SecretName: "route-12-34", SecretNamespace: "default", + Visibility: netv1alpha1.IngressVisibilityExternalIP, }}, nil, ), @@ -2611,7 +2615,8 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef( Route("default", "becomes-ready", WithConfigTarget("config"), WithRouteUID("12-34")))}, Labels: map[string]string{ - serving.RouteLabelKey: "becomes-ready", + serving.RouteLabelKey: "becomes-ready", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, Annotations: map[string]string{ netapi.CertificateClassAnnotationKey: netcfg.CertManagerCertificateClassName, @@ -2631,7 +2636,8 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef( Route("default", "becomes-ready", WithConfigTarget("config"), WithRouteUID("12-34")))}, Labels: map[string]string{ - serving.RouteLabelKey: "becomes-ready", + serving.RouteLabelKey: "becomes-ready", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, Annotations: map[string]string{ netapi.CertificateClassAnnotationKey: netcfg.CertManagerCertificateClassName, @@ -2651,7 +2657,8 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef( Route("default", "becomes-ready", WithConfigTarget("config"), WithRouteUID("12-34")))}, Labels: map[string]string{ - serving.RouteLabelKey: "becomes-ready", + serving.RouteLabelKey: "becomes-ready", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, Annotations: map[string]string{ netapi.CertificateClassAnnotationKey: netcfg.CertManagerCertificateClassName, @@ -2683,6 +2690,7 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { Hosts: []string{"becomes-ready.default.example.com"}, SecretName: "route-12-34", SecretNamespace: "default", + Visibility: netv1alpha1.IngressVisibilityExternalIP, }}, nil, ), @@ -2741,7 +2749,8 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { netapi.CertificateClassAnnotationKey: netcfg.CertManagerCertificateClassName, }, Labels: map[string]string{ - serving.RouteLabelKey: "becomes-ready", + serving.RouteLabelKey: "becomes-ready", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ @@ -2863,7 +2872,8 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { netapi.CertificateClassAnnotationKey: netcfg.CertManagerCertificateClassName, }, Labels: map[string]string{ - serving.RouteLabelKey: "becomes-ready", + serving.RouteLabelKey: "becomes-ready", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, }, Spec: netv1alpha1.CertificateSpec{ @@ -2927,6 +2937,7 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { Hosts: []string{"becomes-ready.default.example.com"}, SecretName: "route-12-34", SecretNamespace: "default", + Visibility: netv1alpha1.IngressVisibilityExternalIP, }}, nil, withReadyIngress, @@ -2965,6 +2976,7 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { Hosts: []string{"becomes-ready.default.example.com"}, SecretName: "route-12-34", SecretNamespace: "default", + Visibility: netv1alpha1.IngressVisibilityExternalIP, }}, []netv1alpha1.HTTP01Challenge{{ URL: &apis.URL{ @@ -3053,7 +3065,8 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef( Route("default", "becomes-ready", WithConfigTarget("config"), WithRouteUID("12-34")))}, Labels: map[string]string{ - serving.RouteLabelKey: "becomes-ready", + serving.RouteLabelKey: "becomes-ready", + netapi.CertificateTypeLabelKey: string(netcfg.CertificateExternalDomain), }, Annotations: map[string]string{ netapi.CertificateClassAnnotationKey: netcfg.CertManagerCertificateClassName, @@ -3175,7 +3188,7 @@ func TestReconcileEnableExternalDomainTLS(t *testing.T) { Object: Route("default", "becomes-local", WithConfigTarget("config"), WithRouteUID("65-23"), WithRouteGeneration(1), WithRouteObservedGeneration, - MarkTrafficAssigned, MarkIngressNotConfigured, WithRouteConditionsTLSNotEnabledForClusterLocalMessage, + MarkTrafficAssigned, MarkIngressNotConfigured, WithLocalDomain, WithAddress, WithInitRouteConditions, WithRouteLabel(map[string]string{netapi.VisibilityLabelKey: serving.VisibilityClusterLocal}), WithStatusTraffic( diff --git a/pkg/testing/v1/route.go b/pkg/testing/v1/route.go index 429f4f861cb5..9f2a60987414 100644 --- a/pkg/testing/v1/route.go +++ b/pkg/testing/v1/route.go @@ -180,14 +180,6 @@ func WithRouteConditionsExternalDomainTLSDisabled(rt *v1.Route) { rt.Status.MarkTLSNotEnabled(v1.ExternalDomainTLSNotEnabledMessage) } -// WithRouteConditionsTLSNotEnabledForClusterLocalMessage calls -// MarkTLSNotEnabled with TLSNotEnabledForClusterLocalMessage after initialized -// the Service's conditions. -func WithRouteConditionsTLSNotEnabledForClusterLocalMessage(rt *v1.Route) { - rt.Status.InitializeConditions() - rt.Status.MarkTLSNotEnabled(v1.TLSNotEnabledForClusterLocalMessage) -} - // WithRouteConditionsHTTPDowngrade calls MarkHTTPDowngrade after initialized the Service's conditions. func WithRouteConditionsHTTPDowngrade(rt *v1.Route) { rt.Status.InitializeConditions() diff --git a/test/config/tls/cert-secret.yaml b/test/config/tls/cert-secret.yaml deleted file mode 100644 index 7800c91f4728..000000000000 --- a/test/config/tls/cert-secret.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2022 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. - -apiVersion: v1 -kind: Secret -metadata: - name: ca-cert - namespace: serving-tests -data: - ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURSVENDQWkyZ0F3SUJBZ0lVS0lNbmZTUUpTRHgyVThWYU1UdjR2cnYwcnRrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd01qRWFNQmdHQTFVRUNnd1JTMjVoZEdsMlpTQkRiMjF0ZFc1cGRIa3hGREFTQmdOVkJBTU1DMlY0WVcxdwpiR1V1WTI5dE1CNFhEVEl6TURrd01UQXpNRGd4TkZvWERUTXpNRGd5T1RBek1EZ3hORm93TWpFYU1CZ0dBMVVFCkNnd1JTMjVoZEdsMlpTQkRiMjF0ZFc1cGRIa3hGREFTQmdOVkJBTU1DMlY0WVcxd2JHVXVZMjl0TUlJQklqQU4KQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBak83alk0bysvSTRZYnQ3ZjlwWWt3ZkJnSG4yQQpiSThvWWRxczg1UGlxaThsWm1lOXM4ZmhBcnJjbGJPcEZPTEwrTUJHWEVCSkxEMUNTN2VaWS9HQ0E1VkZYdkMzCkpjR0VjNmVZY2l0ZnNtdlh3bWk1bm1oVFovajdZSkNRNGZzS29KNkQ3Q1YzS2ZBVEhUTmsxUXVFbWpmUmRBNjEKS01tVkZSMVlpM0NWT1FNSzFhSHhRaEJ3TFRMbERQbVZkaHYvdDI0aDZFL0cwZHNTSGhodUI2aGgzOEoybFBPYwpyTjBOVFhFQ25JZ1hOZHNlMzVEVi9yQlZYUUhlQlRjQ1dqSElBdFQybUxPWWRxZ0dBdE1rYTZDRCtpaXVFemY4CjYyZGdOUjRoS1ErVTR4Q3FBOXNoRExqWVdKS2FMRFFPMFRKOXF5aTR4RTBZSVZETUFHMzhqakU3d1FJREFRQUIKbzFNd1VUQWRCZ05WSFE0RUZnUVVtTXVLSjEyaDBBQmRmT0hnRDhWU2ROVUpjQm93SHdZRFZSMGpCQmd3Rm9BVQptTXVLSjEyaDBBQmRmT0hnRDhWU2ROVUpjQm93RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCCkFRc0ZBQU9DQVFFQWlNRnByYVVqOWRrMDBpUlFRUi9vV1FHSks0c3VNWnJRT3hUNjMycThac1RmaGRoRWVwNUQKbk9wNCs0UnBJTWpPQVN0SnNIbWRNMXBYUkJiUFp4WnhQSjd4Z0pVQmdycE1JS3k2SmZoZU1aaGVnR1AvUmFFbwpXR3pPTzlSZER0Q3M4azRVUzVHeGJSUUVXWVV1dDlGUGhGL1RlaFdXS1RvOWFVMTUwakVyclNseFYwRkUxVzBtCitPUFBDOUVtV24vUHhVWXNKSitHalAwSENDTENMUU1tR2VZN0Y1TkVVWUtobFo4UnBISFdBaE54RXM1WSszUU4KakNVY1JvQ2RRaTBrS3NZYytheUp6Yi9hRVJQdTJlQStNVVpqM1pxMTlqenY4RzRseVlETmpleTZSdlBxV21XZQpHcmZpN2JpS21oSlNLWU5US1pRaHVWeTdEcUVkNUl5VWZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= ---- -apiVersion: v1 -kind: Secret -metadata: - name: server-certs - namespace: knative-serving -data: - tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRQ3Bmd09tY21qMGZZNTQKSzg4SkxSWVh0MGt3Z3NNN2VTVEZGNWg5ZG5QYmk5KzIrRDRQYjgwN3F5cXZ3aEIzYTM0V215ZVpvOTAxS3BxeQp6TzNaR2VmVVd2dk1KVkVSUzhaRnVWVlJObTBDWWpsazhBUUtZSGloQVBXdFF0c0diVGhJVVM0cVZhc1M4U0tGCnFieGkwTG1WVDVlSTVseGNlL1pHaEtWS0psZmMzQ2NvSUovYW5YZXRCRHA4d1dUdEFDaUt6NVhpcnZuKzBnTjUKeVVnQmZIWHB2VE5qYkwyVFU4QXFhaThkdTNvS0dHaGo2Vkh1akVhTEZmVmdiUXNNMXUyMHkwcHpzcjIxZXlFZQovQXVMSGZXS0hsNmdieU9OUk1oRWJjTEpiRk83eXoxVkJnVUZzaTY2bDArRTRLeUJ3YW4zSTRsSnhUWDlheTdzCjVjSWV3dllSQWdNQkFBRUNnZ0VBRk5tNUd6cXJ5cGUvZE96K3RRUkUyWG9FbU9FZEh5M1I1aVQyNzBncERITHkKZkZHaFlNakNHSHIvNzBzU04zNlRyamc3OE55Rms4cS82UXJvbjNKZVlITW8wbjRzc05IL2ZBaEdoSTBMYitXaApaZGRZeCtZQ01Od3JYTHNDc3BHeEFNUnJ4MjF1ZEJBUnpSdUtQeVdxRHNJUnhCZUNlU1lPcjdJVm16K0lRM1RsCjlOajAyMUpCN0FNQmhpUlVQR2NJdTNOdk9UVGlNQnNBMFBNRCtsY1JJYXdOaW9XZWs3a1kxYXdWMlZycElwbDMKRkJvbThFK2pCSWxSbHVqcHBsMGlsKzR0Uy9xSHIwanZBQ2tEcUlaVTJ3QUlaRU5UNmFvRTZzWWxBdm9xN3R6WgpMaWVNNjh4cGVueEhpRXBZUDYwaFRlVUVrTEZ0V0ltNkg5Z0lxNFpJbVFLQmdRRHRSM1NJL3ZBQjU1V1BVMjluClF5R0VkZ3NoK05jNThXeWp1QVlLSUFBVStpUTJOSEIwK21KWGhxWmdab0RmNElZcVRXMjFZdXdQTVNQM1lrLzAKam1zcGpqQU1VYUd2U2JmZW1yQjc2KzJpeFhKUWduYzB6S0M4SEF0TXAyWHRITnp1N0VWODltRUdlRjJWYWluUwptZStLcVNMcCt4Rk9RekNaNTU5V2czSlRXd0tCZ1FDMjNudmxjTEh0KzZOMVZYWis4VFpQSitEQmYraUpGaStOCnZQRUFYTGlxRXM2TkV2RVNRWENJbjR0TS9LNnR6VVo4NlNtblEzWnpDdzdTR2ZwRWoxcEZhenZnNWc2bldvaFEKeFhRbDlaK0xrTUlNVkZjUHp2N29vYmJld2hjN3VHZUtsUzh4QXVRQ29qR0lyVnVTeHJCKzJmYWpFRVphWERRRgpEK0E0VG5DMEF3S0JnREg1YWI3c3lzbnI1NkVQTnBodUdDSVk1cEZhSXFKdWlhNFZ0UmZ1MDNXWGxZYmhGb3BjCnJkZTNZVlZPWVhoRmhweGtRR1lDbHF0QWMwM0lKQVRpOWdrRGpIVWJ3RXoxM3NjQWw0a1NFTFBHbUNRQ3htNlYKWm9rWDh2MUxDSG1mS1owY29Db0lqampab3dRMEh1amZTUWRRUmkwM2x0Wi82ajJQL2d3dmxTV2ZBb0dBUmVYQQpnYkNUc2gxUEcxZ3hWTkFxTEJOWUMxNHlxY043SmJna2Zqanl0TDgvaUJqSFlHejI4S0hiQXZCS2JGQmNNdjZFClYxU24vODBvT3hLRzRKSFN0Vm9KcHlzSVN0dUY0eW0xL1pSbkNWZXBkRUVBamlCV3V1Q2xIM3djbVUwZzlvMlQKWGk1MnJMTUdML0hqWUxUbFhYYyttSkZ0OHJmdmdrZlJNblI1QzdVQ2dZQnlmYXBaUmlrMkFuVHJGY1RldERScwpDSGFnbXkxZlowL0VuSjNxZlAwNWprTUo0bnFkM1I1WWFvRjNZNklKNFZyUXM0Wk9TbWgxaG9kTDhzcFBCVDFUCno4VUhMOFRhR1lxalJrL2RkZ0JiWjRjTU5ldmZoSTVsWU85TWIvR3pNSnNsSi9XN1RlSkZ3bXhFNzZwWXFsVXUKQ2k3M1ppekhWMTZ5cHpKZDVneUhZdz09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K - tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURURENDQWpTZ0F3SUJBZ0lVWHh3K2hrNmE1Y1hWNW9QelRZR29pVzNQcFNFd0RRWUpLb1pJaHZjTkFRRUwKQlFBd01qRWFNQmdHQTFVRUNnd1JTMjVoZEdsMlpTQkRiMjF0ZFc1cGRIa3hGREFTQmdOVkJBTU1DMlY0WVcxdwpiR1V1WTI5dE1CNFhEVEl6TURrd01UQXpNRGd4TkZvWERUTXpNRGd5T1RBek1EZ3hORm93TWpFVU1CSUdBMVVFCkF3d0xaWGhoYlhCc1pTNWpiMjB4R2pBWUJnTlZCQW9NRVV0dVlYUnBkbVVnUTI5dGJYVnVhWFI1TUlJQklqQU4KQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcVg4RHBuSm85SDJPZUN2UENTMFdGN2RKTUlMRApPM2treFJlWWZYWnoyNHZmdHZnK0QyL05PNnNxcjhJUWQydCtGcHNubWFQZE5TcWFzc3p0MlJubjFGcjd6Q1ZSCkVVdkdSYmxWVVRadEFtSTVaUEFFQ21CNG9RRDFyVUxiQm0wNFNGRXVLbFdyRXZFaWhhbThZdEM1bFUrWGlPWmMKWEh2MlJvU2xTaVpYM053bktDQ2YycDEzclFRNmZNRms3UUFvaXMrVjRxNzUvdElEZWNsSUFYeDE2YjB6WTJ5OQprMVBBS21vdkhidDZDaGhvWStsUjdveEdpeFgxWUcwTEROYnR0TXRLYzdLOXRYc2hIdndMaXgzMWloNWVvRzhqCmpVVElSRzNDeVd4VHU4czlWUVlGQmJJdXVwZFBoT0NzZ2NHcDl5T0pTY1UxL1dzdTdPWENIc0wyRVFJREFRQUIKbzFvd1dEQVdCZ05WSFJFRUR6QU5nZ3RyYm1GMGFYWmxMbVJsZGpBZEJnTlZIUTRFRmdRVWQrZXVqbzV3cTVIWgpjTEhTUU1VSURKOUJ2akl3SHdZRFZSMGpCQmd3Rm9BVW1NdUtKMTJoMEFCZGZPSGdEOFZTZE5VSmNCb3dEUVlKCktvWklodmNOQVFFTEJRQURnZ0VCQUJqK2JxNFE5bWYrRzZudVREdUpGUnlRUmNTcEpYa1p0VWc0R0pqMFFrVHAKN2J6MWFVTWRrdHJuY1lqZVk0QkpMdm9Ia3V1QVFlMUZlZmVyWmtnb3hVZkorU2syMUdhMEVGTEEvVzdQeElNZAo5MmVyNHQ3M0xGa1hVV1c2N3JoZ2Q5b2thcVA5bjBZSms2VlF2M0hoTVl3Wk1iSi82dXQ0c1kwN0lxYUpRUysrCllhK3RVK1dVOUhSQjAvRXBTRXlHSVB0ZWFPNi9XTjJzTVVCSVBzOWR2dW12SHROYVpMUnYxdWRHMnN3TTdPZkgKeVJEVFJ0Y05XSkxlc1RhY01BYlZUa1dGUHNJKzR3bXFJMW5FRVZBQ2loVi9sZUlHQmxYNGdKK0FJN0d5MEdkLwpnaXlranlmZmFkb1JRSjhyK0RuOEMzeDVTNUVDSWhtK2lSei9oZkhWalpFPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== diff --git a/test/config/tls/generate.sh b/test/config/tls/generate.sh deleted file mode 100755 index 1196211dd9dc..000000000000 --- a/test/config/tls/generate.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2022 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. - -# This script generates test/config/tls/cert-secret.yaml. - -san="knative.dev" - -# Create CA key and cert -openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -subj '/O=Knative Community/CN=example.com' -keyout rootCAKey.pem -out rootCACert.pem - -# Create server key -openssl req -out tls.csr -newkey rsa:2048 -nodes -keyout tls.key -subj "/CN=example.com/O=Knative Community" -addext "subjectAltName = DNS:$san" - -# Create server certs -openssl x509 -req -extfile <(printf "subjectAltName=DNS:$san") -days 3650 -in tls.csr -CA rootCACert.pem -CAkey rootCAKey.pem -CAcreateserial -out tls.crt - -CA_CERT=$(cat rootCACert.pem | base64 | tr -d '\n') -TLS_KEY=$(cat tls.key | base64 | tr -d '\n') -TLS_CERT=$(cat tls.crt | base64 | tr -d '\n') - -cat < cert-secret.yaml -# Copyright 2022 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. - -apiVersion: v1 -kind: Secret -metadata: - name: ca-cert - namespace: serving-tests -data: - ca.crt: ${CA_CERT} ---- -apiVersion: v1 -kind: Secret -metadata: - name: server-certs - namespace: knative-serving -data: - tls.key: ${TLS_KEY} - tls.crt: ${TLS_CERT} -EOF - -# Clean up -rm -f rootCACert.pem rootCAKey.pem tls.key tls.crt tls.csr rootCACert.srl diff --git a/test/e2e-common.sh b/test/e2e-common.sh index 1946824d6635..4461a61d357c 100644 --- a/test/e2e-common.sh +++ b/test/e2e-common.sh @@ -319,10 +319,6 @@ function install() { YTT_FILES+=("${REPO_ROOT_DIR}/test/config/resource-quota/resource-quota.yaml") fi - if (( ENABLE_TLS )); then - YTT_FILES+=("${REPO_ROOT_DIR}/test/config/tls/cert-secret.yaml") - fi - local ytt_result=$(mktemp) local ytt_post_install_result=$(mktemp) local ytt_flags="" @@ -375,16 +371,14 @@ function install() { fi if (( ENABLE_TLS )); then - echo "Patch to config-network to enable internal encryption" - toggle_feature system-internal-tls Enabled config-network + echo "Patch config-network to enable encryption features" + toggle_feature system-internal-tls enabled config-network + + # This is currently only supported by kourier if [[ "$INGRESS_CLASS" == "kourier.ingress.networking.knative.dev" ]]; then - echo "Point Kourier local gateway to custom server certificates" - toggle_feature cluster-cert-secret server-certs config-kourier - # This needs to match the name of Secret in test/config/tls/cert-secret.yaml - export CA_CERT=ca-cert - # This needs to match $san from test/config/tls/generate.sh - export SERVER_NAME=knative.dev + toggle_feature cluster-local-domain-tls enabled config-network fi + echo "Restart activator to mount the certificates" kubectl delete pod -n ${SYSTEM_NAMESPACE} -l app=activator kubectl wait --timeout=60s --for=condition=Available deployment -n ${SYSTEM_NAMESPACE} activator diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh index eff5a2e51faf..56b9c661eec0 100755 --- a/test/e2e-tests.sh +++ b/test/e2e-tests.sh @@ -63,23 +63,26 @@ if (( SHORT )); then GO_TEST_FLAGS+=" -short" fi +#go_test_e2e -timeout=30m \ +# ${GO_TEST_FLAGS} \ +# ./test/conformance/api/... \ +# ./test/conformance/runtime/... \ +# ./test/e2e \ +# ${E2E_TEST_FLAGS} || failed=1 +# +#toggle_feature tag-header-based-routing Enabled +#go_test_e2e -timeout=2m ./test/e2e/tagheader ${E2E_TEST_FLAGS} || failed=1 +#toggle_feature tag-header-based-routing Disabled +# +#toggle_feature allow-zero-initial-scale true config-autoscaler || fail_test +#go_test_e2e -timeout=2m ./test/e2e/initscale ${E2E_TEST_FLAGS} || failed=1 +#toggle_feature allow-zero-initial-scale false config-autoscaler || fail_test +# +#go_test_e2e -timeout=2m ./test/e2e/domainmapping ${E2E_TEST_FLAGS} || failed=1 -go_test_e2e -timeout=30m \ - ${GO_TEST_FLAGS} \ - ./test/conformance/api/... \ - ./test/conformance/runtime/... \ - ./test/e2e \ - ${E2E_TEST_FLAGS} || failed=1 - -toggle_feature tag-header-based-routing Enabled -go_test_e2e -timeout=2m ./test/e2e/tagheader ${E2E_TEST_FLAGS} || failed=1 -toggle_feature tag-header-based-routing Disabled - -toggle_feature allow-zero-initial-scale true config-autoscaler || fail_test -go_test_e2e -timeout=2m ./test/e2e/initscale ${E2E_TEST_FLAGS} || failed=1 -toggle_feature allow-zero-initial-scale false config-autoscaler || fail_test - -go_test_e2e -timeout=2m ./test/e2e/domainmapping ${E2E_TEST_FLAGS} || failed=1 +toggle_feature cluster-local-domain-tls enabled config-network || fail_test +go_test_e2e -timeout=2m ./test/e2e/clusterlocaldomaintls ${E2E_TEST_FLAGS} || failed=1 +toggle_feature cluster-local-domain-tls disabled config-network || fail_test toggle_feature system-internal-tls enabled config-network || fail_test toggle_feature "logging.enable-request-log" true config-observability || fail_test diff --git a/test/e2e/clusterlocaldomaintls/cluster_local_domain_tls_test.go b/test/e2e/clusterlocaldomaintls/cluster_local_domain_tls_test.go new file mode 100644 index 000000000000..a8e97a8f99de --- /dev/null +++ b/test/e2e/clusterlocaldomaintls/cluster_local_domain_tls_test.go @@ -0,0 +1,155 @@ +//go:build e2e +// +build e2e + +/* +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 clusterlocaldomaintls + +import ( + "net/url" + "strings" + "testing" + + netapi "knative.dev/networking/pkg/apis/networking" + "knative.dev/serving/pkg/apis/serving" + rtesting "knative.dev/serving/pkg/testing/v1" + "knative.dev/serving/test" + "knative.dev/serving/test/e2e" + v1test "knative.dev/serving/test/v1" +) + +var dnsVariants = []struct { + name string + suffix string +}{ + {"fqdn", ""}, + {"short", ".cluster.local"}, + {"shortest", ".svc.cluster.local"}, +} + +func TestClusterLocalDomainTLSClusterLocalVisibility(t *testing.T) { + if !test.ServingFlags.EnableAlphaFeatures { + t.Skip("Alpha features not enabled") + } + + if !(strings.Contains(test.ServingFlags.IngressClass, "kourier")) { + t.Skip("Skip this test for non-kourier ingress.") + } + + t.Parallel() + clients := test.Setup(t) + names := test.ResourceNames{ + Service: test.ObjectNameForTest(t), + Image: test.HelloWorld, + } + + test.EnsureTearDown(t, clients, &names) + + withInternalVisibility := rtesting.WithServiceLabel(netapi.VisibilityLabelKey, serving.VisibilityClusterLocal) + t.Log("Creating a new service with cluster-local visibility") + resources, err := v1test.CreateServiceReady(t, clients, &names, withInternalVisibility) + if err != nil { + t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) + } + + // After the service is created, we need to wait for the CA to be populated, + // then use that secret in the ProxyImage to trust the cluster-local https connection + secret, err := e2e.GetCASecret(clients) + if err != nil { + t.Fatal(err.Error()) + } + + svcUrl := resources.Route.Status.URL.URL() + if svcUrl.Scheme != "https" { + t.Fatalf("URL scheme of service %v was not https", names.Service) + } + + // Check access via https on all cluster-local-domains + for _, dns := range dnsVariants { + helloworldURL := &url.URL{ + Scheme: svcUrl.Scheme, + Host: strings.TrimSuffix(svcUrl.Host, dns.suffix), + Path: svcUrl.Path, + } + t.Run(dns.name, func(t *testing.T) { + t.Parallel() + e2e.TestProxyToHelloworld(t, clients, helloworldURL, false, false, secret) + }) + } +} + +func TestClusterLocalDomainTLSClusterExternalVisibility(t *testing.T) { + if !test.ServingFlags.EnableAlphaFeatures { + t.Skip("Alpha features not enabled") + } + + if !(strings.Contains(test.ServingFlags.IngressClass, "kourier")) { + t.Skip("Skip this test for non-kourier ingress.") + } + + t.Parallel() + clients := test.Setup(t) + names := test.ResourceNames{ + Service: test.ObjectNameForTest(t), + Image: test.HelloWorld, + } + + test.EnsureTearDown(t, clients, &names) + + t.Log("Creating a new service with external visibility") + resources, err := v1test.CreateServiceReady(t, clients, &names) + if err != nil { + t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) + } + + // After the service is created, we need to wait for the CA to be populated, + // then use that secret in the ProxyImage to trust the cluster-local https connection + secret, err := e2e.GetCASecret(clients) + if err != nil { + t.Fatal(err.Error()) + } + + externalURL := resources.Route.Status.URL.URL() + internalURL := resources.Route.Status.Address.URL + + if internalURL.Scheme != "https" { + t.Fatalf("Internal URL scheme of service %v was not https", names.Service) + } + + if externalURL.Scheme != "http" { + t.Fatalf("External URL scheme of service %v was not http", names.Service) + } + + // Check normal access on external domain + t.Run("external-access", func(t *testing.T) { + t.Parallel() + e2e.TestProxyToHelloworld(t, clients, externalURL, false, true, secret) + }) + + // Check access via https on all cluster-local-domains + for _, dns := range dnsVariants { + helloworldURL := &url.URL{ + Scheme: internalURL.Scheme, + Host: strings.TrimSuffix(internalURL.Host, dns.suffix), + Path: internalURL.Path, + } + t.Run(dns.name, func(t *testing.T) { + t.Parallel() + e2e.TestProxyToHelloworld(t, clients, helloworldURL, false, false, secret) + }) + } +} diff --git a/test/e2e/encryption.go b/test/e2e/encryption.go new file mode 100644 index 000000000000..886d3a697ed5 --- /dev/null +++ b/test/e2e/encryption.go @@ -0,0 +1,96 @@ +//go:build e2e +// +build e2e + +/* +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 e2e + +import ( + "context" + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "knative.dev/networking/pkg/certificates" + netcfg "knative.dev/networking/pkg/config" + "knative.dev/pkg/system" + "knative.dev/serving/test" +) + +// this needs to match the ClusterIssuer in third_parth/cert-manager-latest/net-certmanager.yaml +const ( + certManagerCASecret = "knative-selfsigned-ca" + certManagerNamespace = "cert-manager" +) + +// GetCASecret returns the Secret that is used by the CA to issue KnativeCertificates. +// Note: this process can be omitted when https://github.com/knative/serving/issues/14196 is implemented, +// then httpproxy.go should get the CA to trust from the Addressable. +func GetCASecret(clients *test.Clients) (*corev1.Secret, error) { + cm, err := clients.KubeClient.CoreV1().ConfigMaps(system.Namespace()). + Get(context.Background(), netcfg.ConfigMapName, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("failed to get ConfigMap config-network: %w", err) + } + + // CA is only needed when encryption on the cluster is enabled + if !strings.EqualFold(cm.Data[netcfg.ClusterLocalDomainTLSKey], string(netcfg.EncryptionEnabled)) { + return nil, nil + } + + class := getCertificateClass(cm) + switch class { + case netcfg.CertManagerCertificateClassName: + return getCertManagerCA(clients) + default: + return nil, fmt.Errorf("invalid %s: %s", netcfg.DefaultCertificateClassKey, class) + } +} + +// getCertificateClass returns the currently configured certificate-class. +func getCertificateClass(cm *corev1.ConfigMap) string { + // if not specified, we fall back to our default, which is cert-manager + if class, ok := cm.Data[netcfg.DefaultCertificateClassKey]; ok { + return class + } + + return netcfg.CertManagerCertificateClassName +} + +func getCertManagerCA(clients *test.Clients) (*corev1.Secret, error) { + var secret *corev1.Secret + err := wait.PollImmediate(test.PollInterval, test.PollTimeout, func() (bool, error) { + caSecret, err := clients.KubeClient.CoreV1().Secrets(certManagerNamespace).Get(context.Background(), certManagerCASecret, metav1.GetOptions{}) + if err != nil { + return false, err + } + // CA not yet populated + if len(caSecret.Data[certificates.CertName]) == 0 { + return false, nil + } + + secret = caSecret + return true, nil + }) + if err != nil { + return nil, fmt.Errorf("error while waiting for cert-manager self-signed CA to be popluated: %w", err) + } + + return secret, nil +} diff --git a/test/e2e/httpproxy.go b/test/e2e/httpproxy.go new file mode 100644 index 000000000000..55c3916844a8 --- /dev/null +++ b/test/e2e/httpproxy.go @@ -0,0 +1,128 @@ +package e2e + +import ( + "context" + "net" + "net/http" + "net/url" + "strconv" + "testing" + + corev1 "k8s.io/api/core/v1" + "knative.dev/networking/pkg/certificates" + pkgTest "knative.dev/pkg/test" + "knative.dev/pkg/test/ingress" + "knative.dev/pkg/test/spoof" + rtesting "knative.dev/serving/pkg/testing/v1" + "knative.dev/serving/test" + v1test "knative.dev/serving/test/v1" +) + +const ( + targetHostEnv = "TARGET_HOST" + gatewayHostEnv = "GATEWAY_HOST" + helloworldResponse = "Hello World! How about some tasty noodles?" +) + +func TestProxyToHelloworld(t *testing.T, clients *test.Clients, helloworldURL *url.URL, inject bool, accessibleExternal bool, caSecret *corev1.Secret) { + // Create envVars to be used in httpproxy app. + envVars := []corev1.EnvVar{{ + Name: targetHostEnv, + Value: helloworldURL.Hostname(), + }} + + // When resolvable domain is not set for external access test, use gateway for the endpoint as services like sslip.io may be flaky. + // ref: https://github.com/knative/serving/issues/5389 + if !test.ServingFlags.ResolvableDomain && accessibleExternal { + gatewayTarget, mapper, err := ingress.GetIngressEndpoint(context.Background(), clients.KubeClient, pkgTest.Flags.IngressEndpoint) + if err != nil { + t.Fatal("Failed to get gateway IP:", err) + } + envVars = append(envVars, corev1.EnvVar{ + Name: gatewayHostEnv, + Value: net.JoinHostPort(gatewayTarget, mapper("80")), + }) + } + + // HTTPProxy needs to trust the CA that signed the cluster-local-domain certificates of the target service + if caSecret != nil && !accessibleExternal { + envVars = append(envVars, []corev1.EnvVar{{Name: "CA_CERT", Value: string(caSecret.Data[certificates.CertName])}}...) + } + + // Set up httpproxy app. + t.Log("Creating a Service for the httpproxy test app.") + names := test.ResourceNames{ + Service: test.ObjectNameForTest(t), + Image: test.HTTPProxy, + } + + test.EnsureTearDown(t, clients, &names) + + serviceOptions := []rtesting.ServiceOption{ + rtesting.WithEnv(envVars...), + rtesting.WithConfigAnnotations(map[string]string{ + "sidecar.istio.io/inject": strconv.FormatBool(inject), + }), + } + + resources, err := v1test.CreateServiceReady(t, clients, &names, serviceOptions...) + + if err != nil { + t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) + } + + url := resources.Route.Status.URL.URL() + if _, err = pkgTest.CheckEndpointState( + context.Background(), + clients.KubeClient, + t.Logf, + url, + spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(helloworldResponse)), + "HTTPProxy", + test.ServingFlags.ResolvableDomain, + test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), + ); err != nil { + t.Fatal("Failed to start endpoint of httpproxy:", err) + } + t.Log("httpproxy is ready.") + + // When we're testing with resolvable domains, we fail earlier trying + // to resolve the cluster local domain. + if !accessibleExternal && test.ServingFlags.ResolvableDomain { + return + } + + // if the service is not externally available, + // the gateway does not expose a https port, so we need to call the http port + if !accessibleExternal && helloworldURL.Scheme == "https" { + helloworldURL.Scheme = "http" + } + + // As a final check (since we know they are both up), check that if we can + // (or cannot) access the helloworld app externally. + response, err := sendRequest(t, clients, test.ServingFlags.ResolvableDomain, helloworldURL) + if err != nil { + t.Fatal("Unexpected error when sending request to helloworld:", err) + } + expectedStatus := http.StatusNotFound + if accessibleExternal { + expectedStatus = http.StatusOK + } + if got, want := response.StatusCode, expectedStatus; got != want { + t.Errorf("helloworld response StatusCode = %v, want %v", got, want) + } +} + +func sendRequest(t *testing.T, clients *test.Clients, resolvableDomain bool, url *url.URL) (*spoof.Response, error) { + t.Logf("The domain of request is %s.", url.Hostname()) + client, err := pkgTest.NewSpoofingClient(context.Background(), clients.KubeClient, t.Logf, url.Hostname(), resolvableDomain, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodGet, url.String(), nil) + if err != nil { + return nil, err + } + return client.Do(req) +} diff --git a/test/e2e/service_to_service_test.go b/test/e2e/service_to_service_test.go index 5787bcac4c71..52a25babdaf3 100644 --- a/test/e2e/service_to_service_test.go +++ b/test/e2e/service_to_service_test.go @@ -20,22 +20,13 @@ limitations under the License. package e2e import ( - "context" - "net" - "net/http" "net/url" - "os" "strconv" "strings" "testing" - corev1 "k8s.io/api/core/v1" netapi "knative.dev/networking/pkg/apis/networking" - ptr "knative.dev/pkg/ptr" - pkgTest "knative.dev/pkg/test" - ingress "knative.dev/pkg/test/ingress" "knative.dev/pkg/test/logstream" - "knative.dev/pkg/test/spoof" "knative.dev/serving/pkg/apis/autoscaling" "knative.dev/serving/pkg/apis/serving" rtesting "knative.dev/serving/pkg/testing/v1" @@ -43,14 +34,6 @@ import ( v1test "knative.dev/serving/test/v1" ) -const ( - targetHostEnv = "TARGET_HOST" - gatewayHostEnv = "GATEWAY_HOST" - helloworldResponse = "Hello World! How about some tasty noodles?" - caCertDirectory = "/var/lib/knative/ca" - caCertPath = caCertDirectory + "/ca.crt" -) - // testCases for table-driven testing. var testCases = []struct { // name of the test case, which will be inserted in names of routes, configurations, etc. @@ -79,117 +62,6 @@ var testInjection = []struct { {"both-enabled", true, true}, } -func sendRequest(t *testing.T, clients *test.Clients, resolvableDomain bool, url *url.URL) (*spoof.Response, error) { - t.Logf("The domain of request is %s.", url.Hostname()) - client, err := pkgTest.NewSpoofingClient(context.Background(), clients.KubeClient, t.Logf, url.Hostname(), resolvableDomain, test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS)) - if err != nil { - return nil, err - } - - req, err := http.NewRequest(http.MethodGet, url.String(), nil) - if err != nil { - return nil, err - } - return client.Do(req) -} - -func testProxyToHelloworld(t *testing.T, clients *test.Clients, helloworldURL *url.URL, inject bool, accessibleExternal bool) { - // Create envVars to be used in httpproxy app. - envVars := []corev1.EnvVar{{ - Name: targetHostEnv, - Value: helloworldURL.Hostname(), - }} - - // When resolvable domain is not set for external access test, use gateway for the endpoint as services like sslip.io may be flaky. - // ref: https://github.com/knative/serving/issues/5389 - if !test.ServingFlags.ResolvableDomain && accessibleExternal { - gatewayTarget, mapper, err := ingress.GetIngressEndpoint(context.Background(), clients.KubeClient, pkgTest.Flags.IngressEndpoint) - if err != nil { - t.Fatal("Failed to get gateway IP:", err) - } - envVars = append(envVars, corev1.EnvVar{ - Name: gatewayHostEnv, - Value: net.JoinHostPort(gatewayTarget, mapper("80")), - }) - } - - caSecretName := os.Getenv("CA_CERT") - - // External services use different TLS certificates than cluster-local services. - // Not passing CA_CERT will make the httpproxy use plain http to connect to the - // target service. - if caSecretName != "" && !accessibleExternal { - envVars = append(envVars, []corev1.EnvVar{{Name: "CA_CERT", Value: caCertPath}, - {Name: "SERVER_NAME", Value: os.Getenv("SERVER_NAME")}}...) - } - - // Set up httpproxy app. - t.Log("Creating a Service for the httpproxy test app.") - names := test.ResourceNames{ - Service: test.ObjectNameForTest(t), - Image: test.HTTPProxy, - } - - test.EnsureTearDown(t, clients, &names) - - serviceOptions := []rtesting.ServiceOption{ - rtesting.WithEnv(envVars...), - rtesting.WithConfigAnnotations(map[string]string{ - "sidecar.istio.io/inject": strconv.FormatBool(inject), - }), - } - - if caSecretName != "" && !accessibleExternal { - serviceOptions = append(serviceOptions, rtesting.WithVolume("ca-certs", caCertDirectory, corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: caSecretName, - Optional: ptr.Bool(false), - }}), - ) - } - - resources, err := v1test.CreateServiceReady(t, clients, &names, serviceOptions...) - - if err != nil { - t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) - } - - url := resources.Route.Status.URL.URL() - if _, err = pkgTest.CheckEndpointState( - context.Background(), - clients.KubeClient, - t.Logf, - url, - spoof.MatchesAllOf(spoof.IsStatusOK, spoof.MatchesBody(helloworldResponse)), - "HTTPProxy", - test.ServingFlags.ResolvableDomain, - test.AddRootCAtoTransport(context.Background(), t.Logf, clients, test.ServingFlags.HTTPS), - ); err != nil { - t.Fatal("Failed to start endpoint of httpproxy:", err) - } - t.Log("httpproxy is ready.") - - // When we're testing with resolvable domains, we fail earlier trying - // to resolve the cluster local domain. - if !accessibleExternal && test.ServingFlags.ResolvableDomain { - return - } - - // As a final check (since we know they are both up), check that if we can - // (or cannot) access the helloworld app externally. - response, err := sendRequest(t, clients, test.ServingFlags.ResolvableDomain, helloworldURL) - if err != nil { - t.Fatal("Unexpected error when sending request to helloworld:", err) - } - expectedStatus := http.StatusNotFound - if accessibleExternal { - expectedStatus = http.StatusOK - } - if got, want := response.StatusCode, expectedStatus; got != want { - t.Errorf("helloworld response StatusCode = %v, want %v", got, want) - } -} - // In this test, we set up two apps: helloworld and httpproxy. // helloworld is a simple app that displays a plaintext string. // httpproxy is a proxy that redirects request to internal service of helloworld app @@ -229,6 +101,13 @@ func TestServiceToServiceCall(t *testing.T) { } t.Logf("helloworld internal domain is %s.", resources.Route.Status.URL.Host) + // if cluster-local-domain-tls is enabled, this will return the CA used to sign the certificates. + // TestProxyToHelloworld will use this CA to verify the https connection + secret, err := GetCASecret(clients) + if err != nil { + t.Fatal(err.Error()) + } + // helloworld app and its route are ready. Running the test cases now. for _, tc := range testCases { helloworldURL := &url.URL{ @@ -243,7 +122,7 @@ func TestServiceToServiceCall(t *testing.T) { cancel := logstream.Start(t) defer cancel() } - testProxyToHelloworld(t, clients, helloworldURL, true /*inject*/, false /*accessible externally*/) + TestProxyToHelloworld(t, clients, helloworldURL, true, false, secret) }) } } @@ -279,8 +158,15 @@ func testSvcToSvcCallViaActivator(t *testing.T, clients *test.Clients, injectA b t.Fatal("Never got Activator endpoints in the service:", err) } + // if cluster-local-domain-tls is enabled, this will return the CA used to sign the certificates. + // TestProxyToHelloworld will use this CA to verify the https connection + secret, err := GetCASecret(clients) + if err != nil { + t.Fatal(err.Error()) + } + // Send request to helloworld app via httpproxy service - testProxyToHelloworld(t, clients, resources.Route.Status.URL.URL(), injectA, false /*accessible externally*/) + TestProxyToHelloworld(t, clients, resources.Route.Status.URL.URL(), injectA, false, secret) } // Same test as TestServiceToServiceCall but before sending requests @@ -340,6 +226,13 @@ func TestCallToPublicService(t *testing.T) { {"external_address", resources.Route.Status.URL.URL(), true}, } + // if cluster-local-domain-tls is enabled, this will return the CA used to sign the certificates. + // TestProxyToHelloworld will use this CA to verify the https connection + secret, err := GetCASecret(clients) + if err != nil { + t.Fatal(err.Error()) + } + for _, tc := range gatewayTestCases { tc := tc t.Run(tc.name, func(t *testing.T) { @@ -348,7 +241,7 @@ func TestCallToPublicService(t *testing.T) { cancel := logstream.Start(t) defer cancel() } - testProxyToHelloworld(t, clients, tc.url, false /*inject*/, tc.accessibleExternally) + TestProxyToHelloworld(t, clients, tc.url, false, tc.accessibleExternally, secret) }) } } diff --git a/test/e2e/subroutes_test.go b/test/e2e/subroutes_test.go index b86fcc27cd38..a66a42ee361d 100644 --- a/test/e2e/subroutes_test.go +++ b/test/e2e/subroutes_test.go @@ -76,6 +76,13 @@ func TestSubrouteLocalSTS(t *testing.T) { // We can't use a longer more descript t.Log("helloworld internal domain is ", resources.Route.Status.URL.Host) + // if cluster-local-domain-tls is enabled, this will return the CA used to sign the certificates. + // TestProxyToHelloworld will use this CA to verify the https connection + secret, err := GetCASecret(clients) + if err != nil { + t.Fatal(err.Error()) + } + // helloworld app and its route are ready. Running the test cases now. for _, tc := range testCases { domain := fmt.Sprintf("%s-%s", tag, resources.Route.Status.Address.URL.Host) @@ -83,7 +90,7 @@ func TestSubrouteLocalSTS(t *testing.T) { // We can't use a longer more descript helloworldURL.Host = strings.TrimSuffix(domain, tc.suffix) t.Run(tc.name, func(t *testing.T) { t.Parallel() - testProxyToHelloworld(t, clients, helloworldURL, true, false) + TestProxyToHelloworld(t, clients, helloworldURL, true, false, secret) }) } } diff --git a/test/ha/ha.go b/test/ha/ha.go index 3183f433fe68..6be34ab0e078 100644 --- a/test/ha/ha.go +++ b/test/ha/ha.go @@ -37,7 +37,7 @@ import ( const ( // NumControllerReconcilers is the number of controllers run by ./cmd/controller/main.go. // It is exported so the tests from cmd/controller/main.go can ensure we keep it in sync. - NumControllerReconcilers = 10 + NumControllerReconcilers = 9 ) func createPizzaPlanetService(t *testing.T, fopt ...rtesting.ServiceOption) (test.ResourceNames, *v1test.ResourceObjects) { diff --git a/test/test_images/httpproxy/httpproxy.go b/test/test_images/httpproxy/httpproxy.go index ba2c0a93e2bd..e36e9cdfd4d2 100644 --- a/test/test_images/httpproxy/httpproxy.go +++ b/test/test_images/httpproxy/httpproxy.go @@ -103,19 +103,12 @@ func newTLSEnabledTransport() http.RoundTripper { } transport.TLSClientConfig = &tls.Config{ RootCAs: rootCAs, - // If SERVER_NAME is not set the empty value will make the - // TLS client infer the ServerName from the hostname. - ServerName: os.Getenv("SERVER_NAME"), } } return transport } -func createRootCAs(caCertFile string) (*x509.CertPool, error) { - pemData, err := os.ReadFile(caCertFile) - if err != nil { - return nil, err - } +func createRootCAs(caCert string) (*x509.CertPool, error) { rootCAs, err := x509.SystemCertPool() if rootCAs == nil || err != nil { if err != nil { @@ -123,7 +116,7 @@ func createRootCAs(caCertFile string) (*x509.CertPool, error) { } rootCAs = x509.NewCertPool() } - if !rootCAs.AppendCertsFromPEM(pemData) { + if !rootCAs.AppendCertsFromPEM([]byte(caCert)) { return nil, errors.New("failed to add the certificate to the root CA") } return rootCAs, nil diff --git a/third_party/cert-manager-latest/net-certmanager.yaml b/third_party/cert-manager-latest/net-certmanager.yaml index 9680edda315c..03dd62d50d25 100644 --- a/third_party/cert-manager-latest/net-certmanager.yaml +++ b/third_party/cert-manager-latest/net-certmanager.yaml @@ -19,7 +19,7 @@ metadata: name: knative-serving-certmanager labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving serving.knative.dev/controller: "true" networking.knative.dev/certificate-provider: cert-manager @@ -52,7 +52,7 @@ metadata: name: config.webhook.net-certmanager.networking.internal.knative.dev labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager webhooks: @@ -93,7 +93,7 @@ metadata: namespace: knative-serving labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager @@ -119,7 +119,7 @@ metadata: namespace: knative-serving labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager data: @@ -138,23 +138,32 @@ data: # These sample configuration options may be copied out of # this block and unindented to actually change the configuration. - # issuerRef is a reference to the issuer for cluster external certificates used for ingress. + # issuerRef is a reference to the issuer for external-domain certificates used for ingress. # IssuerRef should be either `ClusterIssuer` or `Issuer`. # Please refer `IssuerRef` in https://github.com/cert-manager/cert-manager/tree/master/pkg/apis/certmanager/v1/types_certificate.go # for more details about IssuerRef configuration. - # If the issuerRef is not specified, the self-signed `knative-internal-encryption-ca` ClusterIssuer is used. + # If the issuerRef is not specified, the self-signed `knative-selfsigned-issuer` ClusterIssuer is used. issuerRef: | kind: ClusterIssuer name: letsencrypt-issuer - # clusterInternalIssuerRef is a reference to the issuer for cluster internal certificates used for ingress. - # ClusterInternalIssuerRef should be either `ClusterIssuer` or `Issuer`. + # clusterLocalIssuerRef is a reference to the issuer for cluster-local-domain certificates used for ingress. + # clusterLocalIssuerRef should be either `ClusterIssuer` or `Issuer`. # Please refer `IssuerRef` in https://github.com/cert-manager/cert-manager/tree/master/pkg/apis/certmanager/v1/types_certificate.go # for more details about ClusterInternalIssuerRef configuration. - # If the clusterInternalIssuerRef is not specified, the self-signed `knative-internal-encryption-ca` ClusterIssuer is used. - clusterInternalIssuerRef: | + # If the clusterLocalIssuerRef is not specified, the self-signed `knative-selfsigned-issuer` ClusterIssuer is used. + clusterLocalIssuerRef: | kind: ClusterIssuer - name: knative-internal-encryption-issuer + name: your-company-issuer + + # systemInternalIssuerRef is a reference to the issuer for certificates for system-internal-tls certificates used by Knative internal components. + # systemInternalIssuerRef should be either `ClusterIssuer` or `Issuer`. + # Please refer `IssuerRef` in https://github.com/cert-manager/cert-manager/tree/master/pkg/apis/certmanager/v1/types_certificate.go + # for more details about ClusterInternalIssuerRef configuration. + # If the systemInternalIssuerRef is not specified, the self-signed `knative-selfsigned-issuer` ClusterIssuer is used. + systemInternalIssuerRef: | + kind: ClusterIssuer + name: knative-selfsigned-issuer --- # Copyright 2020 The Knative Authors @@ -178,7 +187,7 @@ metadata: namespace: knative-serving labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager spec: @@ -190,7 +199,7 @@ spec: labels: app: net-certmanager-controller app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving spec: serviceAccountName: controller @@ -198,7 +207,7 @@ spec: - name: controller # This is the Go import path for the binary that is containerized # and substituted here. - image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/controller@sha256:c871cd1202050c852102d33de1b4692a11fc042423995a1e7445d770752e1f1d + image: quay.io/rlehmann/net-certmanager-controller:latest resources: requests: cpu: 30m @@ -239,7 +248,7 @@ metadata: labels: app: net-certmanager-controller app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager name: net-certmanager-controller @@ -277,7 +286,7 @@ metadata: name: selfsigned-cluster-issuer labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager spec: @@ -286,28 +295,28 @@ spec: apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: - name: knative-internal-encryption-issuer + name: knative-selfsigned-issuer labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager spec: ca: - secretName: knative-internal-encryption-ca + secretName: knative-selfsigned-ca --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: - name: knative-internal-encryption-ca + name: knative-selfsigned-ca namespace: cert-manager # If you want to use it as a ClusterIssuer the secret must be in the cert-manager namespace. labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager spec: - secretName: knative-internal-encryption-ca + secretName: knative-selfsigned-ca commonName: knative.dev usages: - server auth @@ -338,7 +347,7 @@ metadata: namespace: knative-serving labels: app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager spec: @@ -351,7 +360,7 @@ spec: labels: app: net-certmanager-webhook app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving role: net-certmanager-webhook spec: @@ -360,7 +369,7 @@ spec: - name: webhook # This is the Go import path for the binary that is containerized # and substituted here. - image: gcr.io/knative-nightly/knative.dev/net-certmanager/cmd/webhook@sha256:5d3ae5ae850e2448107eb295ec90ee1a4ad102aeb3ded453a94e1c83b4d626b3 + image: quay.io/rlehmann/net-certmanager-webhook:latest resources: requests: cpu: 20m @@ -426,7 +435,7 @@ metadata: labels: role: net-certmanager-webhook app.kubernetes.io/component: net-certmanager - app.kubernetes.io/version: "20231110-8b2a470c" + app.kubernetes.io/version: "20231110-57baadad" app.kubernetes.io/name: knative-serving networking.knative.dev/certificate-provider: cert-manager spec: diff --git a/third_party/kourier-latest/kourier.yaml b/third_party/kourier-latest/kourier.yaml index dfbabaa5ea36..f2fb30d60597 100644 --- a/third_party/kourier-latest/kourier.yaml +++ b/third_party/kourier-latest/kourier.yaml @@ -20,7 +20,7 @@ metadata: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/name: knative-serving app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" --- # Copyright 2020 The Knative Authors @@ -45,7 +45,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving data: envoy-bootstrap.yaml: | @@ -55,7 +55,7 @@ data: api_type: GRPC rate_limit_settings: {} grpc_services: - - envoy_grpc: {cluster_name: xds_cluster} + - envoy_grpc: {cluster_name: xds_cluster} cds_config: resource_api_version: V3 ads: {} @@ -133,9 +133,9 @@ data: type: STRICT_DNS admin: access_log: - - name: envoy.access_loggers.stdout - typed_config: - "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog + - name: envoy.access_loggers.stdout + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog address: pipe: path: /tmp/envoy.admin @@ -168,7 +168,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving data: _example: | @@ -248,7 +248,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving --- apiVersion: rbac.authorization.k8s.io/v1 @@ -258,7 +258,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving rules: - apiGroups: [""] @@ -287,7 +287,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving roleRef: apiGroup: rbac.authorization.k8s.io @@ -321,7 +321,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving spec: strategy: @@ -343,7 +343,7 @@ spec: app: net-kourier-controller spec: containers: - - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:5bbe77dc277b0ad61572d5816d386738c82099d3ba8bba2910d9be699cbba522 + - image: quay.io/rlehmann/kourier-controller/main.go:latest name: controller env: - name: CERTS_SECRET_NAMESPACE @@ -408,7 +408,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving spec: ports: @@ -443,7 +443,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving spec: strategy: @@ -552,7 +552,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving spec: ports: @@ -576,7 +576,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving spec: ports: @@ -600,7 +600,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving spec: minReplicas: 1 @@ -626,7 +626,7 @@ metadata: labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier - app.kubernetes.io/version: "20231110-ad58d905" + app.kubernetes.io/version: "20231110-1c93d51b" app.kubernetes.io/name: knative-serving spec: minAvailable: 80% diff --git a/vendor/knative.dev/networking/config/ingress.yaml b/vendor/knative.dev/networking/config/ingress.yaml index aafed926f407..e284c2572816 100644 --- a/vendor/knative.dev/networking/config/ingress.yaml +++ b/vendor/knative.dev/networking/config/ingress.yaml @@ -150,6 +150,9 @@ 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/register.go b/vendor/knative.dev/networking/pkg/apis/networking/register.go index e88e9b5c0455..4a7a82bc4fb5 100644 --- a/vendor/knative.dev/networking/pkg/apis/networking/register.go +++ b/vendor/knative.dev/networking/pkg/apis/networking/register.go @@ -119,6 +119,10 @@ const ( // already using labels for domain, it probably best to keep this // consistent. VisibilityLabelKey = PublicGroupName + "/visibility" + + // CertificateTypeLabelKey is the label to indicate the type of Knative certificate + // used for Knative Serving encryption functionality. + CertificateTypeLabelKey = PublicGroupName + "/certificate-type" ) // Pseudo-constants diff --git a/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_defaults.go b/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_defaults.go index 6cfc08524474..a4e81fb9fb58 100644 --- a/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_defaults.go +++ b/vendor/knative.dev/networking/pkg/apis/networking/v1alpha1/ingress_defaults.go @@ -38,7 +38,11 @@ func (is *IngressSpec) SetDefaults(ctx context.Context) { } // SetDefaults populates default values in IngressTLS -func (t *IngressTLS) SetDefaults(_ context.Context) {} +func (t *IngressTLS) SetDefaults(_ context.Context) { + if t.Visibility == "" { + t.Visibility = IngressVisibilityExternalIP + } +} // SetDefaults populates default values in IngressRule func (r *IngressRule) SetDefaults(ctx context.Context) { 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 44b0d74e2814..65d612cd9c59 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,6 +149,10 @@ 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/certificates/reconciler/certificates.go b/vendor/knative.dev/networking/pkg/certificates/reconciler/certificates.go deleted file mode 100644 index bf8c26d207f8..000000000000 --- a/vendor/knative.dev/networking/pkg/certificates/reconciler/certificates.go +++ /dev/null @@ -1,211 +0,0 @@ -/* -Copyright 2021 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 reconciler - -import ( - "bytes" - "context" - "crypto/rsa" - "crypto/x509" - "fmt" - "time" - - "go.uber.org/zap" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/kubernetes" - listerv1 "k8s.io/client-go/listers/core/v1" - pkgreconciler "knative.dev/pkg/reconciler" - "knative.dev/pkg/system" - - "knative.dev/networking/pkg/certificates" -) - -const ( - caExpirationInterval = time.Hour * 24 * 365 * 10 // 10 years - expirationInterval = time.Hour * 24 * 30 // 30 days - rotationThreshold = 24 * time.Hour - - // certificates used by trusted data routing elements such as activator, ingress gw - dataPlaneRoutingSecretType = "data-plane-routing" - - // certificates used by entities acting as senders and receivers (users) of the data-plane such as queue - dataPlaneUserSecretType = "data-plane-user" - - // Deprecated used by any data plane element - dataPlaneDeprecatedSecretType = "data-plane" -) - -// Reconciler reconciles a SampleSource object -type reconciler struct { - client kubernetes.Interface - secretLister listerv1.SecretLister - caSecretName string - secretTypeLabelName string - enqueueAfter func(key types.NamespacedName, delay time.Duration) - - logger *zap.SugaredLogger -} - -// Check that our Reconciler implements Interface -var _ Interface = (*reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *reconciler) ReconcileKind(ctx context.Context, secret *corev1.Secret) pkgreconciler.Event { - // This should not happen, but it happens :) https://github.com/knative/pkg/issues/1891 - if !r.shouldReconcile(secret) { - r.logger.Infof("Skipping reconciling secret %s/%s", secret.Namespace, secret.Name) - return nil - } - r.logger.Infof("Updating secret %s/%s", secret.Namespace, secret.Name) - - // Reconcile CA secret first - caSecret, err := r.secretLister.Secrets(system.Namespace()).Get(r.caSecretName) - if apierrors.IsNotFound(err) { - // The secret should be created explicitly by a higher-level system - // that's responsible for install/updates. We simply populate the - // secret information. - return nil - } else if err != nil { - r.logger.Errorf("Error accessing CA certificate secret %s/%s: %v", system.Namespace(), r.caSecretName, err) - return err - } - caCert, caPk, err := parseAndValidateSecret(caSecret, nil) - if err != nil { - r.logger.Infof("CA cert invalid: %v", err) - - // We need to generate a new CA cert, then shortcircuit the reconciler - keyPair, err := certificates.CreateCACerts(caExpirationInterval) - if err != nil { - return fmt.Errorf("cannot generate the CA cert: %w", err) - } - return r.commitUpdatedSecret(ctx, caSecret, keyPair, nil) - } - - // Reconcile the provided secret - var sans []string - switch secret.Labels[r.secretTypeLabelName] { - case dataPlaneRoutingSecretType: - sans = []string{certificates.DataPlaneRoutingSAN, certificates.LegacyFakeDnsName} - case dataPlaneUserSecretType: - sans = []string{certificates.DataPlaneUserSAN(secret.Namespace), certificates.LegacyFakeDnsName} - case dataPlaneDeprecatedSecretType: - sans = []string{certificates.LegacyFakeDnsName} - default: - return fmt.Errorf("unknown cert type: %v", r.secretTypeLabelName) - } - - cert, _, err := parseAndValidateSecret(secret, caSecret.Data[certificates.CertName], sans...) - if err != nil { - r.logger.Infof("Secret %s/%s invalid: %v", secret.Namespace, secret.Name, err) - // Check the secret to reconcile type - - var keyPair *certificates.KeyPair - keyPair, err = certificates.CreateCert(caPk, caCert, expirationInterval, sans...) - if err != nil { - return fmt.Errorf("cannot generate the cert: %w", err) - } - err = r.commitUpdatedSecret(ctx, secret, keyPair, caSecret.Data[certificates.CertName]) - if err != nil { - return err - } - cert, _, err = certificates.ParseCert(keyPair.CertBytes(), keyPair.PrivateKeyBytes()) - if err != nil { - return err - } - } - - r.enqueueBeforeExpiration(secret, cert) - - return nil -} - -// All sans provided are required to be lower case -func parseAndValidateSecret(secret *corev1.Secret, caCert []byte, sans ...string) (*x509.Certificate, *rsa.PrivateKey, error) { - certBytes, ok := secret.Data[certificates.CertName] - if !ok { - return nil, nil, fmt.Errorf("missing cert bytes in %q", certificates.CertName) - } - pkBytes, ok := secret.Data[certificates.PrivateKeyName] - if !ok { - return nil, nil, fmt.Errorf("missing pk bytes in %q", certificates.PrivateKeyName) - } - if caCert != nil { - ca, ok := secret.Data[certificates.CaCertName] - if !ok { - return nil, nil, fmt.Errorf("missing ca cert bytes in %q", certificates.CaCertName) - } - if !bytes.Equal(ca, caCert) { - return nil, nil, fmt.Errorf("ca cert bytes changed in %q", certificates.CaCertName) - } - } - - cert, caPk, err := certificates.ParseCert(certBytes, pkBytes) - if err != nil { - return nil, nil, err - } - if err := certificates.CheckExpiry(cert, rotationThreshold); err != nil { - return nil, nil, err - } - - sanSet := sets.NewString(sans...) - certSet := sets.NewString(cert.DNSNames...) - if !sanSet.Equal(certSet) { - return nil, nil, fmt.Errorf("unexpected SANs") - } - - return cert, caPk, nil -} - -func (r *reconciler) enqueueBeforeExpiration(secret *corev1.Secret, cert *x509.Certificate) { - when := cert.NotAfter.Add(-rotationThreshold).Add(1 * time.Second) // Make sure to enqueue it after the rotation threshold - r.enqueueAfter(types.NamespacedName{ - Namespace: secret.Namespace, - Name: secret.Name, - }, time.Until(when)) -} - -func (r *reconciler) commitUpdatedSecret(ctx context.Context, secret *corev1.Secret, keyPair *certificates.KeyPair, caCert []byte) error { - // Don't modify the informer copy. - secret = secret.DeepCopy() - - secret.Data = make(map[string][]byte, 3) - secret.Data[certificates.CertName] = keyPair.CertBytes() - secret.Data[certificates.PrivateKeyName] = keyPair.PrivateKeyBytes() - secret.Data[certificates.SecretCertKey] = keyPair.CertBytes() - secret.Data[certificates.SecretPKKey] = keyPair.PrivateKeyBytes() - if caCert != nil { - secret.Data[certificates.SecretCaCertKey] = caCert - secret.Data[certificates.CaCertName] = caCert - } - - _, err := r.client.CoreV1().Secrets(secret.Namespace).Update(ctx, secret, metav1.UpdateOptions{}) - return err -} - -func (r *reconciler) shouldReconcile(secret *corev1.Secret) bool { - // Is CA secret? - if secret.Name == r.caSecretName && secret.Namespace == system.Namespace() { - return false - } - - _, hasLabel := secret.Labels[r.secretTypeLabelName] - return hasLabel -} diff --git a/vendor/knative.dev/networking/pkg/certificates/reconciler/controller.go b/vendor/knative.dev/networking/pkg/certificates/reconciler/controller.go deleted file mode 100644 index 43f475773207..000000000000 --- a/vendor/knative.dev/networking/pkg/certificates/reconciler/controller.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2021 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 reconciler - -import ( - "context" - - v1 "k8s.io/client-go/informers/core/v1" - "k8s.io/client-go/tools/cache" - kubeclient "knative.dev/pkg/client/injection/kube/client" - "knative.dev/pkg/injection" - "knative.dev/pkg/system" - - "knative.dev/pkg/configmap" - "knative.dev/pkg/controller" - "knative.dev/pkg/logging" - - pkgreconciler "knative.dev/pkg/reconciler" - - secretfilteredinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/secret/filtered" - filteredFactory "knative.dev/pkg/client/injection/kube/informers/factory/filtered" -) - -const ( - caSecretNamePostfix = "-ctrl-ca" - secretLabelNamePostfix = "-ctrl" -) - -// NewControllerFactory generates a ControllerConstructor for the control certificates reconciler. -func NewControllerFactory(componentName string) injection.ControllerConstructor { - return func( - ctx context.Context, - cmw configmap.Watcher, - ) *controller.Impl { - - caSecretName := componentName + caSecretNamePostfix - labelName := componentName + secretLabelNamePostfix - - ctx = filteredFactory.WithSelectors(ctx, labelName) - secretInformer := getSecretInformer(ctx) - - r := &reconciler{ - client: kubeclient.Get(ctx), - - secretLister: secretInformer.Lister(), - caSecretName: caSecretName, - secretTypeLabelName: labelName, - - logger: logging.FromContext(ctx), - } - - impl := NewFilteredImpl(ctx, r, secretInformer) - r.enqueueAfter = impl.EnqueueKeyAfter - - logging.FromContext(ctx).Info("Setting up event handlers") - - // If the ca secret changes, global resync - secretInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: controller.FilterWithNameAndNamespace(system.Namespace(), caSecretName), - Handler: controller.HandleAll(func(i interface{}) { - impl.FilteredGlobalResync(pkgreconciler.LabelExistsFilterFunc(labelName), secretInformer.Informer()) - }), - }) - - // Enqueue only secrets with expected label - secretInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: pkgreconciler.LabelExistsFilterFunc(labelName), - Handler: controller.HandleAll(impl.Enqueue), - }) - - return impl - } -} - -func getSecretInformer(ctx context.Context) v1.SecretInformer { - untyped := ctx.Value(filteredFactory.LabelKey{}) // This should always be not nil and have exactly one selector - return secretfilteredinformer.Get(ctx, untyped.([]string)[0]) -} diff --git a/vendor/knative.dev/networking/pkg/certificates/reconciler/controller_impl.go b/vendor/knative.dev/networking/pkg/certificates/reconciler/controller_impl.go deleted file mode 100644 index 908f33f6645a..000000000000 --- a/vendor/knative.dev/networking/pkg/certificates/reconciler/controller_impl.go +++ /dev/null @@ -1,103 +0,0 @@ -/* -Copyright 2022 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 reconciler - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - zap "go.uber.org/zap" - corev1 "k8s.io/api/core/v1" - watch "k8s.io/apimachinery/pkg/watch" - informersv1 "k8s.io/client-go/informers/core/v1" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - client "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - logkey "knative.dev/pkg/logging/logkey" -) - -const ( - defaultControllerAgentName = "secret-controller" - defaultFinalizerName = "secrets.core" -) - -// NewFilteredImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.ControllerOptions to be used by the internal reconciler. -func NewFilteredImpl(ctx context.Context, r Interface, secretInformer informersv1.SecretInformer, options ...controller.Options) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatal("Up to one options function is supported, found: ", len(options)) - } - - lister := secretInformer.Lister() - - agentName := defaultControllerAgentName - recorder := createRecorder(ctx, agentName) - - rec := NewReconciler(ctx, logger, client.Get(ctx), lister, recorder, r, options...) - - ctrType := reflect.TypeOf(r).Elem() - ctrTypeName := fmt.Sprintf("%s.%s", ctrType.PkgPath(), ctrType.Name()) - ctrTypeName = strings.ReplaceAll(ctrTypeName, "/", ".") - - logger = logger.With( - zap.String(logkey.ControllerType, ctrTypeName), - zap.String(logkey.Kind, "core.Secret"), - ) - - impl := controller.NewContext(ctx, rec, controller.ControllerOptions{WorkQueueName: ctrTypeName, Logger: logger}) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: client.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - scheme.AddToScheme(scheme.Scheme) -} diff --git a/vendor/knative.dev/networking/pkg/certificates/reconciler/reconciler.go b/vendor/knative.dev/networking/pkg/certificates/reconciler/reconciler.go deleted file mode 100644 index d036ba0f0115..000000000000 --- a/vendor/knative.dev/networking/pkg/certificates/reconciler/reconciler.go +++ /dev/null @@ -1,434 +0,0 @@ -/* -Copyright 2022 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. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package reconciler - -import ( - context "context" - json "encoding/json" - fmt "fmt" - - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - kubernetes "k8s.io/client-go/kubernetes" - corev1 "k8s.io/client-go/listers/core/v1" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - pkgreconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1.Secret. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1.Secret. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1.Secret) pkgreconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1.Secret. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1.Secret. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1.Secret) pkgreconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1.Secret if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1.Secret. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1.Secret) pkgreconciler.Event -} - -// state is used to track the state of a reconciler in a single run. -type state struct { - // key is the original reconciliation key from the queue. - key string - // namespace is the namespace split from the reconciliation key. - namespace string - // name is the name split from the reconciliation key. - name string - // reconciler is the reconciler. - reconciler Interface - // roi is the read only interface cast of the reconciler. - roi ReadOnlyInterface - // isROI (Read Only Interface) the reconciler only observes reconciliation. - isROI bool - // isLeader the instance of the reconciler is the elected leader. - isLeader bool -} - -type doReconcile func(ctx context.Context, o *v1.Secret) pkgreconciler.Event - -// reconcilerImpl implements controller.Reconciler for v1.Secret resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware. - pkgreconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client kubernetes.Interface - - // Listers index properties about resources. - Lister corev1.SecretLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore pkgreconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler. -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ pkgreconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client kubernetes.Interface, lister corev1.SecretLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatal("Up to one options struct is supported, found: ", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(pkgreconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - - rec := &reconcilerImpl{ - LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.DemoteFunc != nil { - rec.DemoteFunc = opts.DemoteFunc - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Initialize the reconciler state. This will convert the namespace/name - // string into a distinct namespace and name, determine if this instance of - // the reconciler is the leader, and any additional interfaces implemented - // by the reconciler. Returns an error is the resource key is invalid. - s, err := newState(key, r) - if err != nil { - logger.Error("Invalid resource key: ", key) - return nil - } - - // If we are not the leader, and we don't implement either ReadOnly - // observer interfaces, then take a fast-path out. - if s.isNotLeaderNorObserver() { - return controller.NewSkipKey(key) - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.Secrets(s.namespace) - - original, err := getter.Get(s.name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing and call - // the ObserveDeletion handler if appropriate. - logger.Debugf("Resource %q no longer exists", key) - if del, ok := r.reconciler.(pkgreconciler.OnDeletionInterface); ok { - return del.ObserveDeletion(ctx, types.NamespacedName{ - Namespace: s.namespace, - Name: s.name, - }) - } - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent pkgreconciler.Event - - name, do := s.reconcileMethodFor(resource) - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", name)) - switch name { - case pkgreconciler.DoReconcileKind: - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = do(ctx, resource) - - case pkgreconciler.DoFinalizeKind: - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = do(ctx, resource) - - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - - case pkgreconciler.DoObserveKind: - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = do(ctx, resource) - - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *pkgreconciler.ReconcilerEvent - if pkgreconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Event(resource, event.EventType, event.Reason, event.Error()) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*pkgreconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - if controller.IsSkipKey(reconcileEvent) { - // This is a wrapped error, don't emit an event. - } else if ok, _ := controller.IsRequeueKey(reconcileEvent); ok { - // This is a wrapped error, don't emit an event. - } else { - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - } - return reconcileEvent - } - - return nil -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.Secret, desiredFinalizers sets.String) (*v1.Secret, error) { - // Don't modify the informers copy. - existing := resource.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.CoreV1().Secrets(resource.Namespace) - - resourceName := resource.Name - updated, err := patcher.Patch(ctx, resourceName, types.MergePatchType, patch, metav1.PatchOptions{}) - if err != nil { - r.Recorder.Eventf(existing, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(updated, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return updated, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.Secret) (*v1.Secret, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource, finalizers) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.Secret, reconcileEvent pkgreconciler.Event) (*v1.Secret, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *pkgreconciler.ReconcilerEvent - if pkgreconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource, finalizers) -} - -func newState(key string, r *reconcilerImpl) (*state, error) { - // Convert the namespace/name string into a distinct namespace and name. - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - return nil, fmt.Errorf("invalid resource key: %s", key) - } - - roi, isROI := r.reconciler.(ReadOnlyInterface) - - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - - return &state{ - key: key, - namespace: namespace, - name: name, - reconciler: r.reconciler, - roi: roi, - isROI: isROI, - isLeader: isLeader, - }, nil -} - -// isNotLeaderNorObserver checks to see if this reconciler with the current -// state is enabled to do any work or not. -// isNotLeaderNorObserver returns true when there is no work possible for the -// reconciler. -func (s *state) isNotLeaderNorObserver() bool { - if !s.isLeader && !s.isROI { - // If we are not the leader, and we don't implement the ReadOnly - // interface, then take a fast-path out. - return true - } - return false -} - -func (s *state) reconcileMethodFor(o *v1.Secret) (string, doReconcile) { - if o.GetDeletionTimestamp().IsZero() { - if s.isLeader { - return pkgreconciler.DoReconcileKind, s.reconciler.ReconcileKind - } else if s.isROI { - return pkgreconciler.DoObserveKind, s.roi.ObserveKind - } - } else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok { - return pkgreconciler.DoFinalizeKind, fin.FinalizeKind - } - return "unknown", nil -} diff --git a/vendor/knative.dev/networking/pkg/config/config.go b/vendor/knative.dev/networking/pkg/config/config.go index 028937067b70..b9fca8585c24 100644 --- a/vendor/knative.dev/networking/pkg/config/config.go +++ b/vendor/knative.dev/networking/pkg/config/config.go @@ -67,12 +67,6 @@ const ( // Certificate reconciler. CertManagerCertificateClassName = "cert-manager.certificate.networking.knative.dev" - // ServingInternalCertName is the name of secret contains certificates in serving - // system namespace. - // - // Deprecated: ServingInternalCertName is deprecated. Use ServingRoutingCertName instead. - ServingInternalCertName = "knative-serving-certs" - // ServingRoutingCertName is the name of secret contains certificates for Routing data in serving // system namespace. (Used by Ingress GWs and Activator) ServingRoutingCertName = "routing-serving-certs" @@ -148,6 +142,20 @@ const ( SystemInternalTLSKey = "system-internal-tls" ) +// CertificateType indicates the type of Knative Certificate. +type CertificateType string + +const ( + // CertificateSystemInternal defines a certificate used for `system-internal-tls`. + CertificateSystemInternal CertificateType = "system-internal" + + // CertificateClusterLocalDomain defines a certificate used for `cluster-local-domain-tls`. + CertificateClusterLocalDomain CertificateType = "cluster-local-domain" + + // CertificateExternalDomain defines a cerificate used for `external-domain-tls`. + CertificateExternalDomain CertificateType = "external-domain" +) + // EncryptionConfig indicates the encryption configuration // used for TLS connections. type EncryptionConfig string diff --git a/vendor/knative.dev/pkg/client/injection/kube/informers/core/v1/secret/filtered/secret.go b/vendor/knative.dev/pkg/client/injection/kube/informers/core/v1/secret/filtered/secret.go deleted file mode 100644 index 80d46c400c37..000000000000 --- a/vendor/knative.dev/pkg/client/injection/kube/informers/core/v1/secret/filtered/secret.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2022 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. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package filtered - -import ( - context "context" - - v1 "k8s.io/client-go/informers/core/v1" - filtered "knative.dev/pkg/client/injection/kube/informers/factory/filtered" - controller "knative.dev/pkg/controller" - injection "knative.dev/pkg/injection" - logging "knative.dev/pkg/logging" -) - -func init() { - injection.Default.RegisterFilteredInformers(withInformer) -} - -// Key is used for associating the Informer inside the context.Context. -type Key struct { - Selector string -} - -func withInformer(ctx context.Context) (context.Context, []controller.Informer) { - untyped := ctx.Value(filtered.LabelKey{}) - if untyped == nil { - logging.FromContext(ctx).Panic( - "Unable to fetch labelkey from context.") - } - labelSelectors := untyped.([]string) - infs := []controller.Informer{} - for _, selector := range labelSelectors { - f := filtered.Get(ctx, selector) - inf := f.Core().V1().Secrets() - ctx = context.WithValue(ctx, Key{Selector: selector}, inf) - infs = append(infs, inf.Informer()) - } - return ctx, infs -} - -// Get extracts the typed informer from the context. -func Get(ctx context.Context, selector string) v1.SecretInformer { - untyped := ctx.Value(Key{Selector: selector}) - if untyped == nil { - logging.FromContext(ctx).Panicf( - "Unable to fetch k8s.io/client-go/informers/core/v1.SecretInformer with selector %s from context.", selector) - } - return untyped.(v1.SecretInformer) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1ae858b849e7..4fed643dc9c9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1301,14 +1301,13 @@ knative.dev/caching/pkg/client/listers/caching/v1alpha1 # knative.dev/hack v0.0.0-20231109190034-5deaddeb51a7 ## explicit; go 1.18 knative.dev/hack -# knative.dev/networking v0.0.0-20231108061732-e0bee342a97e +# knative.dev/networking v0.0.0-20231108061732-e0bee342a97e => /Users/rlehmann/code/knative/networking ## explicit; go 1.18 knative.dev/networking/config knative.dev/networking/pkg knative.dev/networking/pkg/apis/networking knative.dev/networking/pkg/apis/networking/v1alpha1 knative.dev/networking/pkg/certificates -knative.dev/networking/pkg/certificates/reconciler knative.dev/networking/pkg/client/clientset/versioned knative.dev/networking/pkg/client/clientset/versioned/fake knative.dev/networking/pkg/client/clientset/versioned/scheme @@ -1376,7 +1375,6 @@ knative.dev/pkg/client/injection/kube/informers/core/v1/pod/filtered knative.dev/pkg/client/injection/kube/informers/core/v1/pod/filtered/fake knative.dev/pkg/client/injection/kube/informers/core/v1/secret knative.dev/pkg/client/injection/kube/informers/core/v1/secret/fake -knative.dev/pkg/client/injection/kube/informers/core/v1/secret/filtered knative.dev/pkg/client/injection/kube/informers/core/v1/service knative.dev/pkg/client/injection/kube/informers/core/v1/service/fake knative.dev/pkg/client/injection/kube/informers/factory @@ -1472,3 +1470,4 @@ sigs.k8s.io/structured-merge-diff/v4/value sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 # github.com/gorilla/websocket => github.com/gorilla/websocket v1.5.0 +# knative.dev/networking => /Users/rlehmann/code/knative/networking