From 5e68fd8fe0f40f3d2bb02c0b52d05bd907b05763 Mon Sep 17 00:00:00 2001 From: Dario Tranchitella Date: Mon, 28 Jul 2025 09:40:16 +0200 Subject: [PATCH] fix: honouring certificate expiratin threshold (#886) Signed-off-by: Dario Tranchitella --- cmd/manager/cmd.go | 9 ++- controllers/resources.go | 78 +++++++++++-------- controllers/tenantcontrolplane_controller.go | 11 +-- internal/crypto/crypto.go | 14 ++-- internal/kubeadm/kubeconfig.go | 5 +- internal/resources/api_server_certificate.go | 9 ++- .../api_server_kubelet_client_certificate.go | 9 ++- internal/resources/ca_certificate.go | 7 +- .../datastore/datastore_certificate.go | 12 +-- .../front-proxy-client-certificate.go | 9 ++- .../resources/front_proxy_ca_certificate.go | 9 ++- .../konnectivity/certificate_resource.go | 8 +- internal/resources/kubeconfig.go | 16 ++-- 13 files changed, 116 insertions(+), 80 deletions(-) diff --git a/cmd/manager/cmd.go b/cmd/manager/cmd.go index efb6d44..f2af7d8 100644 --- a/cmd/manager/cmd.go +++ b/cmd/manager/cmd.go @@ -149,11 +149,12 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command { Client: mgr.GetClient(), APIReader: mgr.GetAPIReader(), Config: controllers.TenantControlPlaneReconcilerConfig{ - ReconcileTimeout: controllerReconcileTimeout, - DefaultDataStoreName: datastore, - KineContainerImage: kineImage, - TmpBaseDirectory: tmpDirectory, + DefaultDataStoreName: datastore, + KineContainerImage: kineImage, + TmpBaseDirectory: tmpDirectory, + CertExpirationThreshold: certificateExpirationDeadline, }, + ReconcileTimeout: controllerReconcileTimeout, CertificateChan: certChannel, TriggerChan: tcpChannel, KamajiNamespace: managerNamespace, diff --git a/controllers/resources.go b/controllers/resources.go index b0dca3b..f2f1346 100644 --- a/controllers/resources.go +++ b/controllers/resources.go @@ -5,6 +5,7 @@ package controllers import ( "fmt" + "time" "github.com/go-logr/logr" "github.com/google/uuid" @@ -26,6 +27,7 @@ type GroupResourceBuilderConfiguration struct { log logr.Logger tcpReconcilerConfig TenantControlPlaneReconcilerConfig tenantControlPlane kamajiv1alpha1.TenantControlPlane + ExpirationThreshold time.Duration Connection datastore.Connection DataStore kamajiv1alpha1.DataStore KamajiNamespace string @@ -78,8 +80,8 @@ func getDefaultResources(config GroupResourceBuilderConfiguration) []resources.R resources = append(resources, getKubeadmConfigResources(config.client, getTmpDirectory(config.tcpReconcilerConfig.TmpBaseDirectory, config.tenantControlPlane), config.DataStore)...) resources = append(resources, getKubernetesCertificatesResources(config.client, config.tcpReconcilerConfig, config.tenantControlPlane)...) resources = append(resources, getKubeconfigResources(config.client, config.tcpReconcilerConfig, config.tenantControlPlane)...) - resources = append(resources, getKubernetesStorageResources(config.client, config.Connection, config.DataStore)...) - resources = append(resources, getKonnectivityServerRequirementsResources(config.client)...) + resources = append(resources, getKubernetesStorageResources(config.client, config.Connection, config.DataStore, config.ExpirationThreshold)...) + resources = append(resources, getKonnectivityServerRequirementsResources(config.client, config.ExpirationThreshold)...) resources = append(resources, getKubernetesDeploymentResources(config.client, config.tcpReconcilerConfig, config.DataStore)...) resources = append(resources, getKonnectivityServerPatchResources(config.client)...) resources = append(resources, getDataStoreMigratingCleanup(config.client, config.KamajiNamespace)...) @@ -148,28 +150,33 @@ func getKubeadmConfigResources(c client.Client, tmpDirectory string, dataStore k func getKubernetesCertificatesResources(c client.Client, tcpReconcilerConfig TenantControlPlaneReconcilerConfig, tenantControlPlane kamajiv1alpha1.TenantControlPlane) []resources.Resource { return []resources.Resource{ &resources.CACertificate{ - Client: c, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, &resources.FrontProxyCACertificate{ - Client: c, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, &resources.SACertificate{ Client: c, TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), }, &resources.APIServerCertificate{ - Client: c, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, &resources.APIServerKubeletClientCertificate{ - Client: c, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, &resources.FrontProxyClientCertificate{ - Client: c, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, } } @@ -177,33 +184,37 @@ func getKubernetesCertificatesResources(c client.Client, tcpReconcilerConfig Ten func getKubeconfigResources(c client.Client, tcpReconcilerConfig TenantControlPlaneReconcilerConfig, tenantControlPlane kamajiv1alpha1.TenantControlPlane) []resources.Resource { return []resources.Resource{ &resources.KubeconfigResource{ - Name: "admin-kubeconfig", - Client: c, - KubeConfigFileName: resources.AdminKubeConfigFileName, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + Name: "admin-kubeconfig", + KubeConfigFileName: resources.AdminKubeConfigFileName, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, &resources.KubeconfigResource{ - Name: "admin-kubeconfig", - Client: c, - KubeConfigFileName: resources.SuperAdminKubeConfigFileName, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + Name: "admin-kubeconfig", + KubeConfigFileName: resources.SuperAdminKubeConfigFileName, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, &resources.KubeconfigResource{ - Name: "controller-manager-kubeconfig", - Client: c, - KubeConfigFileName: resources.ControllerManagerKubeConfigFileName, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + Name: "controller-manager-kubeconfig", + KubeConfigFileName: resources.ControllerManagerKubeConfigFileName, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, &resources.KubeconfigResource{ - Name: "scheduler-kubeconfig", - Client: c, - KubeConfigFileName: resources.SchedulerKubeConfigFileName, - TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + Client: c, + Name: "scheduler-kubeconfig", + KubeConfigFileName: resources.SchedulerKubeConfigFileName, + TmpDirectory: getTmpDirectory(tcpReconcilerConfig.TmpBaseDirectory, tenantControlPlane), + CertExpirationThreshold: tcpReconcilerConfig.CertExpirationThreshold, }, } } -func getKubernetesStorageResources(c client.Client, dbConnection datastore.Connection, datastore kamajiv1alpha1.DataStore) []resources.Resource { +func getKubernetesStorageResources(c client.Client, dbConnection datastore.Connection, datastore kamajiv1alpha1.DataStore, threshold time.Duration) []resources.Resource { return []resources.Resource{ &ds.MultiTenancy{ DataStore: datastore, @@ -219,8 +230,9 @@ func getKubernetesStorageResources(c client.Client, dbConnection datastore.Conne DataStore: datastore, }, &ds.Certificate{ - Client: c, - DataStore: datastore, + Client: c, + DataStore: datastore, + CertExpirationThreshold: threshold, }, } } @@ -251,10 +263,10 @@ func GetExternalKonnectivityResources(c client.Client) []resources.Resource { } } -func getKonnectivityServerRequirementsResources(c client.Client) []resources.Resource { +func getKonnectivityServerRequirementsResources(c client.Client, threshold time.Duration) []resources.Resource { return []resources.Resource{ &konnectivity.EgressSelectorConfigurationResource{Client: c}, - &konnectivity.CertificateResource{Client: c}, + &konnectivity.CertificateResource{Client: c, CertExpirationThreshold: threshold}, &konnectivity.KubeconfigResource{Client: c}, } } diff --git a/controllers/tenantcontrolplane_controller.go b/controllers/tenantcontrolplane_controller.go index 6441c48..6baca1d 100644 --- a/controllers/tenantcontrolplane_controller.go +++ b/controllers/tenantcontrolplane_controller.go @@ -50,6 +50,7 @@ type TenantControlPlaneReconciler struct { KamajiService string KamajiMigrateImage string MaxConcurrentReconciles int + ReconcileTimeout time.Duration // CertificateChan is the channel used by the CertificateLifecycleController that is checking for // certificates and kubeconfig user certs validity: a generic event for the given TCP will be triggered // once the validity threshold for the given certificate is reached. @@ -60,10 +61,10 @@ type TenantControlPlaneReconciler struct { // TenantControlPlaneReconcilerConfig gives the necessary configuration for TenantControlPlaneReconciler. type TenantControlPlaneReconcilerConfig struct { - ReconcileTimeout time.Duration - DefaultDataStoreName string - KineContainerImage string - TmpBaseDirectory string + DefaultDataStoreName string + KineContainerImage string + TmpBaseDirectory string + CertExpirationThreshold time.Duration } //+kubebuilder:rbac:groups=kamaji.clastix.io,resources=tenantcontrolplanes,verbs=get;list;watch;create;update;patch;delete @@ -80,7 +81,7 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R log := log.FromContext(ctx) var cancelFn context.CancelFunc - ctx, cancelFn = context.WithTimeout(ctx, r.Config.ReconcileTimeout) + ctx, cancelFn = context.WithTimeout(ctx, r.ReconcileTimeout) defer cancelFn() tenantControlPlane, err := r.getTenantControlPlane(ctx, req.NamespacedName)() diff --git a/internal/crypto/crypto.go b/internal/crypto/crypto.go index 83ad256..ab8e318 100644 --- a/internal/crypto/crypto.go +++ b/internal/crypto/crypto.go @@ -22,7 +22,7 @@ import ( ) // CheckPublicAndPrivateKeyValidity checks if the given bytes for the private and public keys are valid. -func CheckPublicAndPrivateKeyValidity(publicKey []byte, privateKey []byte) (bool, error) { +func CheckPublicAndPrivateKeyValidity(publicKey, privateKey []byte) (bool, error) { if len(publicKey) == 0 || len(privateKey) == 0 { return false, nil } @@ -74,12 +74,12 @@ func CheckCertificateNamesAndIPs(certificateBytes []byte, entries []string) (boo } // CheckCertificateAndPrivateKeyPairValidity checks if the certificate and private key pair are valid. -func CheckCertificateAndPrivateKeyPairValidity(certificate []byte, privateKey []byte) (bool, error) { +func CheckCertificateAndPrivateKeyPairValidity(certificate, privateKey []byte, threshold time.Duration) (bool, error) { switch { case len(certificate) == 0, len(privateKey) == 0: return false, nil default: - return IsValidCertificateKeyPairBytes(certificate, privateKey) + return IsValidCertificateKeyPairBytes(certificate, privateKey, threshold) } } @@ -159,7 +159,7 @@ func ParsePublicKeyBytes(content []byte) (*rsa.PublicKey, error) { } // IsValidCertificateKeyPairBytes checks if the certificate matches the private key bounded to it. -func IsValidCertificateKeyPairBytes(certificateBytes []byte, privateKeyBytes []byte) (bool, error) { +func IsValidCertificateKeyPairBytes(certificateBytes, privateKeyBytes []byte, expirationThreshold time.Duration) (bool, error) { crt, err := ParseCertificateBytes(certificateBytes) if err != nil { return false, err @@ -171,7 +171,7 @@ func IsValidCertificateKeyPairBytes(certificateBytes []byte, privateKeyBytes []b } switch { - case !checkCertificateValidity(*crt): + case !checkCertificateValidity(*crt, expirationThreshold): return false, nil case !checkPublicKeys(crt.PublicKey, key): return false, nil @@ -238,9 +238,9 @@ func generateCertificateKeyPairBytes(template *x509.Certificate, caCert *x509.Ce return certPEM, certPrivKeyPEM, nil } -func checkCertificateValidity(cert x509.Certificate) bool { +func checkCertificateValidity(cert x509.Certificate, threshold time.Duration) bool { // Avoiding waiting for the exact expiration date by creating a one-day gap - notAfter := cert.NotAfter.After(time.Now().AddDate(0, 0, 1)) + notAfter := cert.NotAfter.After(time.Now().Add(threshold)) notBefore := cert.NotBefore.Before(time.Now()) return notAfter && notBefore diff --git a/internal/kubeadm/kubeconfig.go b/internal/kubeadm/kubeconfig.go index 46ec7aa..aa144e2 100644 --- a/internal/kubeadm/kubeconfig.go +++ b/internal/kubeadm/kubeconfig.go @@ -8,6 +8,7 @@ import ( "os" "path" "path/filepath" + "time" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig" @@ -62,13 +63,13 @@ func IsKubeconfigCAValid(in, caCrt []byte) bool { return true } -func IsKubeconfigValid(bytes []byte) bool { +func IsKubeconfigValid(bytes []byte, expirationThreshold time.Duration) bool { kc, err := utilities.DecodeKubeconfigYAML(bytes) if err != nil { return false } - ok, _ := crypto.IsValidCertificateKeyPairBytes(kc.AuthInfos[0].AuthInfo.ClientCertificateData, kc.AuthInfos[0].AuthInfo.ClientKeyData) + ok, _ := crypto.IsValidCertificateKeyPairBytes(kc.AuthInfos[0].AuthInfo.ClientCertificateData, kc.AuthInfos[0].AuthInfo.ClientKeyData, expirationThreshold) return ok } diff --git a/internal/resources/api_server_certificate.go b/internal/resources/api_server_certificate.go index 9717797..37a7737 100644 --- a/internal/resources/api_server_certificate.go +++ b/internal/resources/api_server_certificate.go @@ -7,6 +7,7 @@ import ( "context" "crypto/x509" "fmt" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -27,9 +28,10 @@ import ( ) type APIServerCertificate struct { - resource *corev1.Secret - Client client.Client - TmpDirectory string + resource *corev1.Secret + Client client.Client + TmpDirectory string + CertExpirationThreshold time.Duration } func (r *APIServerCertificate) GetHistogram() prometheus.Histogram { @@ -138,6 +140,7 @@ func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *k isCertValid, err := crypto.CheckCertificateAndPrivateKeyPairValidity( r.resource.Data[kubeadmconstants.APIServerCertName], r.resource.Data[kubeadmconstants.APIServerKeyName], + r.CertExpirationThreshold, ) if err != nil { logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", kubeadmconstants.APIServerCertAndKeyBaseName, err.Error())) diff --git a/internal/resources/api_server_kubelet_client_certificate.go b/internal/resources/api_server_kubelet_client_certificate.go index c334262..12d64a5 100644 --- a/internal/resources/api_server_kubelet_client_certificate.go +++ b/internal/resources/api_server_kubelet_client_certificate.go @@ -7,6 +7,7 @@ import ( "context" "crypto/x509" "fmt" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -26,9 +27,10 @@ import ( ) type APIServerKubeletClientCertificate struct { - resource *corev1.Secret - Client client.Client - TmpDirectory string + resource *corev1.Secret + Client client.Client + TmpDirectory string + CertExpirationThreshold time.Duration } func (r *APIServerKubeletClientCertificate) GetHistogram() prometheus.Histogram { @@ -125,6 +127,7 @@ func (r *APIServerKubeletClientCertificate) mutate(ctx context.Context, tenantCo isValid, err := crypto.CheckCertificateAndPrivateKeyPairValidity( r.resource.Data[kubeadmconstants.APIServerKubeletClientCertName], r.resource.Data[kubeadmconstants.APIServerKubeletClientKeyName], + r.CertExpirationThreshold, ) if err != nil { logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName, err.Error())) diff --git a/internal/resources/ca_certificate.go b/internal/resources/ca_certificate.go index f30e6e2..7d79e5a 100644 --- a/internal/resources/ca_certificate.go +++ b/internal/resources/ca_certificate.go @@ -7,6 +7,7 @@ import ( "bytes" "context" "fmt" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -27,8 +28,9 @@ type CACertificate struct { resource *corev1.Secret isRotatingCA bool - Client client.Client - TmpDirectory string + Client client.Client + TmpDirectory string + CertExpirationThreshold time.Duration } func (r *CACertificate) GetHistogram() prometheus.Histogram { @@ -102,6 +104,7 @@ func (r *CACertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1 isValid, err := crypto.CheckCertificateAndPrivateKeyPairValidity( r.resource.Data[kubeadmconstants.CACertName], r.resource.Data[kubeadmconstants.CAKeyName], + r.CertExpirationThreshold, ) if err != nil { logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", kubeadmconstants.CACertAndKeyBaseName, err.Error())) diff --git a/internal/resources/datastore/datastore_certificate.go b/internal/resources/datastore/datastore_certificate.go index 077bc60..ffae2ee 100644 --- a/internal/resources/datastore/datastore_certificate.go +++ b/internal/resources/datastore/datastore_certificate.go @@ -7,6 +7,7 @@ import ( "bytes" "context" "fmt" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -24,10 +25,11 @@ import ( ) type Certificate struct { - resource *corev1.Secret - Client client.Client - Name string - DataStore kamajiv1alpha1.DataStore + resource *corev1.Secret + Client client.Client + Name string + DataStore kamajiv1alpha1.DataStore + CertExpirationThreshold time.Duration } func (r *Certificate) GetHistogram() prometheus.Histogram { @@ -118,7 +120,7 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al if utilities.GetObjectChecksum(r.resource) == utilities.CalculateMapChecksum(r.resource.Data) { if r.DataStore.Spec.Driver == kamajiv1alpha1.EtcdDriver { - if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"]); isValid && !isRotationRequested { + if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"], r.CertExpirationThreshold); isValid && !isRotationRequested { return nil } } diff --git a/internal/resources/front-proxy-client-certificate.go b/internal/resources/front-proxy-client-certificate.go index 6b85f80..95e7826 100644 --- a/internal/resources/front-proxy-client-certificate.go +++ b/internal/resources/front-proxy-client-certificate.go @@ -7,6 +7,7 @@ import ( "context" "crypto/x509" "fmt" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -26,9 +27,10 @@ import ( ) type FrontProxyClientCertificate struct { - resource *corev1.Secret - Client client.Client - TmpDirectory string + resource *corev1.Secret + Client client.Client + TmpDirectory string + CertExpirationThreshold time.Duration } func (r *FrontProxyClientCertificate) GetHistogram() prometheus.Histogram { @@ -125,6 +127,7 @@ func (r *FrontProxyClientCertificate) mutate(ctx context.Context, tenantControlP isValid, err := crypto.CheckCertificateAndPrivateKeyPairValidity( r.resource.Data[kubeadmconstants.FrontProxyClientCertName], r.resource.Data[kubeadmconstants.FrontProxyClientKeyName], + r.CertExpirationThreshold, ) if err != nil { logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", kubeadmconstants.FrontProxyClientCertAndKeyBaseName, err.Error())) diff --git a/internal/resources/front_proxy_ca_certificate.go b/internal/resources/front_proxy_ca_certificate.go index 7f5c13c..d01d975 100644 --- a/internal/resources/front_proxy_ca_certificate.go +++ b/internal/resources/front_proxy_ca_certificate.go @@ -6,6 +6,7 @@ package resources import ( "context" "fmt" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -23,9 +24,10 @@ import ( ) type FrontProxyCACertificate struct { - resource *corev1.Secret - Client client.Client - TmpDirectory string + resource *corev1.Secret + Client client.Client + TmpDirectory string + CertExpirationThreshold time.Duration } func (r *FrontProxyCACertificate) GetHistogram() prometheus.Histogram { @@ -95,6 +97,7 @@ func (r *FrontProxyCACertificate) mutate(ctx context.Context, tenantControlPlane isValid, err := crypto.CheckCertificateAndPrivateKeyPairValidity( r.resource.Data[kubeadmconstants.FrontProxyCACertName], r.resource.Data[kubeadmconstants.FrontProxyCAKeyName], + r.CertExpirationThreshold, ) if err != nil { logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", kubeadmconstants.FrontProxyCACertAndKeyBaseName, err.Error())) diff --git a/internal/resources/konnectivity/certificate_resource.go b/internal/resources/konnectivity/certificate_resource.go index ebb2576..0442c7f 100644 --- a/internal/resources/konnectivity/certificate_resource.go +++ b/internal/resources/konnectivity/certificate_resource.go @@ -6,6 +6,7 @@ package konnectivity import ( "context" "fmt" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -27,8 +28,9 @@ import ( ) type CertificateResource struct { - resource *corev1.Secret - Client client.Client + resource *corev1.Secret + Client client.Client + CertExpirationThreshold time.Duration } func (r *CertificateResource) GetHistogram() prometheus.Histogram { @@ -117,7 +119,7 @@ func (r *CertificateResource) mutate(ctx context.Context, tenantControlPlane *ka isRotationRequested := utilities.IsRotationRequested(r.resource) if checksum := tenantControlPlane.Status.Addons.Konnectivity.Certificate.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.CalculateMapChecksum(r.resource.Data)) { - isValid, err := crypto.IsValidCertificateKeyPairBytes(r.resource.Data[corev1.TLSCertKey], r.resource.Data[corev1.TLSPrivateKeyKey]) + isValid, err := crypto.IsValidCertificateKeyPairBytes(r.resource.Data[corev1.TLSCertKey], r.resource.Data[corev1.TLSPrivateKeyKey], r.CertExpirationThreshold) if err != nil { logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", konnectivityCertAndKeyBaseName, err.Error())) } diff --git a/internal/resources/kubeconfig.go b/internal/resources/kubeconfig.go index 2a65cb6..864d132 100644 --- a/internal/resources/kubeconfig.go +++ b/internal/resources/kubeconfig.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "strings" + "time" "github.com/prometheus/client_golang/prometheus" corev1 "k8s.io/api/core/v1" @@ -33,11 +34,12 @@ const ( ) type KubeconfigResource struct { - resource *corev1.Secret - Client client.Client - Name string - KubeConfigFileName string - TmpDirectory string + resource *corev1.Secret + Client client.Client + Name string + KubeConfigFileName string + TmpDirectory string + CertExpirationThreshold time.Duration } func (r *KubeconfigResource) GetHistogram() prometheus.Histogram { @@ -189,8 +191,8 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam shouldCreate = shouldCreate || len(r.resource.Data) == 0 // Missing data key shouldCreate = shouldCreate || len(r.resource.Data[r.KubeConfigFileName]) == 0 // Missing kubeconfig file, must be generated shouldCreate = shouldCreate || !kubeadm.IsKubeconfigCAValid(r.resource.Data[r.KubeConfigFileName], caCertificatesSecret.Data[kubeadmconstants.CACertName]) - shouldCreate = shouldCreate || !kubeadm.IsKubeconfigValid(r.resource.Data[r.KubeConfigFileName]) // invalid kubeconfig, or expired client certificate - shouldCreate = shouldCreate || status.Checksum != checksum || len(r.resource.UID) == 0 // Wrong checksum + shouldCreate = shouldCreate || !kubeadm.IsKubeconfigValid(r.resource.Data[r.KubeConfigFileName], r.CertExpirationThreshold) // invalid kubeconfig, or expired client certificate + shouldCreate = shouldCreate || status.Checksum != checksum || len(r.resource.UID) == 0 // Wrong checksum shouldRotate := utilities.IsRotationRequested(r.resource)