...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/phases/certs

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package certs
    18  
    19  import (
    20  	"crypto"
    21  	"crypto/x509"
    22  	"fmt"
    23  	"os"
    24  	"path/filepath"
    25  	"sync"
    26  
    27  	"github.com/pkg/errors"
    28  
    29  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    30  	"k8s.io/client-go/util/keyutil"
    31  	"k8s.io/klog/v2"
    32  
    33  	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
    34  	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
    35  	"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
    36  )
    37  
    38  var (
    39  	// certPeriodValidation is used to store if period validation was done for a certificate
    40  	certPeriodValidationMutex sync.Mutex
    41  	certPeriodValidation      = map[string]struct{}{}
    42  )
    43  
    44  // CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
    45  // If the PKI assets already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
    46  func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
    47  	klog.V(1).Infoln("creating PKI assets")
    48  
    49  	// This structure cannot handle multilevel CA hierarchies.
    50  	// This isn't a problem right now, but may become one in the future.
    51  
    52  	var certList Certificates
    53  
    54  	if cfg.Etcd.Local == nil {
    55  		certList = GetCertsWithoutEtcd()
    56  	} else {
    57  		certList = GetDefaultCertList()
    58  	}
    59  
    60  	certTree, err := certList.AsMap().CertTree()
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	if err := certTree.CreateTree(cfg); err != nil {
    66  		return errors.Wrap(err, "error creating PKI assets")
    67  	}
    68  
    69  	fmt.Printf("[certs] Valid certificates and keys now exist in %q\n", cfg.CertificatesDir)
    70  
    71  	// Service accounts are not x509 certs, so handled separately
    72  	return CreateServiceAccountKeyAndPublicKeyFiles(cfg.CertificatesDir, cfg.ClusterConfiguration.EncryptionAlgorithmType())
    73  }
    74  
    75  // CreateServiceAccountKeyAndPublicKeyFiles creates new public/private key files for signing service account users.
    76  // If the sa public/private key files already exist in the target folder, they are used only if evaluated equals; otherwise an error is returned.
    77  func CreateServiceAccountKeyAndPublicKeyFiles(certsDir string, keyType kubeadmapi.EncryptionAlgorithmType) error {
    78  	klog.V(1).Infoln("creating new public/private key files for signing service account users")
    79  	_, err := keyutil.PrivateKeyFromFile(filepath.Join(certsDir, kubeadmconstants.ServiceAccountPrivateKeyName))
    80  	if err == nil {
    81  		// kubeadm doesn't validate the existing certificate key more than this;
    82  		// Basically, if we find a key file with the same path kubeadm thinks those files
    83  		// are equal and doesn't bother writing a new file
    84  		fmt.Printf("[certs] Using the existing %q key\n", kubeadmconstants.ServiceAccountKeyBaseName)
    85  		return nil
    86  	} else if !os.IsNotExist(err) {
    87  		return errors.Wrapf(err, "file %s existed but it could not be loaded properly", kubeadmconstants.ServiceAccountPrivateKeyName)
    88  	}
    89  
    90  	// The key does NOT exist, let's generate it now
    91  	key, err := pkiutil.NewPrivateKey(keyType)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	// Write .key and .pub files to disk
    97  	fmt.Printf("[certs] Generating %q key and public key\n", kubeadmconstants.ServiceAccountKeyBaseName)
    98  
    99  	if err := pkiutil.WriteKey(certsDir, kubeadmconstants.ServiceAccountKeyBaseName, key); err != nil {
   100  		return err
   101  	}
   102  
   103  	return pkiutil.WritePublicKey(certsDir, kubeadmconstants.ServiceAccountKeyBaseName, key.Public())
   104  }
   105  
   106  // CreateCACertAndKeyFiles generates and writes out a given certificate authority.
   107  // The certSpec should be one of the variables from this package.
   108  func CreateCACertAndKeyFiles(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) error {
   109  	if certSpec.CAName != "" {
   110  		return errors.Errorf("this function should only be used for CAs, but cert %s has CA %s", certSpec.Name, certSpec.CAName)
   111  	}
   112  	klog.V(1).Infof("creating a new certificate authority for %s", certSpec.Name)
   113  
   114  	certConfig, err := certSpec.GetConfig(cfg)
   115  	if err != nil {
   116  		return err
   117  	}
   118  
   119  	caCert, caKey, err := pkiutil.NewCertificateAuthority(certConfig)
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	return writeCertificateAuthorityFilesIfNotExist(
   125  		cfg.CertificatesDir,
   126  		certSpec.BaseName,
   127  		caCert,
   128  		caKey,
   129  	)
   130  }
   131  
   132  // NewCSR will generate a new CSR and accompanying key
   133  func NewCSR(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) (*x509.CertificateRequest, crypto.Signer, error) {
   134  	certConfig, err := certSpec.GetConfig(cfg)
   135  	if err != nil {
   136  		return nil, nil, errors.Wrap(err, "failed to retrieve cert configuration")
   137  	}
   138  
   139  	return pkiutil.NewCSRAndKey(certConfig)
   140  }
   141  
   142  // CreateCertAndKeyFilesWithCA loads the given certificate authority from disk, then generates and writes out the given certificate and key.
   143  // The certSpec and caCertSpec should both be one of the variables from this package.
   144  func CreateCertAndKeyFilesWithCA(certSpec *KubeadmCert, caCertSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) error {
   145  	if certSpec.CAName != caCertSpec.Name {
   146  		return errors.Errorf("expected CAname for %s to be %q, but was %s", certSpec.Name, certSpec.CAName, caCertSpec.Name)
   147  	}
   148  
   149  	caCert, caKey, err := LoadCertificateAuthority(cfg.CertificatesDir, caCertSpec.BaseName)
   150  	if err != nil {
   151  		return errors.Wrapf(err, "couldn't load CA certificate %s", caCertSpec.Name)
   152  	}
   153  
   154  	return certSpec.CreateFromCA(cfg, caCert, caKey)
   155  }
   156  
   157  // LoadCertificateAuthority tries to load a CA in the given directory with the given name.
   158  func LoadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, crypto.Signer, error) {
   159  	// Checks if certificate authority exists in the PKI directory
   160  	if !pkiutil.CertOrKeyExist(pkiDir, baseName) {
   161  		return nil, nil, errors.Errorf("couldn't load %s certificate authority from %s", baseName, pkiDir)
   162  	}
   163  
   164  	// Try to load certificate authority .crt and .key from the PKI directory
   165  	caCert, caKey, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
   166  	if err != nil {
   167  		return nil, nil, errors.Wrapf(err, "failure loading %s certificate authority", baseName)
   168  	}
   169  	// Validate period
   170  	CheckCertificatePeriodValidity(baseName, caCert)
   171  
   172  	// Make sure the loaded CA cert actually is a CA
   173  	if !caCert.IsCA {
   174  		return nil, nil, errors.Errorf("%s certificate is not a certificate authority", baseName)
   175  	}
   176  
   177  	return caCert, caKey, nil
   178  }
   179  
   180  // writeCertificateAuthorityFilesIfNotExist write a new certificate Authority to the given path.
   181  // If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the
   182  // existing and the expected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
   183  // otherwise this function returns an error.
   184  func writeCertificateAuthorityFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey crypto.Signer) error {
   185  
   186  	// If cert or key exists, we should try to load them
   187  	if pkiutil.CertOrKeyExist(pkiDir, baseName) {
   188  
   189  		// Try to load .crt and .key from the PKI directory
   190  		caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, baseName)
   191  		if err != nil {
   192  			return errors.Wrapf(err, "failure loading %s certificate", baseName)
   193  		}
   194  		// Validate period
   195  		CheckCertificatePeriodValidity(baseName, caCert)
   196  
   197  		// Check if the existing cert is a CA
   198  		if !caCert.IsCA {
   199  			return errors.Errorf("certificate %s is not a CA", baseName)
   200  		}
   201  
   202  		// kubeadm doesn't validate the existing certificate Authority more than this;
   203  		// Basically, if we find a certificate file with the same path; and it is a CA
   204  		// kubeadm thinks those files are equal and doesn't bother writing a new file
   205  		fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
   206  	} else {
   207  		// Write .crt and .key files to disk
   208  		fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
   209  
   210  		if err := pkiutil.WriteCertAndKey(pkiDir, baseName, caCert, caKey); err != nil {
   211  			return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
   212  		}
   213  	}
   214  	return nil
   215  }
   216  
   217  // writeCertificateFilesIfNotExist write a new certificate to the given path.
   218  // If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the
   219  // existing and the expected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
   220  // otherwise this function returns an error.
   221  func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert *x509.Certificate, cert *x509.Certificate, key crypto.Signer, cfg *pkiutil.CertConfig) error {
   222  
   223  	// Checks if the signed certificate exists in the PKI directory
   224  	if pkiutil.CertOrKeyExist(pkiDir, baseName) {
   225  		// Try to load key from the PKI directory
   226  		_, err := pkiutil.TryLoadKeyFromDisk(pkiDir, baseName)
   227  		if err != nil {
   228  			return errors.Wrapf(err, "failure loading %s key", baseName)
   229  		}
   230  
   231  		// Try to load certificate from the PKI directory
   232  		signedCert, intermediates, err := pkiutil.TryLoadCertChainFromDisk(pkiDir, baseName)
   233  		if err != nil {
   234  			return errors.Wrapf(err, "failure loading %s certificate", baseName)
   235  		}
   236  		// Validate period
   237  		CheckCertificatePeriodValidity(baseName, signedCert)
   238  
   239  		// Check if the existing cert is signed by the given CA
   240  		if err := pkiutil.VerifyCertChain(signedCert, intermediates, signingCert); err != nil {
   241  			return errors.Errorf("certificate %s is not signed by corresponding CA", baseName)
   242  		}
   243  
   244  		// Check if the certificate has the correct attributes
   245  		if err := validateCertificateWithConfig(signedCert, baseName, cfg); err != nil {
   246  			return err
   247  		}
   248  
   249  		fmt.Printf("[certs] Using the existing %q certificate and key\n", baseName)
   250  	} else {
   251  		// Write .crt and .key files to disk
   252  		fmt.Printf("[certs] Generating %q certificate and key\n", baseName)
   253  
   254  		if err := pkiutil.WriteCertAndKey(pkiDir, baseName, cert, key); err != nil {
   255  			return errors.Wrapf(err, "failure while saving %s certificate and key", baseName)
   256  		}
   257  		if pkiutil.HasServerAuth(cert) {
   258  			fmt.Printf("[certs] %s serving cert is signed for DNS names %v and IPs %v\n", baseName, cert.DNSNames, cert.IPAddresses)
   259  		}
   260  	}
   261  
   262  	return nil
   263  }
   264  
   265  type certKeyLocation struct {
   266  	pkiDir     string
   267  	caBaseName string
   268  	baseName   string
   269  	uxName     string
   270  }
   271  
   272  // SharedCertificateExists verifies if the shared certificates exist and are still valid - the certificates must be
   273  // equal across control-plane nodes: ca.key, ca.crt, sa.key, sa.pub, front-proxy-ca.key, front-proxy-ca.crt and etcd/ca.key, etcd/ca.crt if local/stacked etcd
   274  // Missing private keys of CA are non-fatal and produce warnings.
   275  func SharedCertificateExists(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
   276  	var errs []error
   277  	if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
   278  		errs = append(errs, err)
   279  	}
   280  
   281  	if err := validatePrivatePublicKey(certKeyLocation{cfg.CertificatesDir, "", kubeadmconstants.ServiceAccountKeyBaseName, "service account"}); err != nil {
   282  		errs = append(errs, err)
   283  	}
   284  
   285  	if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName, "", "front-proxy CA"}); err != nil {
   286  		errs = append(errs, err)
   287  	}
   288  
   289  	// in case of local/stacked etcd
   290  	if cfg.Etcd.External == nil {
   291  		if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, "", "etcd CA"}); err != nil {
   292  			errs = append(errs, err)
   293  		}
   294  	}
   295  	if len(errs) != 0 {
   296  		return false, utilerrors.NewAggregate(errs)
   297  	}
   298  	return true, nil
   299  }
   300  
   301  // UsingExternalCA determines whether the user is relying on an external CA.  We currently implicitly determine this is the case
   302  // when the CA Cert is present but the CA Key is not.
   303  // This allows us to, e.g., skip generating certs or not start the csr signing controller.
   304  // In case we are using an external front-proxy CA, the function validates the certificates signed by front-proxy CA that should be provided by the user.
   305  func UsingExternalCA(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
   306  
   307  	if err := validateCACert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
   308  		return false, err
   309  	}
   310  
   311  	caKeyPath := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)
   312  	if _, err := os.Stat(caKeyPath); !os.IsNotExist(err) {
   313  		return false, nil
   314  	}
   315  
   316  	if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, kubeadmconstants.APIServerCertAndKeyBaseName, "API server"}); err != nil {
   317  		return true, err
   318  	}
   319  
   320  	if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName, "API server kubelet client"}); err != nil {
   321  		return true, err
   322  	}
   323  
   324  	return true, nil
   325  }
   326  
   327  // UsingExternalFrontProxyCA determines whether the user is relying on an external front-proxy CA.  We currently implicitly determine this is the case
   328  // when the front proxy CA Cert is present but the front proxy CA Key is not.
   329  // In case we are using an external front-proxy CA, the function validates the certificates signed by front-proxy CA that should be provided by the user.
   330  func UsingExternalFrontProxyCA(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
   331  
   332  	if err := validateCACert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName, "", "front-proxy CA"}); err != nil {
   333  		return false, err
   334  	}
   335  
   336  	frontProxyCAKeyPath := filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCAKeyName)
   337  	if _, err := os.Stat(frontProxyCAKeyPath); !os.IsNotExist(err) {
   338  		return false, nil
   339  	}
   340  
   341  	if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName, kubeadmconstants.FrontProxyClientCertAndKeyBaseName, "front-proxy client"}); err != nil {
   342  		return true, err
   343  	}
   344  
   345  	return true, nil
   346  }
   347  
   348  // UsingExternalEtcdCA determines whether the user is relying on an external etcd CA. We currently implicitly determine this is the case
   349  // when the etcd CA Cert is present but the etcd CA Key is not.
   350  // In case we are using an external etcd CA, the function validates the certificates signed by etcd CA that should be provided by the user.
   351  func UsingExternalEtcdCA(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
   352  	if err := validateCACert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, "", "etcd CA"}); err != nil {
   353  		return false, err
   354  	}
   355  
   356  	path := filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCAKeyName)
   357  	if _, err := os.Stat(path); !os.IsNotExist(err) {
   358  		return false, nil
   359  	}
   360  
   361  	if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName, "apiserver etcd client"}); err != nil {
   362  		return true, err
   363  	}
   364  
   365  	if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.EtcdServerCertAndKeyBaseName, "etcd server"}); err != nil {
   366  		return true, err
   367  	}
   368  
   369  	if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.EtcdPeerCertAndKeyBaseName, "etcd peer"}); err != nil {
   370  		return true, err
   371  	}
   372  
   373  	if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName, "etcd health-check client"}); err != nil {
   374  		return true, err
   375  	}
   376  
   377  	return true, nil
   378  }
   379  
   380  // validateCACert tries to load a x509 certificate from pkiDir and validates that it is a CA
   381  func validateCACert(l certKeyLocation) error {
   382  	// Check CA Cert
   383  	caCert, err := pkiutil.TryLoadCertFromDisk(l.pkiDir, l.caBaseName)
   384  	if err != nil {
   385  		return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
   386  	}
   387  	// Validate period
   388  	CheckCertificatePeriodValidity(l.uxName, caCert)
   389  
   390  	// Check if cert is a CA
   391  	if !caCert.IsCA {
   392  		return errors.Errorf("certificate %s is not a CA", l.uxName)
   393  	}
   394  	return nil
   395  }
   396  
   397  // validateCACertAndKey tries to load a x509 certificate and private key from pkiDir,
   398  // and validates that the cert is a CA. Failure to load the key produces a warning.
   399  func validateCACertAndKey(l certKeyLocation) error {
   400  	if err := validateCACert(l); err != nil {
   401  		return err
   402  	}
   403  
   404  	_, err := pkiutil.TryLoadKeyFromDisk(l.pkiDir, l.caBaseName)
   405  	if err != nil {
   406  		klog.Warningf("assuming external key for %s: %v", l.uxName, err)
   407  	}
   408  	return nil
   409  }
   410  
   411  // validateSignedCert tries to load a x509 certificate and private key from pkiDir and validates
   412  // that the cert is signed by a given CA
   413  func validateSignedCert(l certKeyLocation) error {
   414  	// Try to load CA
   415  	caCert, err := pkiutil.TryLoadCertFromDisk(l.pkiDir, l.caBaseName)
   416  	if err != nil {
   417  		return errors.Wrapf(err, "failure loading certificate authority for %s", l.uxName)
   418  	}
   419  	// Validate period
   420  	CheckCertificatePeriodValidity(l.uxName, caCert)
   421  
   422  	return validateSignedCertWithCA(l, caCert)
   423  }
   424  
   425  // validateSignedCertWithCA tries to load a certificate and private key and
   426  // validates that the cert is signed by the given caCert
   427  func validateSignedCertWithCA(l certKeyLocation, caCert *x509.Certificate) error {
   428  	// Try to load key from the PKI directory
   429  	_, err := pkiutil.TryLoadKeyFromDisk(l.pkiDir, l.baseName)
   430  	if err != nil {
   431  		return errors.Wrapf(err, "failure loading key for %s", l.baseName)
   432  	}
   433  
   434  	// Try to load certificate from the PKI directory
   435  	signedCert, intermediates, err := pkiutil.TryLoadCertChainFromDisk(l.pkiDir, l.baseName)
   436  	if err != nil {
   437  		return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
   438  	}
   439  	// Validate period
   440  	CheckCertificatePeriodValidity(l.uxName, signedCert)
   441  
   442  	// Check if the cert is signed by the CA
   443  	if err := pkiutil.VerifyCertChain(signedCert, intermediates, caCert); err != nil {
   444  		return errors.Wrapf(err, "certificate %s is not signed by corresponding CA", l.uxName)
   445  	}
   446  	return nil
   447  }
   448  
   449  // validatePrivatePublicKey tries to load a private key from pkiDir
   450  func validatePrivatePublicKey(l certKeyLocation) error {
   451  	// Try to load key
   452  	_, _, err := pkiutil.TryLoadPrivatePublicKeyFromDisk(l.pkiDir, l.baseName)
   453  	return errors.Wrapf(err, "failure loading key for %s", l.uxName)
   454  }
   455  
   456  // validateCertificateWithConfig makes sure that a given certificate is valid at
   457  // least for the SANs defined in the configuration.
   458  func validateCertificateWithConfig(cert *x509.Certificate, baseName string, cfg *pkiutil.CertConfig) error {
   459  	for _, dnsName := range cfg.AltNames.DNSNames {
   460  		if err := cert.VerifyHostname(dnsName); err != nil {
   461  			return errors.Wrapf(err, "certificate %s is invalid", baseName)
   462  		}
   463  	}
   464  	for _, ipAddress := range cfg.AltNames.IPs {
   465  		if err := cert.VerifyHostname(ipAddress.String()); err != nil {
   466  			return errors.Wrapf(err, "certificate %s is invalid", baseName)
   467  		}
   468  	}
   469  	return nil
   470  }
   471  
   472  // CheckCertificatePeriodValidity takes a certificate and prints a warning if its period
   473  // is not valid related to the current time. It does so only if the certificate was not validated already
   474  // by keeping track with a cache.
   475  func CheckCertificatePeriodValidity(baseName string, cert *x509.Certificate) {
   476  	certPeriodValidationMutex.Lock()
   477  	defer certPeriodValidationMutex.Unlock()
   478  	if _, exists := certPeriodValidation[baseName]; exists {
   479  		return
   480  	}
   481  	certPeriodValidation[baseName] = struct{}{}
   482  
   483  	klog.V(5).Infof("validating certificate period for %s certificate", baseName)
   484  	if err := pkiutil.ValidateCertPeriod(cert, 0); err != nil {
   485  		klog.Warningf("WARNING: could not validate bounds for certificate %s: %v", baseName, err)
   486  	}
   487  }
   488  

View as plain text