diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index 958b2bb8bc..64d0c57eeb 100644 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -414,7 +414,7 @@ func createrLeaderControllers( configuration config.Configuration, metricsConfig *metrics.MetricsConfig, eventGenerator event.Interface, - certRenewer *tls.CertRenewer, + certRenewer tls.CertRenewer, runtime runtimeutils.Runtime, ) ([]controller, error) { policyCtrl, err := policy.NewPolicyController( @@ -564,7 +564,7 @@ func main() { logger.Error(err, "Failed to create openapi manager") os.Exit(1) } - certRenewer, err := tls.NewCertRenewer( + certRenewer := tls.NewCertRenewer( metrics.ObjectClient[*corev1.Secret]( metrics.NamespacedClientQueryRecorder(metricsConfig, config.KyvernoNamespace(), "Secret", metrics.KubeClient), kubeClient.CoreV1().Secrets(config.KyvernoNamespace()), @@ -574,10 +574,6 @@ func main() { tls.TLSValidityDuration, serverIP, ) - if err != nil { - logger.Error(err, "failed to initialize CertRenewer") - os.Exit(1) - } policyCache := policycache.NewCache() eventGenerator := event.NewEventGenerator( dynamicClient, diff --git a/pkg/controllers/certmanager/controller.go b/pkg/controllers/certmanager/controller.go index 351ca8fd33..8aa79b068c 100644 --- a/pkg/controllers/certmanager/controller.go +++ b/pkg/controllers/certmanager/controller.go @@ -26,7 +26,7 @@ const ( ) type controller struct { - renewer *tls.CertRenewer + renewer tls.CertRenewer // listers secretLister corev1listers.SecretLister @@ -36,7 +36,7 @@ type controller struct { secretEnqueue controllerutils.EnqueueFunc } -func NewController(secretInformer corev1informers.SecretInformer, certRenewer *tls.CertRenewer) controllers.Controller { +func NewController(secretInformer corev1informers.SecretInformer, certRenewer tls.CertRenewer) controllers.Controller { queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), ControllerName) c := controller{ renewer: certRenewer, diff --git a/pkg/tls/keypair.go b/pkg/tls/keypair.go index 86e7626e2a..ea1dff1cfa 100644 --- a/pkg/tls/keypair.go +++ b/pkg/tls/keypair.go @@ -50,7 +50,7 @@ func generateCA(key *rsa.PrivateKey, certValidityDuration time.Duration) (*rsa.P // generateTLS takes the results of GenerateCACert and uses it to create the // PEM-encoded public certificate and private key, respectively -func generateTLS(serverIP string, caCert *x509.Certificate, caKey *rsa.PrivateKey, certValidityDuration time.Duration) (*rsa.PrivateKey, *x509.Certificate, error) { +func generateTLS(server string, caCert *x509.Certificate, caKey *rsa.PrivateKey, certValidityDuration time.Duration) (*rsa.PrivateKey, *x509.Certificate, error) { now := time.Now() begin, end := now.Add(-1*time.Hour), now.Add(certValidityDuration) dnsNames := []string{ @@ -59,13 +59,23 @@ func generateTLS(serverIP string, caCert *x509.Certificate, caKey *rsa.PrivateKe InClusterServiceName(), } var ips []net.IP - if serverIP != "" { - if strings.Contains(serverIP, ":") { - host, _, _ := net.SplitHostPort(serverIP) - serverIP = host + if server != "" { + serverHost := "" + if strings.Contains(server, ":") { + host, _, err := net.SplitHostPort(server) + if err != nil { + logger.Error(err, "failed to split server host/port", "server", server) + } + serverHost = host + } + if serverHost != "" { + ip := net.ParseIP(serverHost) + if ip == nil || ip.IsUnspecified() { + dnsNames = append(dnsNames, serverHost) + } else { + ips = append(ips, ip) + } } - ip := net.ParseIP(serverIP) - ips = append(ips, ip) } templ := &x509.Certificate{ SerialNumber: big.NewInt(1), diff --git a/pkg/tls/reader.go b/pkg/tls/reader.go index 1323f70549..98f886127a 100644 --- a/pkg/tls/reader.go +++ b/pkg/tls/reader.go @@ -23,7 +23,7 @@ func ReadRootCASecret(client controllerutils.GetClient[*corev1.Secret]) ([]byte, result := stlsca.Data[corev1.TLSCertKey] // if not there, try old "rootCA.crt" if len(result) == 0 { - result = stlsca.Data[RootCAKey] + result = stlsca.Data[rootCAKey] } if len(result) == 0 { return nil, errors.Errorf("%s in secret %s/%s", ErrorsNotFound, config.KyvernoNamespace(), stlsca.Name) diff --git a/pkg/tls/renewer.go b/pkg/tls/renewer.go index bf8b146025..20339d1e8c 100644 --- a/pkg/tls/renewer.go +++ b/pkg/tls/renewer.go @@ -17,54 +17,49 @@ import ( const ( // CertRenewalInterval is the renewal interval for rootCA - CertRenewalInterval time.Duration = 12 * time.Hour + CertRenewalInterval = 12 * time.Hour // CAValidityDuration is the valid duration for CA certificates - CAValidityDuration time.Duration = 365 * 24 * time.Hour + CAValidityDuration = 365 * 24 * time.Hour // TLSValidityDuration is the valid duration for TLS certificates - TLSValidityDuration time.Duration = 150 * 24 * time.Hour - // ManagedByLabel is added to Kyverno managed secrets - ManagedByLabel string = "cert.kyverno.io/managed-by" - RootCAKey string = "rootCA.crt" + TLSValidityDuration = 150 * 24 * time.Hour + // managedByLabel is added to Kyverno managed secrets + managedByLabel = "cert.kyverno.io/managed-by" + rootCAKey = "rootCA.crt" ) -// CertRenewer creates rootCA and pem pair to register +type CertRenewer interface { + // RenewCA renews the CA certificate if needed + RenewCA() error + // RenewTLS renews the TLS certificate if needed + RenewTLS() error +} + +// certRenewer creates rootCA and pem pair to register // webhook configurations and webhook server // renews RootCA at the given interval -type CertRenewer struct { +type certRenewer struct { client controllerutils.ObjectClient[*corev1.Secret] certRenewalInterval time.Duration caValidityDuration time.Duration tlsValidityDuration time.Duration - // IP address where Kyverno controller runs. Only required if out-of-cluster. - serverIP string + // server is an IP address or domain name where Kyverno controller runs. Only required if out-of-cluster. + server string } // NewCertRenewer returns an instance of CertRenewer -func NewCertRenewer(client controllerutils.ObjectClient[*corev1.Secret], certRenewalInterval, caValidityDuration, tlsValidityDuration time.Duration, serverIP string) (*CertRenewer, error) { - return &CertRenewer{ +func NewCertRenewer(client controllerutils.ObjectClient[*corev1.Secret], certRenewalInterval, caValidityDuration, tlsValidityDuration time.Duration, server string) CertRenewer { + return &certRenewer{ client: client, certRenewalInterval: certRenewalInterval, caValidityDuration: caValidityDuration, tlsValidityDuration: tlsValidityDuration, - serverIP: serverIP, - }, nil + server: server, + } } -// InitTLSPemPair Loads or creates PEM private key and TLS certificate for webhook server. -// Created pair is stored in cluster's secret. -func (c *CertRenewer) InitTLSPemPair() error { - if err := c.RenewCA(); err != nil { - return err - } - if err := c.RenewTLS(); err != nil { - return err - } - return nil -} - -// RenewTLS renews the CA certificate if needed -func (c *CertRenewer) RenewCA() error { +// RenewCA renews the CA certificate if needed +func (c *certRenewer) RenewCA() error { secret, key, certs, err := c.decodeCASecret() if err != nil && !apierrors.IsNotFound(err) { logger.Error(err, "failed to read CA") @@ -96,7 +91,7 @@ func (c *CertRenewer) RenewCA() error { } // RenewTLS renews the TLS certificate if needed -func (c *CertRenewer) RenewTLS() error { +func (c *certRenewer) RenewTLS() error { _, caKey, caCerts, err := c.decodeCASecret() if err != nil { logger.Error(err, "failed to read CA") @@ -117,7 +112,7 @@ func (c *CertRenewer) RenewTLS() error { logger.Error(err, "tls is not valid but certificates are not managed by kyverno, we can't renew them") return err } - tlsKey, tlsCert, err := generateTLS(c.serverIP, caCerts[len(caCerts)-1], caKey, c.tlsValidityDuration) + tlsKey, tlsCert, err := generateTLS(c.server, caCerts[len(caCerts)-1], caKey, c.tlsValidityDuration) if err != nil { logger.Error(err, "failed to generate TLS") return err @@ -131,7 +126,7 @@ func (c *CertRenewer) RenewTLS() error { } // ValidateCert validates the CA Cert -func (c *CertRenewer) ValidateCert() (bool, error) { +func (c *certRenewer) ValidateCert() (bool, error) { _, _, caCerts, err := c.decodeCASecret() if err != nil { return false, err @@ -143,7 +138,7 @@ func (c *CertRenewer) ValidateCert() (bool, error) { return validateCert(time.Now(), cert, caCerts...), nil } -func (c *CertRenewer) getSecret(name string) (*corev1.Secret, error) { +func (c *certRenewer) getSecret(name string) (*corev1.Secret, error) { if s, err := c.client.Get(context.TODO(), name, metav1.GetOptions{}); err != nil { return nil, err } else { @@ -151,7 +146,7 @@ func (c *CertRenewer) getSecret(name string) (*corev1.Secret, error) { } } -func (c *CertRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) { +func (c *certRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) { secret, err := c.getSecret(name) if err != nil { return nil, nil, nil, err @@ -161,7 +156,7 @@ func (c *CertRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey keyBytes = secret.Data[corev1.TLSPrivateKeyKey] certBytes = secret.Data[corev1.TLSCertKey] if len(certBytes) == 0 { - certBytes = secret.Data[RootCAKey] + certBytes = secret.Data[rootCAKey] } } var key *rsa.PrivateKey @@ -175,11 +170,11 @@ func (c *CertRenewer) decodeSecret(name string) (*corev1.Secret, *rsa.PrivateKey return secret, key, pemToCertificates(certBytes), nil } -func (c *CertRenewer) decodeCASecret() (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) { +func (c *certRenewer) decodeCASecret() (*corev1.Secret, *rsa.PrivateKey, []*x509.Certificate, error) { return c.decodeSecret(GenerateRootCASecretName()) } -func (c *CertRenewer) decodeTLSSecret() (*corev1.Secret, *rsa.PrivateKey, *x509.Certificate, error) { +func (c *certRenewer) decodeTLSSecret() (*corev1.Secret, *rsa.PrivateKey, *x509.Certificate, error) { secret, key, certs, err := c.decodeSecret(GenerateTLSPairSecretName()) if err != nil { return nil, nil, nil, err @@ -193,7 +188,7 @@ func (c *CertRenewer) decodeTLSSecret() (*corev1.Secret, *rsa.PrivateKey, *x509. } } -func (c *CertRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x509.Certificate) error { +func (c *certRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x509.Certificate) error { logger := logger.WithValues("name", name, "namespace", config.KyvernoNamespace()) secret, err := c.getSecret(name) if err != nil && !apierrors.IsNotFound(err) { @@ -206,7 +201,7 @@ func (c *CertRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x5 Name: name, Namespace: config.KyvernoNamespace(), Labels: map[string]string{ - ManagedByLabel: kyvernov1.ValueKyvernoApp, + managedByLabel: kyvernov1.ValueKyvernoApp, }, }, Type: corev1.SecretTypeTLS, @@ -236,11 +231,11 @@ func (c *CertRenewer) writeSecret(name string, key *rsa.PrivateKey, certs ...*x5 } // writeCASecret stores the CA cert in secret -func (c *CertRenewer) writeCASecret(key *rsa.PrivateKey, certs ...*x509.Certificate) error { +func (c *certRenewer) writeCASecret(key *rsa.PrivateKey, certs ...*x509.Certificate) error { return c.writeSecret(GenerateRootCASecretName(), key, certs...) } // writeTLSSecret Writes the pair of TLS certificate and key to the specified secret. -func (c *CertRenewer) writeTLSSecret(key *rsa.PrivateKey, cert *x509.Certificate) error { +func (c *certRenewer) writeTLSSecret(key *rsa.PrivateKey, cert *x509.Certificate) error { return c.writeSecret(GenerateTLSPairSecretName(), key, cert) } diff --git a/pkg/tls/utils.go b/pkg/tls/utils.go index cb12735f4e..797f1edab5 100644 --- a/pkg/tls/utils.go +++ b/pkg/tls/utils.go @@ -104,7 +104,7 @@ func IsSecretManagedByKyverno(secret *corev1.Secret) bool { if labels == nil { return false } - if labels[ManagedByLabel] != kyvernov1.ValueKyvernoApp { + if labels[managedByLabel] != kyvernov1.ValueKyvernoApp { return false } }