mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #94504 from neolit123/1.20-warning-cert-bounds-client-side
kubeadm: print warnings on invalid cert period instead of erroring out
This commit is contained in:
commit
604569482f
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||||
kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
|
kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
|
||||||
@ -228,7 +229,9 @@ func runCAPhase(ca *certsphase.KubeadmCert) func(c workflow.RunData) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), ca.BaseName); err == nil {
|
if cert, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), ca.BaseName); err == nil {
|
||||||
|
certsphase.CheckCertificatePeriodValidity(ca.BaseName, cert)
|
||||||
|
|
||||||
if _, err := pkiutil.TryLoadKeyFromDisk(data.CertificateDir(), ca.BaseName); err == nil {
|
if _, err := pkiutil.TryLoadKeyFromDisk(data.CertificateDir(), ca.BaseName); err == nil {
|
||||||
fmt.Printf("[certs] Using existing %s certificate authority\n", ca.BaseName)
|
fmt.Printf("[certs] Using existing %s certificate authority\n", ca.BaseName)
|
||||||
return nil
|
return nil
|
||||||
@ -261,11 +264,15 @@ func runCertPhase(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if certData, _, err := pkiutil.TryLoadCertAndKeyFromDisk(data.CertificateDir(), cert.BaseName); err == nil {
|
if certData, _, err := pkiutil.TryLoadCertAndKeyFromDisk(data.CertificateDir(), cert.BaseName); err == nil {
|
||||||
|
certsphase.CheckCertificatePeriodValidity(cert.BaseName, certData)
|
||||||
|
|
||||||
caCertData, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), caCert.BaseName)
|
caCertData, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), caCert.BaseName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "couldn't load CA certificate %s", caCert.Name)
|
return errors.Wrapf(err, "couldn't load CA certificate %s", caCert.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
certsphase.CheckCertificatePeriodValidity(caCert.BaseName, caCertData)
|
||||||
|
|
||||||
if err := certData.CheckSignatureFrom(caCertData); err != nil {
|
if err := certData.CheckSignatureFrom(caCertData); err != nil {
|
||||||
return errors.Wrapf(err, "[certs] certificate %s not signed by CA certificate %s", cert.BaseName, caCert.BaseName)
|
return errors.Wrapf(err, "[certs] certificate %s not signed by CA certificate %s", cert.BaseName, caCert.BaseName)
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,9 @@ func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
|
|||||||
|
|
||||||
caCert, err := pkiutil.TryLoadCertFromDisk(ic.CertificatesDir, ca.BaseName)
|
caCert, err := pkiutil.TryLoadCertFromDisk(ic.CertificatesDir, ca.BaseName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
// Validate period
|
||||||
|
CheckCertificatePeriodValidity(ca.BaseName, caCert)
|
||||||
|
|
||||||
// Cert exists already, make sure it's valid
|
// Cert exists already, make sure it's valid
|
||||||
if !caCert.IsCA {
|
if !caCert.IsCA {
|
||||||
return errors.Errorf("certificate %q is not a CA", ca.Name)
|
return errors.Errorf("certificate %q is not a CA", ca.Name)
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"k8s.io/client-go/util/keyutil"
|
"k8s.io/client-go/util/keyutil"
|
||||||
@ -32,6 +33,12 @@ import (
|
|||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// certPeriodValidation is used to store if period validation was done for a certificate
|
||||||
|
certPeriodValidationMutex sync.Mutex
|
||||||
|
certPeriodValidation = map[string]struct{}{}
|
||||||
|
)
|
||||||
|
|
||||||
// CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
|
// CreatePKIAssets will create and write to disk all PKI assets necessary to establish the control plane.
|
||||||
// If the PKI assets already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
|
// If the PKI assets already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
|
||||||
func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
|
func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
|
||||||
@ -166,6 +173,8 @@ func LoadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrapf(err, "failure loading %s certificate authority", baseName)
|
return nil, nil, errors.Wrapf(err, "failure loading %s certificate authority", baseName)
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
CheckCertificatePeriodValidity(baseName, caCert)
|
||||||
|
|
||||||
// Make sure the loaded CA cert actually is a CA
|
// Make sure the loaded CA cert actually is a CA
|
||||||
if !caCert.IsCA {
|
if !caCert.IsCA {
|
||||||
@ -189,6 +198,8 @@ func writeCertificateAuthorityFilesIfNotExist(pkiDir string, baseName string, ca
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
CheckCertificatePeriodValidity(baseName, caCert)
|
||||||
|
|
||||||
// Check if the existing cert is a CA
|
// Check if the existing cert is a CA
|
||||||
if !caCert.IsCA {
|
if !caCert.IsCA {
|
||||||
@ -223,6 +234,8 @@ func writeCertificateFilesIfNotExist(pkiDir string, baseName string, signingCert
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
return errors.Wrapf(err, "failure loading %s certificate", baseName)
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
CheckCertificatePeriodValidity(baseName, signedCert)
|
||||||
|
|
||||||
// Check if the existing cert is signed by the given CA
|
// Check if the existing cert is signed by the given CA
|
||||||
if err := signedCert.CheckSignatureFrom(signingCert); err != nil {
|
if err := signedCert.CheckSignatureFrom(signingCert); err != nil {
|
||||||
@ -365,6 +378,8 @@ func validateCACert(l certKeyLocation) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
CheckCertificatePeriodValidity(l.uxName, caCert)
|
||||||
|
|
||||||
// Check if cert is a CA
|
// Check if cert is a CA
|
||||||
if !caCert.IsCA {
|
if !caCert.IsCA {
|
||||||
@ -395,6 +410,8 @@ func validateSignedCert(l certKeyLocation) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failure loading certificate authority for %s", l.uxName)
|
return errors.Wrapf(err, "failure loading certificate authority for %s", l.uxName)
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
CheckCertificatePeriodValidity(l.uxName, caCert)
|
||||||
|
|
||||||
return validateSignedCertWithCA(l, caCert)
|
return validateSignedCertWithCA(l, caCert)
|
||||||
}
|
}
|
||||||
@ -406,6 +423,8 @@ func validateSignedCertWithCA(l certKeyLocation, caCert *x509.Certificate) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
return errors.Wrapf(err, "failure loading certificate for %s", l.uxName)
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
CheckCertificatePeriodValidity(l.uxName, signedCert)
|
||||||
|
|
||||||
// Check if the cert is signed by the CA
|
// Check if the cert is signed by the CA
|
||||||
if err := signedCert.CheckSignatureFrom(caCert); err != nil {
|
if err := signedCert.CheckSignatureFrom(caCert); err != nil {
|
||||||
@ -439,3 +458,21 @@ func validateCertificateWithConfig(cert *x509.Certificate, baseName string, cfg
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckCertificatePeriodValidity takes a certificate and prints a warning if its period
|
||||||
|
// is not valid related to the current time. It does so only if the certificate was not validated already
|
||||||
|
// by keeping track with a cache.
|
||||||
|
func CheckCertificatePeriodValidity(baseName string, cert *x509.Certificate) {
|
||||||
|
certPeriodValidationMutex.Lock()
|
||||||
|
if _, exists := certPeriodValidation[baseName]; exists {
|
||||||
|
certPeriodValidationMutex.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
certPeriodValidation[baseName] = struct{}{}
|
||||||
|
certPeriodValidationMutex.Unlock()
|
||||||
|
|
||||||
|
klog.V(5).Infof("validating certificate period for %s certificate", baseName)
|
||||||
|
if err := pkiutil.ValidateCertPeriod(cert, 0); err != nil {
|
||||||
|
klog.Warningf("WARNING: could not validate bounds for certificate %s: %v", baseName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||||
"//cmd/kubeadm/app/constants:go_default_library",
|
"//cmd/kubeadm/app/constants:go_default_library",
|
||||||
|
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||||
"//cmd/kubeadm/app/util:go_default_library",
|
"//cmd/kubeadm/app/util:go_default_library",
|
||||||
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
||||||
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
"//cmd/kubeadm/app/util/pkiutil:go_default_library",
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
|
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||||
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
|
||||||
@ -140,6 +141,9 @@ func getKubeConfigSpecs(cfg *kubeadmapi.InitConfiguration) (map[string]*kubeConf
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
return nil, errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
certsphase.CheckCertificatePeriodValidity(kubeadmconstants.CACertAndKeyBaseName, caCert)
|
||||||
|
|
||||||
configs, err := getKubeConfigSpecsBase(cfg)
|
configs, err := getKubeConfigSpecsBase(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -282,6 +286,8 @@ func WriteKubeConfigWithClientCert(out io.Writer, cfg *kubeadmapi.InitConfigurat
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
certsphase.CheckCertificatePeriodValidity(kubeadmconstants.CACertAndKeyBaseName, caCert)
|
||||||
|
|
||||||
controlPlaneEndpoint, err := kubeadmutil.GetControlPlaneEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
|
controlPlaneEndpoint, err := kubeadmutil.GetControlPlaneEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -309,6 +315,8 @@ func WriteKubeConfigWithToken(out io.Writer, cfg *kubeadmapi.InitConfiguration,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
return errors.Wrap(err, "couldn't create a kubeconfig; the CA files couldn't be loaded")
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
certsphase.CheckCertificatePeriodValidity(kubeadmconstants.CACertAndKeyBaseName, caCert)
|
||||||
|
|
||||||
controlPlaneEndpoint, err := kubeadmutil.GetControlPlaneEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
|
controlPlaneEndpoint, err := kubeadmutil.GetControlPlaneEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -354,6 +362,8 @@ func ValidateKubeconfigsForExternalCA(outDir string, cfg *kubeadmapi.InitConfigu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "the CA file couldn't be loaded")
|
return errors.Wrapf(err, "the CA file couldn't be loaded")
|
||||||
}
|
}
|
||||||
|
// Validate period
|
||||||
|
certsphase.CheckCertificatePeriodValidity(kubeadmconstants.CACertAndKeyBaseName, caCert)
|
||||||
|
|
||||||
// validate user provided kubeconfig files for the scheduler and controller-manager
|
// validate user provided kubeconfig files for the scheduler and controller-manager
|
||||||
localAPIEndpoint, err := kubeadmutil.GetLocalAPIEndpoint(&cfg.LocalAPIEndpoint)
|
localAPIEndpoint, err := kubeadmutil.GetLocalAPIEndpoint(&cfg.LocalAPIEndpoint)
|
||||||
|
@ -240,7 +240,7 @@ func TryLoadCertAndKeyFromDisk(pkiPath, name string) (*x509.Certificate, crypto.
|
|||||||
return cert, key, nil
|
return cert, key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryLoadCertFromDisk tries to load the cert from the disk and validates that it is valid
|
// TryLoadCertFromDisk tries to load the cert from the disk
|
||||||
func TryLoadCertFromDisk(pkiPath, name string) (*x509.Certificate, error) {
|
func TryLoadCertFromDisk(pkiPath, name string) (*x509.Certificate, error) {
|
||||||
certificatePath := pathForCert(pkiPath, name)
|
certificatePath := pathForCert(pkiPath, name)
|
||||||
|
|
||||||
@ -253,15 +253,6 @@ func TryLoadCertFromDisk(pkiPath, name string) (*x509.Certificate, error) {
|
|||||||
// TODO: Support multiple certs here in order to be able to rotate certs
|
// TODO: Support multiple certs here in order to be able to rotate certs
|
||||||
cert := certs[0]
|
cert := certs[0]
|
||||||
|
|
||||||
// Check so that the certificate is valid now
|
|
||||||
now := time.Now()
|
|
||||||
if now.Before(cert.NotBefore) {
|
|
||||||
return nil, errors.New("the certificate is not valid yet")
|
|
||||||
}
|
|
||||||
if now.After(cert.NotAfter) {
|
|
||||||
return nil, errors.New("the certificate has expired")
|
|
||||||
}
|
|
||||||
|
|
||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,3 +610,17 @@ func RemoveDuplicateAltNames(altNames *certutil.AltNames) {
|
|||||||
}
|
}
|
||||||
altNames.IPs = ips
|
altNames.IPs = ips
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateCertPeriod checks if the certificate is valid relative to the current time
|
||||||
|
// (+/- offset)
|
||||||
|
func ValidateCertPeriod(cert *x509.Certificate, offset time.Duration) error {
|
||||||
|
period := fmt.Sprintf("NotBefore: %v, NotAfter: %v", cert.NotBefore, cert.NotAfter)
|
||||||
|
now := time.Now().Add(offset)
|
||||||
|
if now.Before(cert.NotBefore) {
|
||||||
|
return errors.Errorf("the certificate is not valid yet: %s", period)
|
||||||
|
}
|
||||||
|
if now.After(cert.NotAfter) {
|
||||||
|
return errors.Errorf("the certificate has expired: %s", period)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user