Merge pull request #94988 from neolit123/1.20-tollerate-missing-ca-key-on-join

kubeadm: warn but do not error out on missing CA keys on CP join
This commit is contained in:
Kubernetes Prow Robot 2020-09-28 06:36:48 -07:00 committed by GitHub
commit db9f1e91d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 8 deletions

View File

@ -286,6 +286,7 @@ type certKeyLocation struct {
// SharedCertificateExists verifies if the shared certificates - the certificates that must be
// equal across control-plane nodes: ca.key, ca.crt, sa.key, sa.pub + etcd/ca.key, etcd/ca.crt if local/stacked etcd
// Missing keys are non-fatal and produce warnings.
func SharedCertificateExists(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
@ -373,7 +374,7 @@ func validateCACert(l certKeyLocation) error {
}
// validateCACertAndKey tries to load a x509 certificate and private key from pkiDir,
// and validates that the cert is a CA
// and validates that the cert is a CA. Failure to load the key produces a warning.
func validateCACertAndKey(l certKeyLocation) error {
if err := validateCACert(l); err != nil {
return err
@ -381,7 +382,7 @@ func validateCACertAndKey(l certKeyLocation) error {
_, err := pkiutil.TryLoadKeyFromDisk(l.pkiDir, l.caBaseName)
if err != nil {
return errors.Wrapf(err, "failure loading key for %s", l.uxName)
klog.Warningf("assuming external key for %s: %v", l.uxName, err)
}
return nil
}

View File

@ -401,6 +401,19 @@ func TestSharedCertificateExists(t *testing.T) {
},
expectedError: true,
},
{
name: "missing ca.key",
files: certstestutil.PKIFiles{
"ca.crt": caCert,
"front-proxy-ca.crt": caCert,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
"sa.key": key,
"etcd/ca.crt": caCert,
"etcd/ca.key": caKey,
},
expectedError: false,
},
{
name: "missing sa.key",
files: certstestutil.PKIFiles{
@ -642,7 +655,7 @@ func TestValidateMethods(t *testing.T) {
name: "validateCACertAndKey (key missing)",
validateFunc: validateCACertAndKey,
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
expectedSuccess: false,
expectedSuccess: true,
},
{
name: "validateSignedCert",
@ -666,6 +679,15 @@ func TestValidateMethods(t *testing.T) {
loc: certKeyLocation{baseName: "sa", uxName: "service account"},
expectedSuccess: true,
},
{
name: "validatePrivatePublicKey (missing key)",
files: certstestutil.PKIFiles{
"sa.pub": key.Public(),
},
validateFunc: validatePrivatePublicKey,
loc: certKeyLocation{baseName: "sa", uxName: "service account"},
expectedSuccess: false,
},
}
for _, test := range tests {

View File

@ -67,15 +67,31 @@ type kubeConfigSpec struct {
// CreateJoinControlPlaneKubeConfigFiles will create and write to disk the kubeconfig files required by kubeadm
// join --control-plane workflow, plus the admin kubeconfig file used by the administrator and kubeadm itself; the
// kubelet.conf file must not be created because it will be created and signed by the kubelet TLS bootstrap process.
// If any kubeconfig files already exists, it used only if evaluated equal; otherwise an error is returned.
// When not using external CA mode, if a kubeconfig file already exists it is used only if evaluated equal,
// otherwise an error is returned. For external CA mode, the creation of kubeconfig files is skipped.
func CreateJoinControlPlaneKubeConfigFiles(outDir string, cfg *kubeadmapi.InitConfiguration) error {
return createKubeConfigFiles(
outDir,
cfg,
var externaCA bool
caKeyPath := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)
if _, err := os.Stat(caKeyPath); os.IsNotExist(err) {
externaCA = true
}
files := []string{
kubeadmconstants.AdminKubeConfigFileName,
kubeadmconstants.ControllerManagerKubeConfigFileName,
kubeadmconstants.SchedulerKubeConfigFileName,
)
}
for _, file := range files {
if externaCA {
fmt.Printf("[kubeconfig] External CA mode: Using user provided %s\n", file)
continue
}
if err := createKubeConfigFiles(outDir, cfg, file); err != nil {
return err
}
}
return nil
}
// CreateKubeConfigFile creates a kubeconfig file.