From a981957a9d9b9bd8e616bd963da57bbf96f2d8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Edouard=20Br=C3=A9t=C3=A9ch=C3=A9?= Date: Tue, 10 May 2022 11:55:39 +0200 Subject: [PATCH] feat: fetch tls certificate dynamically (#3851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Charles-Edouard Brétéché --- cmd/kyverno/main.go | 11 ++----- pkg/controllers/certmanager/controller.go | 36 ++++++++++------------- pkg/webhooks/server.go | 23 ++++++++++----- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index db730ac0c5..f9a42fa541 100755 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -335,7 +335,7 @@ func main() { setupLog.Error(err, "failed to initialize CertRenewer") os.Exit(1) } - certManager, err := certmanager.NewController(kubeKyvernoInformer.Core().V1().Secrets(), kubeClient, certRenewer) + certManager, err := certmanager.NewController(kubeKyvernoInformer.Core().V1().Secrets(), certRenewer) if err != nil { setupLog.Error(err, "failed to initialize CertManager") os.Exit(1) @@ -383,13 +383,6 @@ func main() { // the webhook server runs across all instances openAPIController := startOpenAPIController(dynamicClient, stopCh) - var tlsPair *tls.PemPair - tlsPair, err = certManager.GetTLSPemPair() - if err != nil { - setupLog.Error(err, "Failed to get TLS key/certificate pair") - os.Exit(1) - } - // WEBHOOK // - https server to provide endpoints called based on rules defined in Mutating & Validation webhook configuration // - reports the results based on the response from the policy engine: @@ -399,7 +392,7 @@ func main() { server, err := webhooks.NewWebhookServer( kyvernoClient, dynamicClient, - tlsPair, + certManager.GetTLSPemPair, kyvernoInformer.Kyverno().V1beta1().UpdateRequests(), kyvernoV1.ClusterPolicies(), kubeInformer.Rbac().V1().RoleBindings(), diff --git a/pkg/controllers/certmanager/controller.go b/pkg/controllers/certmanager/controller.go index 20342cfd6f..9a4444cb16 100644 --- a/pkg/controllers/certmanager/controller.go +++ b/pkg/controllers/certmanager/controller.go @@ -6,12 +6,11 @@ import ( "strings" "time" - "github.com/kyverno/kyverno/pkg/common" "github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/tls" v1 "k8s.io/api/core/v1" informerv1 "k8s.io/client-go/informers/core/v1" - "k8s.io/client-go/kubernetes" + listersv1 "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" ) @@ -28,16 +27,16 @@ type Controller interface { } type controller struct { - renewer *tls.CertRenewer - secretInformer informerv1.SecretInformer - secretQueue chan bool + renewer *tls.CertRenewer + secretLister listersv1.SecretLister + secretQueue chan bool } -func NewController(secretInformer informerv1.SecretInformer, kubeClient kubernetes.Interface, certRenewer *tls.CertRenewer) (Controller, error) { +func NewController(secretInformer informerv1.SecretInformer, certRenewer *tls.CertRenewer) (Controller, error) { manager := &controller{ - renewer: certRenewer, - secretInformer: secretInformer, - secretQueue: make(chan bool, 1), + renewer: certRenewer, + secretLister: secretInformer.Lister(), + secretQueue: make(chan bool, 1), } secretInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: manager.addSecretFunc, @@ -73,19 +72,14 @@ func (m *controller) InitTLSPemPair() { } func (m *controller) GetTLSPemPair() (*tls.PemPair, error) { - var keyPair *tls.PemPair - var err error - retryReadTLS := func() error { - keyPair, err = tls.ReadTLSPair(m.renewer.ClientConfig(), m.renewer.Client()) - if err != nil { - return err - } - logger.Info("read TLS pem pair from the secret") - return nil + secret, err := m.secretLister.Secrets(config.KyvernoNamespace).Get(m.renewer.GenerateTLSPairSecretName()) + if err != nil { + return nil, err } - msg := "failed to read TLS pair" - f := common.RetryFunc(time.Second, time.Minute, retryReadTLS, msg, logger.WithName("GetTLSPemPair/Retry")) - return keyPair, f() + return &tls.PemPair{ + Certificate: secret.Data[v1.TLSCertKey], + PrivateKey: secret.Data[v1.TLSPrivateKeyKey], + }, nil } func (m *controller) Run(stopCh <-chan struct{}) { diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index e57af9c2ed..848f5810f7 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -97,7 +97,7 @@ type WebhookServer struct { func NewWebhookServer( kyvernoClient kyvernoclient.Interface, client client.Interface, - tlsPair *tlsutils.PemPair, + tlsPair func() (*tlsutils.PemPair, error), urInformer urinformer.UpdateRequestInformer, pInformer kyvernoinformer.ClusterPolicyInformer, rbInformer rbacinformer.RoleBindingInformer, @@ -122,10 +122,6 @@ func NewWebhookServer( if tlsPair == nil { return nil, errors.New("NewWebhookServer is not initialized properly") } - pair, err := tls.X509KeyPair(tlsPair.Certificate, tlsPair.PrivateKey) - if err != nil { - return nil, err - } ws := &WebhookServer{ client: client, kyvernoClient: kyvernoClient, @@ -158,8 +154,21 @@ func NewWebhookServer( mux.HandlerFunc("GET", config.LivenessServicePath, handlers.Probe(ws.webhookRegister.Check)) mux.HandlerFunc("GET", config.ReadinessServicePath, handlers.Probe(nil)) ws.server = &http.Server{ - Addr: ":9443", // Listen on port for HTTPS requests - TLSConfig: &tls.Config{Certificates: []tls.Certificate{pair}, MinVersion: tls.VersionTLS12}, + Addr: ":9443", // Listen on port for HTTPS requests + TLSConfig: &tls.Config{ + GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + tlsPair, err := tlsPair() + if err != nil { + return nil, err + } + pair, err := tls.X509KeyPair(tlsPair.Certificate, tlsPair.PrivateKey) + if err != nil { + return nil, err + } + return &pair, nil + }, + MinVersion: tls.VersionTLS12, + }, Handler: mux, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second,