diff --git a/go.mod b/go.mod index 3c3509a7dd..9e4fd81941 100644 --- a/go.mod +++ b/go.mod @@ -21,10 +21,10 @@ require ( k8s.io/client-go v0.26.5 k8s.io/code-generator v0.26.5 k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 - knative.dev/eventing v0.38.4 + knative.dev/eventing v0.38.5 knative.dev/hack v0.0.0-20230712131415-ddae80293c43 - knative.dev/pkg v0.0.0-20231011193800-bd99f2f98be7 - knative.dev/reconciler-test v0.0.0-20231010075208-03cc77c11831 + knative.dev/pkg v0.0.0-20231023150739-56bfe0dd9626 + knative.dev/reconciler-test v0.0.0-20231023114057-785e0bd2d9a2 sigs.k8s.io/controller-runtime v0.14.6 ) diff --git a/go.sum b/go.sum index 4c1aa00927..de1ae996ce 100644 --- a/go.sum +++ b/go.sum @@ -883,14 +883,14 @@ k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+O k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU= k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -knative.dev/eventing v0.38.4 h1:eH059bfeLilj2xAN6V7XXOh3wqzz5ssoMS/CIJpJfmk= -knative.dev/eventing v0.38.4/go.mod h1:ct8t+v6nmp1kFCy6ngkDWIEvnjJDNDoKptrfnQVh+z8= +knative.dev/eventing v0.38.5 h1:NvSy3lek9IbLLWEot36NyAfNv7VkJNl38F1ItVL0D6s= +knative.dev/eventing v0.38.5/go.mod h1:g+iAS+KBRSKULEPqoVnseMkObDeq3SJhqefbuIu8zY8= knative.dev/hack v0.0.0-20230712131415-ddae80293c43 h1:3SE06uNfSFGm/5XS+0trbyCUpgsOaBeyhPQU8FPNFz8= knative.dev/hack v0.0.0-20230712131415-ddae80293c43/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q= -knative.dev/pkg v0.0.0-20231011193800-bd99f2f98be7 h1:y3qbfYX1SuSr/1ysXvKfpV8q/kCwWLWieCUgAhBUHmQ= -knative.dev/pkg v0.0.0-20231011193800-bd99f2f98be7/go.mod h1:g+UCgSKQ2f15kHYu/V3CPtoKo5F1x/2Y1ot0NSK7gA0= -knative.dev/reconciler-test v0.0.0-20231010075208-03cc77c11831 h1:rOisVvTe0yuJNImgOex1Z4vdqXRPP1FAg5xPxbLOSlU= -knative.dev/reconciler-test v0.0.0-20231010075208-03cc77c11831/go.mod h1:i+/PWK/n3HPgjXMoj5U7CA6WRW/C3c3EfHCQ0FmrhNM= +knative.dev/pkg v0.0.0-20231023150739-56bfe0dd9626 h1:qFE+UDBRg6cpF5LbA0sv1XK4XZ36Z7aTRCa+HcuxnNQ= +knative.dev/pkg v0.0.0-20231023150739-56bfe0dd9626/go.mod h1:g+UCgSKQ2f15kHYu/V3CPtoKo5F1x/2Y1ot0NSK7gA0= +knative.dev/reconciler-test v0.0.0-20231023114057-785e0bd2d9a2 h1:Lenj/sGhPYZoCdl4bvoeZzA4Y1VS4LNEIWH1/HTU+6I= +knative.dev/reconciler-test v0.0.0-20231023114057-785e0bd2d9a2/go.mod h1:HgugJUOhHZ3F6Tbhte92ecL0sBqJtCeJtd7K8jX+IJk= pgregory.net/rapid v0.3.3 h1:jCjBsY4ln4Atz78QoBWxUEvAHaFyNDQg9+WU62aCn1U= pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/vendor/knative.dev/eventing/test/rekt/features/broker/eventing_tls_feature.go b/vendor/knative.dev/eventing/test/rekt/features/broker/eventing_tls_feature.go new file mode 100644 index 0000000000..a170055060 --- /dev/null +++ b/vendor/knative.dev/eventing/test/rekt/features/broker/eventing_tls_feature.go @@ -0,0 +1,105 @@ +/* +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 broker + +import ( + "context" + "time" + + cetest "github.com/cloudevents/sdk-go/v2/test" + "github.com/google/uuid" + "k8s.io/apimachinery/pkg/types" + "knative.dev/pkg/system" + "knative.dev/reconciler-test/pkg/eventshub" + "knative.dev/reconciler-test/pkg/eventshub/assert" + "knative.dev/reconciler-test/pkg/feature" + "knative.dev/reconciler-test/pkg/resources/service" + "knative.dev/reconciler-test/resources/certificate" + + "knative.dev/eventing/test/rekt/features/featureflags" + "knative.dev/eventing/test/rekt/resources/addressable" + "knative.dev/eventing/test/rekt/resources/broker" + "knative.dev/eventing/test/rekt/resources/trigger" +) + +func RotateMTChannelBrokerTLSCertificates() *feature.Feature { + ingressCertificateName := "mt-broker-ingress-server-tls" + ingressSecretName := "mt-broker-ingress-server-tls" + + filterCertificateName := "mt-broker-filter-server-tls" + + brokerName := feature.MakeRandomK8sName("broker") + triggerName := feature.MakeRandomK8sName("trigger") + sink := feature.MakeRandomK8sName("sink") + source := feature.MakeRandomK8sName("source") + + f := feature.NewFeatureNamed("Rotate MTChannelBroker TLS certificate") + + f.Prerequisite("transport encryption is strict", featureflags.TransportEncryptionStrict()) + f.Prerequisite("should not run when Istio is enabled", featureflags.IstioDisabled()) + + f.Setup("Rotate ingress certificate", certificate.Rotate(certificate.RotateCertificate{ + Certificate: types.NamespacedName{ + Namespace: system.Namespace(), + Name: ingressCertificateName, + }, + })) + // We cannot externally verify this certificate rotation + f.Setup("Rotate filter certificate", certificate.Rotate(certificate.RotateCertificate{ + Certificate: types.NamespacedName{ + Namespace: system.Namespace(), + Name: filterCertificateName, + }, + })) + + f.Setup("install sink", eventshub.Install(sink, eventshub.StartReceiverTLS)) + f.Setup("install broker", broker.Install(brokerName, broker.WithEnvConfig()...)) + f.Setup("Broker is ready", broker.IsReady(brokerName)) + f.Setup("install trigger", func(ctx context.Context, t feature.T) { + d := service.AsDestinationRef(sink) + d.CACerts = eventshub.GetCaCerts(ctx) + trigger.Install(triggerName, brokerName, trigger.WithSubscriberFromDestination(d))(ctx, t) + }) + f.Setup("trigger is ready", trigger.IsReady(triggerName)) + f.Setup("Broker has HTTPS address", broker.ValidateAddress(brokerName, addressable.AssertHTTPSAddress)) + + event := cetest.FullEvent() + event.SetID(uuid.New().String()) + + f.Requirement("install source", eventshub.Install(source, + eventshub.StartSenderToResourceTLS(broker.GVR(), brokerName, nil), + eventshub.InputEvent(event), + // Send multiple events so that we take into account that the certificate rotation might + // be detected by the server after some time. + eventshub.SendMultipleEvents(100, 3*time.Second), + )) + + f.Assert("Event sent", assert.OnStore(source). + MatchSentEvent(cetest.HasId(event.ID())). + AtLeast(1), + ) + f.Assert("Event received", assert.OnStore(sink). + MatchReceivedEvent(cetest.HasId(event.ID())). + AtLeast(1), + ) + f.Assert("Source match updated peer certificate", assert.OnStore(source). + MatchPeerCertificatesReceived(assert.MatchPeerCertificatesFromSecret(system.Namespace(), ingressSecretName, "tls.crt")). + AtLeast(1), + ) + + return f +} diff --git a/vendor/knative.dev/eventing/test/rekt/features/featureflags/featureflags.go b/vendor/knative.dev/eventing/test/rekt/features/featureflags/featureflags.go index 0ba4a2c7c8..8d007d96fe 100644 --- a/vendor/knative.dev/eventing/test/rekt/features/featureflags/featureflags.go +++ b/vendor/knative.dev/eventing/test/rekt/features/featureflags/featureflags.go @@ -46,6 +46,20 @@ func TransportEncryptionPermissiveOrStrict() feature.ShouldRun { } } +func TransportEncryptionStrict() feature.ShouldRun { + return func(ctx context.Context, t feature.T) (feature.PrerequisiteResult, error) { + flags, err := getFeatureFlags(ctx, "config-features") + if err != nil { + return feature.PrerequisiteResult{}, err + } + + return feature.PrerequisiteResult{ + ShouldRun: flags.IsStrictTransportEncryption(), + Reason: flags.String(), + }, nil + } +} + func IstioDisabled() feature.ShouldRun { return func(ctx context.Context, t feature.T) (feature.PrerequisiteResult, error) { flags, err := getFeatureFlags(ctx, "config-features") diff --git a/vendor/knative.dev/eventing/test/rekt/resources/addressable/addressable.go b/vendor/knative.dev/eventing/test/rekt/resources/addressable/addressable.go index d8c566186b..df3997e261 100644 --- a/vendor/knative.dev/eventing/test/rekt/resources/addressable/addressable.go +++ b/vendor/knative.dev/eventing/test/rekt/resources/addressable/addressable.go @@ -18,6 +18,7 @@ package addressable import ( "context" + "fmt" "time" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -27,6 +28,8 @@ import ( "knative.dev/reconciler-test/pkg/k8s" ) +type ValidateAddress func(addressable *duckv1.Addressable) error + // Address returns a broker's address. func Address(ctx context.Context, gvr schema.GroupVersionResource, name string, timings ...time.Duration) (*duckv1.Addressable, error) { interval, timeout := k8s.PollTimings(ctx, timings) @@ -51,3 +54,10 @@ func Address(ctx context.Context, gvr schema.GroupVersionResource, name string, }) return addr, err } + +func AssertHTTPSAddress(addr *duckv1.Addressable) error { + if addr.URL.Scheme != "https" { + return fmt.Errorf("address is not HTTPS: %#v", addr) + } + return nil +} diff --git a/vendor/knative.dev/eventing/test/rekt/resources/broker/broker.go b/vendor/knative.dev/eventing/test/rekt/resources/broker/broker.go index cdabc65815..27d7adde92 100644 --- a/vendor/knative.dev/eventing/test/rekt/resources/broker/broker.go +++ b/vendor/knative.dev/eventing/test/rekt/resources/broker/broker.go @@ -158,6 +158,21 @@ func IsAddressable(name string, timings ...time.Duration) feature.StepFn { return k8s.IsAddressable(GVR(), name, timings...) } +// ValidateAddress validates the address retured by Address +func ValidateAddress(name string, validate addressable.ValidateAddress, timings ...time.Duration) feature.StepFn { + return func(ctx context.Context, t feature.T) { + addr, err := Address(ctx, name, timings...) + if err != nil { + t.Error(err) + return + } + if err := validate(addr); err != nil { + t.Error(err) + return + } + } +} + // Address returns a broker's address. func Address(ctx context.Context, name string, timings ...time.Duration) (*duckv1.Addressable, error) { return addressable.Address(ctx, GVR(), name, timings...) diff --git a/vendor/knative.dev/eventing/test/rekt/resources/channel_impl/channel_impl.go b/vendor/knative.dev/eventing/test/rekt/resources/channel_impl/channel_impl.go index 428df32d6a..b7a08d2b9b 100644 --- a/vendor/knative.dev/eventing/test/rekt/resources/channel_impl/channel_impl.go +++ b/vendor/knative.dev/eventing/test/rekt/resources/channel_impl/channel_impl.go @@ -172,3 +172,18 @@ func AsDestinationRef(name string) *duckv1.Destination { // WithDeadLetterSink adds the dead letter sink related config to a Subscription spec. var WithDeadLetterSink = delivery.WithDeadLetterSink + +// ValidateAddress validates the address retured by Address +func ValidateAddress(name string, validate addressable.ValidateAddress, timings ...time.Duration) feature.StepFn { + return func(ctx context.Context, t feature.T) { + addr, err := Address(ctx, name, timings...) + if err != nil { + t.Error(err) + return + } + if err := validate(addr); err != nil { + t.Error(err) + return + } + } +} diff --git a/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.go b/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.go index fa9b8e2298..a2b26c3437 100644 --- a/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.go +++ b/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.go @@ -19,14 +19,16 @@ package subscription import ( "context" "embed" + "strings" "time" "k8s.io/apimachinery/pkg/runtime/schema" - "knative.dev/eventing/test/rekt/resources/delivery" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/reconciler-test/pkg/feature" "knative.dev/reconciler-test/pkg/k8s" "knative.dev/reconciler-test/pkg/manifest" + + "knative.dev/eventing/test/rekt/resources/delivery" ) //go:embed *.yaml @@ -128,3 +130,36 @@ func Install(name string, opts ...manifest.CfgFn) feature.StepFn { func IsReady(name string, timing ...time.Duration) feature.StepFn { return k8s.IsReady(gvr(), name, timing...) } + +// WithSubscriberFromDestination adds the subscriber related config to a Trigger spec. +func WithSubscriberFromDestination(dest *duckv1.Destination) manifest.CfgFn { + return func(cfg map[string]interface{}) { + if _, set := cfg["subscriber"]; !set { + cfg["subscriber"] = map[string]interface{}{} + } + subscriber := cfg["subscriber"].(map[string]interface{}) + + uri := dest.URI + ref := dest.Ref + + if dest.CACerts != nil { + // This is a multi-line string and should be indented accordingly. + // Replace "new line" with "new line + spaces". + subscriber["CACerts"] = strings.ReplaceAll(*dest.CACerts, "\n", "\n ") + } + + if uri != nil { + subscriber["uri"] = uri.String() + } + if ref != nil { + if _, set := subscriber["ref"]; !set { + subscriber["ref"] = map[string]interface{}{} + } + sref := subscriber["ref"].(map[string]interface{}) + sref["apiVersion"] = ref.APIVersion + sref["kind"] = ref.Kind + // skip namespace + sref["name"] = ref.Name + } + } +} diff --git a/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.yaml b/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.yaml index 345a3c8a59..82db40579a 100644 --- a/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.yaml +++ b/vendor/knative.dev/eventing/test/rekt/resources/subscription/subscription.yaml @@ -36,6 +36,10 @@ spec: {{ if .subscriber.uri }} uri: {{ .subscriber.uri }} {{ end }} + {{ if .subscriber.CACerts }} + CACerts: |- + {{ .subscriber.CACerts }} + {{ end }} {{ end }} {{if .reply }} reply: @@ -53,6 +57,10 @@ spec: {{ if .reply.uri }} uri: {{ .reply.uri }} {{ end }} + {{ if .reply.CACerts }} + CACerts: |- + {{ .reply.CACerts }} + {{ end }} {{ end }} {{ if .delivery }} delivery: @@ -72,6 +80,10 @@ spec: {{ if .delivery.deadLetterSink.uri }} uri: {{ .delivery.deadLetterSink.uri }} {{ end }} + {{ if .delivery.deadLetterSink.CACerts }} + CACerts: |- + {{ .delivery.deadLetterSink.CACerts }} + {{ end }} {{ end }} {{ if .delivery.retry }} retry: {{ .delivery.retry}} diff --git a/vendor/knative.dev/pkg/webhook/webhook.go b/vendor/knative.dev/pkg/webhook/webhook.go index 92dd01ae35..26f20a71b6 100644 --- a/vendor/knative.dev/pkg/webhook/webhook.go +++ b/vendor/knative.dev/pkg/webhook/webhook.go @@ -74,6 +74,17 @@ type Options struct { // ControllerOptions encapsulates options for creating a new controller, // including throttling and stats behavior. ControllerOptions *controller.ControllerOptions + + // EnableHTTP2 enables HTTP2 for webhooks. + // Mitigate CVE-2023-44487 by disabling HTTP2 by default until the Go + // standard library and golang.org/x/net are fully fixed. + // Right now, it is possible for authenticated and unauthenticated users to + // hold open HTTP2 connections and consume huge amounts of memory. + // See: + // * https://github.com/kubernetes/kubernetes/pull/121120 + // * https://github.com/kubernetes/kubernetes/issues/121197 + // * https://github.com/golang/go/issues/63417#issuecomment-1758858612 + EnableHTTP2 bool } // Operation is the verb being operated on @@ -237,12 +248,19 @@ func (wh *Webhook) Run(stop <-chan struct{}) error { QuietPeriod: wh.Options.GracePeriod, } + // If TLSNextProto is not nil, HTTP/2 support is not enabled automatically. + nextProto := map[string]func(*http.Server, *tls.Conn, http.Handler){} + if wh.Options.EnableHTTP2 { + nextProto = nil + } + server := &http.Server{ ErrorLog: log.New(&zapWrapper{logger}, "", 0), Handler: drainer, Addr: fmt.Sprint(":", wh.Options.Port), TLSConfig: wh.tlsConfig, ReadHeaderTimeout: time.Minute, //https://medium.com/a-journey-with-go/go-understand-and-mitigate-slowloris-attack-711c1b1403f6 + TLSNextProto: nextProto, } var serve = server.ListenAndServe diff --git a/vendor/knative.dev/reconciler-test/pkg/environment/namespace.go b/vendor/knative.dev/reconciler-test/pkg/environment/namespace.go index 18c73c8e10..939f382eec 100644 --- a/vendor/knative.dev/reconciler-test/pkg/environment/namespace.go +++ b/vendor/knative.dev/reconciler-test/pkg/environment/namespace.go @@ -122,12 +122,26 @@ func (mr *MagicEnvironment) CreateNamespaceIfNeeded() error { return fmt.Errorf("error copying the image pull Secret: %s", err) } - _, err = c.CoreV1().ServiceAccounts(mr.namespace).Patch(context.Background(), sa.Name, types.StrategicMergePatchType, - []byte(`{"imagePullSecrets":[{"name":"`+mr.imagePullSecretName+`"}]}`), metav1.PatchOptions{}) + for _, secret := range sa.ImagePullSecrets { + if secret.Name == mr.imagePullSecretName { + return nil + } + } + + // Prevent overwriting existing imagePullSecrets + patch := `[{"op":"add","path":"/imagePullSecrets/-","value":{"name":"` + mr.imagePullSecretName + `"}}]` + if len(sa.ImagePullSecrets) == 0 { + patch = `[{"op":"add","path":"/imagePullSecrets","value":[{"name":"` + mr.imagePullSecretName + `"}]}]` + } + + _, err = c.CoreV1().ServiceAccounts(mr.namespace).Patch(context.Background(), sa.Name, types.JSONPatchType, + []byte(patch), metav1.PatchOptions{}) if err != nil { - return fmt.Errorf("patch failed on NS/SA (%s/%s): %s", mr.namespace, sa.Name, err) + return fmt.Errorf("patch failed on NS/SA (%s/%s): %w", + mr.namespace, sa.Name, err) } } + return nil } diff --git a/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/100-sa.yaml b/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/100-sa.yaml index f86b523942..2cafc9ab1b 100644 --- a/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/100-sa.yaml +++ b/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/100-sa.yaml @@ -17,3 +17,9 @@ kind: ServiceAccount metadata: name: {{ .name }} namespace: {{ .namespace }} +{{ if .withPullSecrets }} +imagePullSecrets: + {{ range $_, $value := .withPullSecrets.secrets }} + - name: {{ $value }} + {{ end }} +{{ end }} diff --git a/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/rbac.go b/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/rbac.go index de8a2cfbde..5c7494231a 100644 --- a/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/rbac.go +++ b/vendor/knative.dev/reconciler-test/pkg/eventshub/rbac/rbac.go @@ -21,6 +21,9 @@ import ( "embed" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kubeclient "knative.dev/pkg/client/injection/kube/client" + "knative.dev/reconciler-test/pkg/environment" "knative.dev/reconciler-test/pkg/feature" "knative.dev/reconciler-test/pkg/manifest" @@ -30,11 +33,33 @@ import ( var templates embed.FS // Install creates the necessary ServiceAccount, Role, RoleBinding for the eventshub. -// The resources are named according to the current namespace defined in the environment. func Install(cfg map[string]interface{}) feature.StepFn { return func(ctx context.Context, t feature.T) { + WithPullSecrets(ctx, t)(cfg) if _, err := manifest.InstallYamlFS(ctx, templates, cfg); err != nil && !apierrors.IsAlreadyExists(err) { t.Fatal(err) } } } + +func WithPullSecrets(ctx context.Context, t feature.T) manifest.CfgFn { + namespace := environment.FromContext(ctx).Namespace() + serviceAccount, err := kubeclient.Get(ctx).CoreV1().ServiceAccounts(namespace).Get(ctx, "default", metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to read default SA in %s namespace: %v", namespace, err) + } + + return func(cfg map[string]interface{}) { + if len(serviceAccount.ImagePullSecrets) == 0 { + return + } + if _, set := cfg["withPullSecrets"]; !set { + cfg["withPullSecrets"] = map[string]interface{}{} + } + withPullSecrets := cfg["withPullSecrets"].(map[string]interface{}) + withPullSecrets["secrets"] = []string{} + for _, secret := range serviceAccount.ImagePullSecrets { + withPullSecrets["secrets"] = append(withPullSecrets["secrets"].([]string), secret.Name) + } + } +} diff --git a/vendor/knative.dev/reconciler-test/pkg/feature/feature.go b/vendor/knative.dev/reconciler-test/pkg/feature/feature.go index 1c4aef8738..4113bc3d0d 100644 --- a/vendor/knative.dev/reconciler-test/pkg/feature/feature.go +++ b/vendor/knative.dev/reconciler-test/pkg/feature/feature.go @@ -227,6 +227,8 @@ func DeleteResources(ctx context.Context, t T, refs []corev1.ObjectReference) er } } + var lastResource corev1.ObjectReference // One still present resource + err := wait.Poll(time.Second, 4*time.Minute, func() (bool, error) { for _, ref := range refs { gv, err := schema.ParseGroupVersion(ref.APIVersion) @@ -248,6 +250,7 @@ func DeleteResources(ctx context.Context, t T, refs []corev1.ObjectReference) er return false, fmt.Errorf("failed to get resource %+v %s/%s: %w", resource, ref.Namespace, ref.Name, err) } + lastResource = ref t.Logf("Resource %+v %s/%s still present", resource, ref.Namespace, ref.Name) return false, nil } @@ -255,6 +258,7 @@ func DeleteResources(ctx context.Context, t T, refs []corev1.ObjectReference) er return true, nil }) if err != nil { + LogReferences(lastResource)(ctx, t) return fmt.Errorf("failed to wait for resources to be deleted: %v", err) } diff --git a/vendor/knative.dev/reconciler-test/pkg/feature/logging.go b/vendor/knative.dev/reconciler-test/pkg/feature/logging.go index cbbc572e06..2261e30886 100644 --- a/vendor/knative.dev/reconciler-test/pkg/feature/logging.go +++ b/vendor/knative.dev/reconciler-test/pkg/feature/logging.go @@ -26,6 +26,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" + kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/injection/clients/dynamicclient" ) @@ -62,13 +63,26 @@ func logReference(ref corev1.ObjectReference) StepFn { return } - b, err := json.MarshalIndent(r, "", " ") + b, err := json.MarshalIndent(r, "", " ") if err != nil { t.Logf("Failed to marshal %s: %v\n", resourceStr, err) return } - t.Logf("%s\n%s", resourceStr, string(b)) + // Get events for the given resource + events, _ := kubeclient.Get(ctx).EventsV1(). + Events(ref.Namespace). + List(ctx, metav1.ListOptions{ + TypeMeta: metav1.TypeMeta{ + Kind: ref.Kind, + APIVersion: ref.APIVersion, + }, + FieldSelector: fmt.Sprintf("involvedObject.name=%s", ref.Name), + Limit: 50, + }) + eBytes, _ := json.MarshalIndent(events, "", " ") + + t.Logf("%s\n%s\nEvents:\n%s\n", resourceStr, string(b), string(eBytes)) // Recursively log owners for _, or := range r.GetOwnerReferences() { diff --git a/vendor/knative.dev/reconciler-test/resources/certificate/certificate.go b/vendor/knative.dev/reconciler-test/resources/certificate/certificate.go new file mode 100644 index 0000000000..e3e80768e1 --- /dev/null +++ b/vendor/knative.dev/reconciler-test/resources/certificate/certificate.go @@ -0,0 +1,218 @@ +/* +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 certificate + +import ( + "bytes" + "context" + "time" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + kubeclient "knative.dev/pkg/client/injection/kube/client" + "knative.dev/pkg/injection/clients/dynamicclient" + + "knative.dev/reconciler-test/pkg/feature" +) + +var ( + certificateGVR = schema.GroupVersionResource{ + Group: "cert-manager.io", + Version: "v1", + Resource: "certificates", + } +) + +type RotateCertificate struct { + Certificate types.NamespacedName +} + +// Rotate rotates a cert-manager issued certificate. +// The procedure follows the same process as the cert-manager command `cmctl renew ` +// See also https://cert-manager.io/docs/usage/certificate/#actions-triggering-private-key-rotation +func Rotate(rotate RotateCertificate) feature.StepFn { + return func(ctx context.Context, t feature.T) { + before := getSecret(ctx, t, rotate) + issueRotation(ctx, t, rotate) + waitForRotation(ctx, t, rotate, before) + } + +} + +func issueRotation(ctx context.Context, t feature.T, rotate RotateCertificate) { + var lastErr error + err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) { + err := rotateCertificate(ctx, rotate) + if err == nil { + return true, nil + } + lastErr = err + + // Retry on conflicts + if apierrors.IsConflict(err) { + return false, nil + } + + return false, err + }) + if err != nil { + t.Fatal(err, lastErr) + } +} + +type Certificate struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec Spec `json:"spec"` + + Status Status `json:"status"` +} + +type Spec struct { + SecretName string `json:"secretName"` +} + +// Status defines the observed state of Certificate +type Status struct { + duckv1.Status `json:",inline"` + // Copied from https://github.com/cert-manager/cert-manager/blob/master/pkg/apis/certmanager/v1/types_certificate.go + LastFailureTime *metav1.Time `json:"lastFailureTime,omitempty"` + NotBefore *metav1.Time `json:"notBefore,omitempty"` + NotAfter *metav1.Time `json:"notAfter,omitempty"` + RenewalTime *metav1.Time `json:"renewalTime,omitempty"` + Revision *int `json:"revision,omitempty"` + NextPrivateKeySecretName *string `json:"nextPrivateKeySecretName,omitempty"` + FailedIssuanceAttempts *int `json:"failedIssuanceAttempts,omitempty"` +} + +func rotateCertificate(ctx context.Context, rotate RotateCertificate) error { + dc := dynamicclient.Get(ctx).Resource(certificateGVR) + + obj, err := dc. + Namespace(rotate.Certificate.Namespace). + Get(ctx, rotate.Certificate.Name, metav1.GetOptions{}) + if err != nil { + return err + } + + cert := &Certificate{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, cert); err != nil { + return err + } + + renewCertificate(cert) + + obj.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(cert) + if err != nil { + return err + } + + _, err = dc. + Namespace(rotate.Certificate.Namespace). + UpdateStatus(ctx, obj, metav1.UpdateOptions{}) + if err != nil { + return err + } + + return nil +} + +func waitForRotation(ctx context.Context, t feature.T, rotate RotateCertificate, before *corev1.Secret) { + keys := []string{"tls.key", "tls.crt"} + err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) { + current := getSecret(ctx, t, rotate) + for _, key := range keys { + if bytes.Equal(before.Data[key], current.Data[key]) { + t.Logf("Value for key %s is equal", key) + return false, nil + } + } + return true, nil + }) + if err != nil { + t.Errorf("Failed while waiting for Certificate rotation to happen: %v", err) + } +} + +func getSecret(ctx context.Context, t feature.T, rotate RotateCertificate) *corev1.Secret { + obj, err := dynamicclient.Get(ctx).Resource(certificateGVR). + Namespace(rotate.Certificate.Namespace). + Get(ctx, rotate.Certificate.Name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get certificate %s/%s: %v", rotate.Certificate.Namespace, rotate.Certificate.Name, err) + } + + cert := &Certificate{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, cert); err != nil { + t.Fatal(err) + } + + secret, err := kubeclient.Get(ctx). + CoreV1(). + Secrets(rotate.Certificate.Namespace). + Get(ctx, cert.Spec.SecretName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get secret %s/%s: %v", rotate.Certificate.Namespace, cert.Spec.SecretName, err) + } + + return secret +} + +// Adapted from: +// - https://github.com/cert-manager/cert-manager/blob/843deed22f563dbdcbbf71a9fc478609ee90cb8e/pkg/api/util/conditions.go#L165-L204 +// - https://github.com/cert-manager/cert-manager/blob/843deed22f563dbdcbbf71a9fc478609ee90cb8e/cmd/ctl/pkg/renew/renew.go#L206-L214 +func renewCertificate(c *Certificate) { + + newCondition := apis.Condition{ + Type: apis.ConditionType("Issuing"), + Status: corev1.ConditionTrue, + Reason: "ManuallyTriggered", + Message: "Certificate re-issuance manually triggered", + } + + nowTime := metav1.NewTime(time.Now()) + newCondition.LastTransitionTime = apis.VolatileTime{Inner: nowTime} + + // Search through existing conditions + for idx, cond := range c.Status.GetConditions() { + // Skip unrelated conditions + if cond.Type != newCondition.Type { + continue + } + + // If this update doesn't contain a state transition, we don't update + // the conditions LastTransitionTime to Now() + if cond.Status == newCondition.Status { + newCondition.LastTransitionTime = cond.LastTransitionTime + } + + // Overwrite the existing condition + c.Status.Conditions[idx] = newCondition + return + } + + c.Status.SetConditions(append(c.Status.GetConditions(), newCondition)) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 70ef5eb473..7005fde4f3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1052,7 +1052,7 @@ k8s.io/utils/net k8s.io/utils/pointer k8s.io/utils/strings/slices k8s.io/utils/trace -# knative.dev/eventing v0.38.4 +# knative.dev/eventing v0.38.5 ## explicit; go 1.19 knative.dev/eventing/cmd/heartbeats knative.dev/eventing/pkg/adapter/v2 @@ -1163,7 +1163,7 @@ knative.dev/eventing/test/test_images/print # knative.dev/hack v0.0.0-20230712131415-ddae80293c43 ## explicit; go 1.18 knative.dev/hack -# knative.dev/pkg v0.0.0-20231011193800-bd99f2f98be7 +# knative.dev/pkg v0.0.0-20231023150739-56bfe0dd9626 ## explicit; go 1.18 knative.dev/pkg/apis knative.dev/pkg/apis/duck @@ -1268,7 +1268,7 @@ knative.dev/pkg/webhook/json knative.dev/pkg/webhook/resourcesemantics knative.dev/pkg/webhook/resourcesemantics/defaulting knative.dev/pkg/webhook/resourcesemantics/validation -# knative.dev/reconciler-test v0.0.0-20231010075208-03cc77c11831 +# knative.dev/reconciler-test v0.0.0-20231023114057-785e0bd2d9a2 ## explicit; go 1.18 knative.dev/reconciler-test/cmd/eventshub knative.dev/reconciler-test/pkg/environment @@ -1295,6 +1295,7 @@ knative.dev/reconciler-test/pkg/resources/knativeservice knative.dev/reconciler-test/pkg/resources/secret knative.dev/reconciler-test/pkg/resources/service knative.dev/reconciler-test/pkg/state +knative.dev/reconciler-test/resources/certificate # sigs.k8s.io/controller-runtime v0.14.6 ## explicit; go 1.19 sigs.k8s.io/controller-runtime