1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-04-16 09:16:24 +00:00

refactor: make cert manager a real controller (#4792)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

Co-authored-by: Prateek Pandey <prateek.pandey@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-10-07 16:21:37 +02:00 committed by GitHub
parent 7bfcf7d7e2
commit 83b7f919aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 55 deletions

View file

@ -639,11 +639,6 @@ func main() {
logger := logger.WithName("leader") logger := logger.WithName("leader")
// when losing the lead we just terminate the pod // when losing the lead we just terminate the pod
defer signalCancel() defer signalCancel()
// init tls secret
if err := certRenewer.InitTLSPemPair(); err != nil {
logger.Error(err, "tls initialization error")
os.Exit(1)
}
// validate config // validate config
if err := webhookCfg.ValidateWebhookConfigurations(config.KyvernoNamespace(), config.KyvernoConfigMapName()); err != nil { if err := webhookCfg.ValidateWebhookConfigurations(config.KyvernoNamespace(), config.KyvernoConfigMapName()); err != nil {
logger.Error(err, "invalid format of the Kyverno init ConfigMap, please correct the format of 'data.webhooks'") logger.Error(err, "invalid format of the Kyverno init ConfigMap, please correct the format of 'data.webhooks'")
@ -682,6 +677,10 @@ func main() {
// TODO: shall we just exit ? // TODO: shall we just exit ?
logger.Error(errors.New("failed to wait for cache sync"), "failed to wait for cache sync") logger.Error(errors.New("failed to wait for cache sync"), "failed to wait for cache sync")
} }
// start leader controllers
for _, controller := range leaderControllers {
go controller.run(signalCtx, logger.WithName("controllers"))
}
// bootstrap // bootstrap
if autoUpdateWebhooks { if autoUpdateWebhooks {
go webhookCfg.UpdateWebhookConfigurations(configuration) go webhookCfg.UpdateWebhookConfigurations(configuration)
@ -692,10 +691,6 @@ func main() {
os.Exit(1) os.Exit(1)
} }
webhookCfg.UpdateWebhookChan <- true webhookCfg.UpdateWebhookChan <- true
// start leader controllers
for _, controller := range leaderControllers {
go controller.run(signalCtx, logger.WithName("controllers"))
}
// wait until we loose the lead (or signal context is canceled) // wait until we loose the lead (or signal context is canceled)
<-ctx.Done() <-ctx.Done()
}, },

View file

@ -2,91 +2,111 @@ package certmanager
import ( import (
"context" "context"
"os"
"reflect"
"time" "time"
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/pkg/common" "github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/controllers" "github.com/kyverno/kyverno/pkg/controllers"
"github.com/kyverno/kyverno/pkg/tls" "github.com/kyverno/kyverno/pkg/tls"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
corev1informers "k8s.io/client-go/informers/core/v1" corev1informers "k8s.io/client-go/informers/core/v1"
corev1listers "k8s.io/client-go/listers/core/v1" corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue"
) )
const ( const (
// Workers is the number of workers for this controller // Workers is the number of workers for this controller
Workers = 1 Workers = 1
ControllerName = "certmanager-controller" ControllerName = "certmanager-controller"
maxRetries = 10
) )
type controller struct { type controller struct {
renewer *tls.CertRenewer renewer *tls.CertRenewer
// listers
secretLister corev1listers.SecretLister secretLister corev1listers.SecretLister
secretQueue chan bool
// queue
queue workqueue.RateLimitingInterface
secretEnqueue controllerutils.EnqueueFunc
} }
func NewController(secretInformer corev1informers.SecretInformer, certRenewer *tls.CertRenewer) controllers.Controller { func NewController(secretInformer corev1informers.SecretInformer, certRenewer *tls.CertRenewer) controllers.Controller {
manager := &controller{ queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), ControllerName)
renewer: certRenewer, c := controller{
secretLister: secretInformer.Lister(), renewer: certRenewer,
secretQueue: make(chan bool, 1), secretLister: secretInformer.Lister(),
queue: queue,
secretEnqueue: controllerutils.AddDefaultEventHandlers(logger.V(3), secretInformer.Informer(), queue),
} }
secretInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ return &c
AddFunc: manager.addSecretFunc,
UpdateFunc: manager.updateSecretFunc,
})
return manager
} }
func (m *controller) Run(ctx context.Context, workers int) { func (c *controller) Run(ctx context.Context, workers int) {
logger.Info("start managing certificate") go c.ticker(ctx)
// we need to enqueue our secrets in case they don't exist yet in the cluster
// this way we ensure the reconcile happens (hence renewal/creation)
if err := c.secretEnqueue(&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: config.KyvernoNamespace(),
Name: tls.GenerateTLSPairSecretName(),
},
}); err != nil {
logger.Error(err, "failed to enqueue secret", "name", tls.GenerateTLSPairSecretName())
}
if err := c.secretEnqueue(&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: config.KyvernoNamespace(),
Name: tls.GenerateRootCASecretName(),
},
}); err != nil {
logger.Error(err, "failed to enqueue CA secret", "name", tls.GenerateRootCASecretName())
}
controllerutils.Run(ctx, ControllerName, logger.V(3), c.queue, workers, maxRetries, c.reconcile)
}
func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, namespace, name string) error {
if namespace != config.KyvernoNamespace() {
return nil
}
if name != tls.GenerateTLSPairSecretName() && name != tls.GenerateRootCASecretName() {
return nil
}
return c.renewCertificates()
}
func (c *controller) ticker(ctx context.Context) {
certsRenewalTicker := time.NewTicker(tls.CertRenewalInterval) certsRenewalTicker := time.NewTicker(tls.CertRenewalInterval)
defer certsRenewalTicker.Stop() defer certsRenewalTicker.Stop()
for { for {
select { select {
case <-certsRenewalTicker.C: case <-certsRenewalTicker.C:
if err := m.renewCertificates(); err != nil { list, err := c.secretLister.List(labels.Everything())
logger.Error(err, "unable to renew certificates, force restarting") if err == nil {
os.Exit(1) for _, secret := range list {
} if err := c.secretEnqueue(secret); err != nil {
case <-m.secretQueue: logger.Error(err, "failed to enqueue secret", "name", secret.Name)
if err := m.renewCertificates(); err != nil { }
logger.Error(err, "unable to renew certificates, force restarting") }
os.Exit(1) } else {
logger.Error(err, "falied to list secrets")
} }
case <-ctx.Done(): case <-ctx.Done():
logger.V(2).Info("stopping cert renewer")
return return
} }
} }
} }
func (m *controller) addSecretFunc(obj interface{}) { func (c *controller) renewCertificates() error {
secret := obj.(*corev1.Secret) if err := common.RetryFunc(time.Second, 5*time.Second, c.renewer.RenewCA, "failed to renew CA", logger)(); err != nil {
if secret.GetNamespace() == config.KyvernoNamespace() && secret.GetName() == tls.GenerateTLSPairSecretName() {
m.secretQueue <- true
}
}
func (m *controller) updateSecretFunc(oldObj interface{}, newObj interface{}) {
old := oldObj.(*corev1.Secret)
new := newObj.(*corev1.Secret)
if new.GetNamespace() == config.KyvernoNamespace() && new.GetName() == tls.GenerateTLSPairSecretName() {
if !reflect.DeepEqual(old.DeepCopy().Data, new.DeepCopy().Data) {
m.secretQueue <- true
logger.V(4).Info("secret updated, reconciling webhook configurations")
}
}
}
func (m *controller) renewCertificates() error {
if err := common.RetryFunc(time.Second, 5*time.Second, m.renewer.RenewCA, "failed to renew CA", logger)(); err != nil {
return err return err
} }
if err := common.RetryFunc(time.Second, 5*time.Second, m.renewer.RenewTLS, "failed to renew TLS", logger)(); err != nil { if err := common.RetryFunc(time.Second, 5*time.Second, c.renewer.RenewTLS, "failed to renew TLS", logger)(); err != nil {
return err return err
} }
return nil return nil