diff --git a/cmd/kubeadm/app/phases/certs/certs.go b/cmd/kubeadm/app/phases/certs/certs.go index 7e8a60bce91..738fccf1743 100644 --- a/cmd/kubeadm/app/phases/certs/certs.go +++ b/cmd/kubeadm/app/phases/certs/certs.go @@ -381,6 +381,38 @@ func UsingExternalFrontProxyCA(cfg *kubeadmapi.ClusterConfiguration) (bool, erro return true, nil } +// UsingExternalEtcdCA determines whether the user is relying on an external etcd CA. We currently implicitly determine this is the case +// when the etcd CA Cert is present but the etcd CA Key is not. +// 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. +func UsingExternalEtcdCA(cfg *kubeadmapi.ClusterConfiguration) (bool, error) { + if err := validateCACert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, "", "etcd CA"}); err != nil { + return false, err + } + + path := filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdCAKeyName) + if _, err := os.Stat(path); !os.IsNotExist(err) { + return false, nil + } + + if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName, "apiserver etcd client"}); err != nil { + return true, err + } + + if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.EtcdServerCertAndKeyBaseName, "etcd server"}); err != nil { + return true, err + } + + if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.EtcdPeerCertAndKeyBaseName, "etcd peer"}); err != nil { + return true, err + } + + if err := validateSignedCert(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName, kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName, "etcd health-check client"}); err != nil { + return true, err + } + + return true, nil +} + // validateCACert tries to load a x509 certificate from pkiDir and validates that it is a CA func validateCACert(l certKeyLocation) error { // Check CA Cert diff --git a/cmd/kubeadm/app/phases/certs/renewal/manager.go b/cmd/kubeadm/app/phases/certs/renewal/manager.go index 09421d7e816..764bcb01a80 100644 --- a/cmd/kubeadm/app/phases/certs/renewal/manager.go +++ b/cmd/kubeadm/app/phases/certs/renewal/manager.go @@ -166,6 +166,7 @@ func NewManager(cfg *kubeadmapi.ClusterConfiguration, kubernetesDir string) (*Ma LongName: kubeConfig.longName, FileName: kubeConfig.fileName, CABaseName: kubeadmconstants.CACertAndKeyBaseName, // all certificates in kubeConfig files are signed by the Kubernetes CA + CAName: kubeadmconstants.CACertAndKeyBaseName, readwriter: kubeConfigReadWriter, } } @@ -374,7 +375,11 @@ func (rm *Manager) IsExternallyManaged(caBaseName string) (bool, error) { } return externallyManaged, nil case kubeadmconstants.EtcdCACertAndKeyBaseName: - return false, nil + externallyManaged, err := certsphase.UsingExternalEtcdCA(rm.cfg) + if err != nil { + return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", caBaseName) + } + return externallyManaged, nil default: return false, errors.Errorf("unknown certificate authority %s", caBaseName) }