Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Cert Manager #8509

Merged
merged 8 commits into from
Mar 6, 2025
Merged

Enable Cert Manager #8509

merged 8 commits into from
Mar 6, 2025

Conversation

matzew
Copy link
Member

@matzew matzew commented Feb 26, 2025

Fixes #

Proposed Changes

  • in sink controller we create the cert-mgr informer based on the fact if TLS is enabled

Pre-review Checklist

  • At least 80% unit test coverage
  • E2E tests for any new behavior
  • Docs PR for any user-facing impact
  • Spec PR for any new API feature
  • Conformance test for any change to the spec

Release Note

TLS / Cert Manager integration for IntegrationSink

Docs

@knative-prow knative-prow bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Feb 26, 2025
Copy link

knative-prow bot commented Feb 26, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: matzew

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow knative-prow bot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Feb 26, 2025
@knative-prow knative-prow bot added the area/test-and-release Test infrastructure, tests or release label Feb 26, 2025
@@ -78,3 +76,7 @@ func MakeCertificate(obj kmeta.OwnerRefableAccessor, name string) *cmv1.Certific
},
}
}

func deploymentName(sinkName string) string {
return kmeta.ChildName(sinkName, "-deployment")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think on the "generic" certificate factory we could just pass in the name of the deployment to the MakeCert function

eventPolicyLister: eventPolicyInformer.Lister(),
//cmCertificateLister: cmCertificateInformer.Lister(),
//certManagerClient: cmclient.Get(ctx),
secretLister: secretInformer.Lister(),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

knoob needed

@matzew
Copy link
Member Author

matzew commented Feb 26, 2025

This needs the knob for turning on/off the "cert manager" hooks.

As discussed in #8385 (review)

@matzew
Copy link
Member Author

matzew commented Mar 5, 2025

With the manual created lister, I seem to get error

{"level":"error","ts":"2025-03-05T09:28:42.424Z","logger":"controller","caller":"controller/controller.go:564","msg":"Reconcile error","commit":"794d3a1-dirty","knative.dev/pod":"eventing-controller-f554cb8c9-tgwzz","knative.dev/controller":"knative.dev.eventing.pkg.reconciler.integration.sink.Reconciler","knative.dev/kind":"sinks.knative.dev.IntegrationSink","knative.dev/traceid":"9f6eac8e-fd4f-4229-ba0c-7cef645deb97","knative.dev/key":"test-gpgbdyap/integrationsink-mmxezqvd","duration":0.018033456,"error":"creating new Certificate: certificates.cert-manager.io \"integrationsink-mmxezqvd-server-tls\" already exists","stacktrace":"knative.dev/pkg/controller.(*Impl).handleErr\n\tknative.dev/[email protected]/controller/controller.go:564\nknative.dev/pkg/controller.(*Impl).processNextWorkItem\n\tknative.dev/[email protected]/controller/controller.go:541\nknative.dev/pkg/controller.(*Impl).RunContext.func3\n\tknative.dev/[email protected]/controller/controller.go:489"}

And yes, it gets once created, but I end up in the IsNotFound, where the create than fails like above

https://github.com/matzew/eventing/blob/enable_cert_mgr/pkg/reconciler/integration/sink/integrationsink.go#L175-L183

@pierDipi
Copy link
Member

pierDipi commented Mar 5, 2025

@matzew you need to label the certificate with that label app.kubernetes.io/component=knative-eventing https://github.com/matzew/eventing/blob/1ae012d15dde0de849b485de71382fa726ab0a47/pkg/certificates/certificate.go#L37-L41

logging.FromContext(ctx).Errorw("Error reconciling Certificate", zap.Error(err))
return err
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: delete certificate once the feature is turned.

eventPolicyInformer.Informer().AddEventHandler(auth.EventPolicyEventHandler(
integrationSinkInformer.Informer().GetIndexer(),
integrationSinkGK,
impl.EnqueueKey,
))

cmCertificateInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo: better filtering.

@matzew matzew changed the title WIP: Re-enable Cert Mgr Enable Cert Manager Mar 6, 2025
@knative-prow knative-prow bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 6, 2025
@matzew
Copy link
Member Author

matzew commented Mar 6, 2025

TODO: delete certificate once the feature is turned off
-> will do in a separate PR

More unit tests for reconciler will come too

matzew added 6 commits March 6, 2025 09:06
Signed-off-by: Matthias Wessendorf <[email protected]>
Signed-off-by: Matthias Wessendorf <[email protected]>
Signed-off-by: Matthias Wessendorf <[email protected]>
Signed-off-by: Matthias Wessendorf <[email protected]>
Signed-off-by: Matthias Wessendorf <[email protected]>
Signed-off-by: Matthias Wessendorf <[email protected]>
@matzew matzew force-pushed the enable_cert_mgr branch from f74f08b to 06bd3bb Compare March 6, 2025 08:06
}()

} else {
cancelFunc, cancelExists := ctx.Value("cancelFunc").(context.CancelFunc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this set?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah. yeah. right

Comment on lines +90 to +94
factory.Start(ctx.Done())

if !cache.WaitForCacheSync(ctx.Done(), cmCertificateInformer.Informer().HasSynced) {
logging.FromContext(ctx).Error("Failed to sync Cert Manager Certificate informer")
}
Copy link
Member

@pierDipi pierDipi Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this ctx will only complete when the pod exits, so this might leak informers watchers/connections, I think we need a "sub-context" for only this factory start/stop

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, let me take a look

Copy link
Member

@pierDipi pierDipi Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diff --git a/pkg/certificates/certificate.go b/pkg/certificates/certificate.go
index 67f7aa308..cb97e58be 100644
--- a/pkg/certificates/certificate.go
+++ b/pkg/certificates/certificate.go
@@ -17,16 +17,96 @@ limitations under the License.
 package certificates
 
 import (
+       "context"
        "fmt"
+       "sync"
+       "sync/atomic"
        "time"
 
        cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
        cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
-       "knative.dev/pkg/kmeta"
-
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/client-go/tools/cache"
+       "knative.dev/eventing/pkg/apis/feature"
+       cmclient "knative.dev/eventing/pkg/client/certmanager/clientset/versioned"
+       cminformers "knative.dev/eventing/pkg/client/certmanager/informers/externalversions"
+       cmlistersv1 "knative.dev/eventing/pkg/client/certmanager/listers/certmanager/v1"
+       "knative.dev/pkg/controller"
+       "knative.dev/pkg/injection"
+       "knative.dev/pkg/kmeta"
+       "knative.dev/pkg/logging"
 )
 
+type DynamicCertificatesInformer struct {
+       cancel atomic.Pointer[context.CancelFunc]
+       lister atomic.Pointer[cmlistersv1.CertificateLister]
+       mu     sync.Mutex
+}
+
+func NewDynamicCertificatesInformer() *DynamicCertificatesInformer {
+       return &DynamicCertificatesInformer{
+               cancel: atomic.Pointer[context.CancelFunc]{},
+               lister: atomic.Pointer[cmlistersv1.CertificateLister]{},
+               mu:     sync.Mutex{},
+       }
+}
+
+func (df *DynamicCertificatesInformer) Reconcile(ctx context.Context, features feature.Flags, handler cache.ResourceEventHandler) error {
+       df.mu.Lock()
+       defer df.mu.Unlock()
+       if !features.IsPermissiveTransportEncryption() && !features.IsStrictTransportEncryption() {
+               return df.stop(ctx)
+       }
+       if df.cancel.Load() != nil {
+               return nil
+       }
+       ctx, cancel := context.WithCancel(ctx)
+
+       client := cmclient.NewForConfigOrDie(injection.GetConfig(ctx))
+
+       factory := cminformers.NewSharedInformerFactoryWithOptions(
+               client,
+               controller.DefaultResyncPeriod,
+               cminformers.WithTweakListOptions(func(options *metav1.ListOptions) {
+                       options.LabelSelector = "app.kubernetes.io/component=knative-eventing"
+               }),
+       )
+       informer := factory.Certmanager().V1().Certificates()
+       informer.Informer().AddEventHandler(handler)
+
+       factory.Start(ctx.Done())
+       if !cache.WaitForCacheSync(ctx.Done(), informer.Informer().HasSynced) {
+               defer cancel()
+               return fmt.Errorf("failed to sync cert-manager Certificate informer")
+       }
+
+       lister := informer.Lister()
+       df.lister.Store(&lister)
+       df.cancel.Store(&cancel) // Cancel is always set as last field since it's used as a "guard".
+
+       return nil
+}
+
+func (df *DynamicCertificatesInformer) stop(ctx context.Context) error {
+       cancel := df.cancel.Load()
+       if cancel == nil {
+               logging.FromContext(ctx).Debugw("Certificate informer has not been started, nothing to stop")
+               return nil
+       }
+
+       (*cancel)()
+       df.lister.Store(nil)
+       df.cancel.Store(nil) // Cancel is always set as last field since it's used as a "guard".
+       return nil
+}
+
+func (df *DynamicCertificatesInformer) Lister() *atomic.Pointer[cmlistersv1.CertificateLister] {
+       df.mu.Lock()
+       defer df.mu.Unlock()
+
+       return &df.lister
+}
+
 func CertificateName(objName string) string {
        return kmeta.ChildName(objName, "-server-tls")
 }
diff --git a/pkg/reconciler/integration/sink/controller.go b/pkg/reconciler/integration/sink/controller.go
index dcc181adc..3cdbab854 100644
--- a/pkg/reconciler/integration/sink/controller.go
+++ b/pkg/reconciler/integration/sink/controller.go
@@ -19,19 +19,18 @@ package sink
 import (
        "context"
 
-       v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "go.uber.org/zap"
        "k8s.io/client-go/tools/cache"
-       certmanagerclient "knative.dev/eventing/pkg/client/certmanager/clientset/versioned"
-       certmanagerinformers "knative.dev/eventing/pkg/client/certmanager/informers/externalversions"
-       "knative.dev/pkg/injection"
-
        "knative.dev/eventing/pkg/apis/feature"
-       v1alpha1 "knative.dev/eventing/pkg/apis/sinks/v1alpha1"
+       "knative.dev/eventing/pkg/apis/sinks/v1alpha1"
        "knative.dev/eventing/pkg/auth"
+       "knative.dev/eventing/pkg/certificates"
+       cmclient "knative.dev/eventing/pkg/client/certmanager/clientset/versioned"
        "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/eventpolicy"
        "knative.dev/eventing/pkg/client/injection/informers/sinks/v1alpha1/integrationsink"
        deploymentinformer "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment"
        "knative.dev/pkg/client/injection/kube/informers/core/v1/service"
+       "knative.dev/pkg/injection"
        pkgreconciler "knative.dev/pkg/reconciler"
 
        integrationsinkreconciler "knative.dev/eventing/pkg/client/injection/reconciler/sinks/v1alpha1/integrationsink"
@@ -52,12 +51,15 @@ func NewController(
        deploymentInformer := deploymentinformer.Get(ctx)
        serviceInformer := service.Get(ctx)
 
+       dynamicCertificateInformer := certificates.NewDynamicCertificatesInformer()
        r := &Reconciler{
-               kubeClientSet:     kubeclient.Get(ctx),
-               deploymentLister:  deploymentInformer.Lister(),
-               serviceLister:     serviceInformer.Lister(),
-               secretLister:      secretInformer.Lister(),
-               eventPolicyLister: eventPolicyInformer.Lister(),
+               secretLister:        secretInformer.Lister(),
+               eventPolicyLister:   eventPolicyInformer.Lister(),
+               kubeClientSet:       kubeclient.Get(ctx),
+               deploymentLister:    deploymentInformer.Lister(),
+               serviceLister:       serviceInformer.Lister(),
+               cmCertificateLister: *dynamicCertificateInformer.Lister(),
+               certManagerClient:   cmclient.NewForConfigOrDie(injection.GetConfig(ctx)),
        }
 
        logging.FromContext(ctx).Info("Creating IntegrationSink controller")
@@ -66,40 +68,15 @@ func NewController(
 
        featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"), func(name string, value interface{}) {
                if globalResync != nil {
-                       globalResync(nil)
-               }
 
-               if features, ok := value.(feature.Flags); ok {
-                       // we assume that Cert-Manager is installed in the cluster if the feature flag is enabled
-                       if features.IsPermissiveTransportEncryption() || features.IsStrictTransportEncryption() {
-
-                               go func() { // Start and register informer
-                                       certManagerClient := certmanagerclient.NewForConfigOrDie(injection.GetConfig(ctx))
-                                       factory := certmanagerinformers.NewSharedInformerFactoryWithOptions(
-                                               certManagerClient,
-                                               controller.DefaultResyncPeriod,
-                                               certmanagerinformers.WithTweakListOptions(func(options *v1.ListOptions) {
-                                                       options.LabelSelector = "app.kubernetes.io/component=knative-eventing"
-                                               }),
-                                       )
-                                       cmCertificateInformer := factory.Certmanager().V1().Certificates()
-                                       r.cmCertificateLister = cmCertificateInformer.Lister()
-                                       r.certManagerClient = certManagerClient
-
-                                       cmCertificateInformer.Informer().AddEventHandler(controller.HandleAll(globalResync))
-                                       factory.Start(ctx.Done())
-
-                                       if !cache.WaitForCacheSync(ctx.Done(), cmCertificateInformer.Informer().HasSynced) {
-                                               logging.FromContext(ctx).Error("Failed to sync Cert Manager Certificate informer")
-                                       }
-                               }()
-
-                       } else {
-                               cancelFunc, cancelExists := ctx.Value("cancelFunc").(context.CancelFunc)
-                               if cancelExists {
-                                       go cancelFunc()
+                       if features, ok := value.(feature.Flags); ok {
+                               // we assume that Cert-Manager is installed in the cluster if the feature flag is enabled
+                               if err := dynamicCertificateInformer.Reconcile(ctx, features, controller.HandleAll(globalResync)); err != nil {
+                                       logging.FromContext(ctx).Errorw("Failed to start certificates dynamic factory", zap.Error(err))
                                }
                        }
+
+                       globalResync(nil)
                }
        })
        featureStore.WatchConfigs(cmw)
diff --git a/pkg/reconciler/integration/sink/integrationsink.go b/pkg/reconciler/integration/sink/integrationsink.go
index 0f5a338bc..8e7f77b44 100644
--- a/pkg/reconciler/integration/sink/integrationsink.go
+++ b/pkg/reconciler/integration/sink/integrationsink.go
@@ -19,8 +19,10 @@ package sink
 import (
        "context"
        "fmt"
+       "sync/atomic"
 
        "knative.dev/eventing/pkg/certificates"
+       certmanagerlisters "knative.dev/eventing/pkg/client/certmanager/listers/certmanager/v1"
 
        cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
 
@@ -47,8 +49,6 @@ import (
 
        certmanagerclientset "knative.dev/eventing/pkg/client/certmanager/clientset/versioned"
 
-       certmanagerlisters "knative.dev/eventing/pkg/client/certmanager/listers/certmanager/v1"
-
        "knative.dev/eventing/pkg/eventingtls"
        duckv1 "knative.dev/pkg/apis/duck/v1"
        "knative.dev/pkg/controller"
@@ -74,7 +74,7 @@ type Reconciler struct {
 
        deploymentLister    appsv1listers.DeploymentLister
        serviceLister       corev1listers.ServiceLister
-       cmCertificateLister certmanagerlisters.CertificateLister
+       cmCertificateLister atomic.Pointer[certmanagerlisters.CertificateLister]
        certManagerClient   certmanagerclientset.Interface
 }
 
@@ -174,7 +174,12 @@ func (r *Reconciler) reconcileCMCertificate(ctx context.Context, sink *sinks.Int
 
        expected := certificates.MakeCertificate(sink, sink.Name)
 
-       cert, err := r.cmCertificateLister.Certificates(sink.Namespace).Get(expected.Name)
+       lister := r.cmCertificateLister.Load()
+       if lister == nil {
+               return nil, fmt.Errorf("no cer-manager certificate lister created yet, this should never happen")
+       }
+
+       cert, err := (*lister).Certificates(sink.Namespace).Get(expected.Name)
        if apierrors.IsNotFound(err) {
                cert, err := r.certManagerClient.CertmanagerV1().Certificates(sink.Namespace).Create(ctx, expected, metav1.CreateOptions{})
                if err != nil {

Something like this I guess

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hitting this:

               logging.FromContext(ctx).Debugw("Certificate informer has not been started, nothing to stop")

than later it is stuck here:

              return nil, fmt.Errorf("no cer-manager certificate lister created yet, this should never happen")

Copy link

codecov bot commented Mar 6, 2025

Codecov Report

Attention: Patch coverage is 51.28205% with 38 lines in your changes missing coverage. Please review.

Project coverage is 64.19%. Comparing base (615a071) to head (06bd3bb).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/reconciler/integration/sink/controller.go 0.00% 32 Missing ⚠️
pkg/reconciler/integration/sink/integrationsink.go 0.00% 5 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8509      +/-   ##
==========================================
- Coverage   64.26%   64.19%   -0.08%     
==========================================
  Files         397      397              
  Lines       24337    24354      +17     
==========================================
- Hits        15641    15634       -7     
- Misses       7858     7880      +22     
- Partials      838      840       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@matzew
Copy link
Member Author

matzew commented Mar 6, 2025

We could merge my current and work on proper fix in separate PR... as an option.

@pierDipi
Copy link
Member

pierDipi commented Mar 6, 2025

/lgtm

@knative-prow knative-prow bot added the lgtm Indicates that a PR is ready to be merged. label Mar 6, 2025
@knative-prow knative-prow bot merged commit eb3dd80 into knative:main Mar 6, 2025
34 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/test-and-release Test infrastructure, tests or release lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants