Skip to content

Commit db9f1e9

Browse files
authored
Merge pull request kubernetes#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
2 parents 4b24dca + 7c783fa commit db9f1e9

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

cmd/kubeadm/app/phases/certs/certs.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ type certKeyLocation struct {
286286

287287
// SharedCertificateExists verifies if the shared certificates - the certificates that must be
288288
// equal across control-plane nodes: ca.key, ca.crt, sa.key, sa.pub + etcd/ca.key, etcd/ca.crt if local/stacked etcd
289+
// Missing keys are non-fatal and produce warnings.
289290
func SharedCertificateExists(cfg *kubeadmapi.ClusterConfiguration) (bool, error) {
290291

291292
if err := validateCACertAndKey(certKeyLocation{cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName, "", "CA"}); err != nil {
@@ -373,15 +374,15 @@ func validateCACert(l certKeyLocation) error {
373374
}
374375

375376
// validateCACertAndKey tries to load a x509 certificate and private key from pkiDir,
376-
// and validates that the cert is a CA
377+
// and validates that the cert is a CA. Failure to load the key produces a warning.
377378
func validateCACertAndKey(l certKeyLocation) error {
378379
if err := validateCACert(l); err != nil {
379380
return err
380381
}
381382

382383
_, err := pkiutil.TryLoadKeyFromDisk(l.pkiDir, l.caBaseName)
383384
if err != nil {
384-
return errors.Wrapf(err, "failure loading key for %s", l.uxName)
385+
klog.Warningf("assuming external key for %s: %v", l.uxName, err)
385386
}
386387
return nil
387388
}

cmd/kubeadm/app/phases/certs/certs_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,19 @@ func TestSharedCertificateExists(t *testing.T) {
401401
},
402402
expectedError: true,
403403
},
404+
{
405+
name: "missing ca.key",
406+
files: certstestutil.PKIFiles{
407+
"ca.crt": caCert,
408+
"front-proxy-ca.crt": caCert,
409+
"front-proxy-ca.key": caKey,
410+
"sa.pub": publicKey,
411+
"sa.key": key,
412+
"etcd/ca.crt": caCert,
413+
"etcd/ca.key": caKey,
414+
},
415+
expectedError: false,
416+
},
404417
{
405418
name: "missing sa.key",
406419
files: certstestutil.PKIFiles{
@@ -642,7 +655,7 @@ func TestValidateMethods(t *testing.T) {
642655
name: "validateCACertAndKey (key missing)",
643656
validateFunc: validateCACertAndKey,
644657
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
645-
expectedSuccess: false,
658+
expectedSuccess: true,
646659
},
647660
{
648661
name: "validateSignedCert",
@@ -666,6 +679,15 @@ func TestValidateMethods(t *testing.T) {
666679
loc: certKeyLocation{baseName: "sa", uxName: "service account"},
667680
expectedSuccess: true,
668681
},
682+
{
683+
name: "validatePrivatePublicKey (missing key)",
684+
files: certstestutil.PKIFiles{
685+
"sa.pub": key.Public(),
686+
},
687+
validateFunc: validatePrivatePublicKey,
688+
loc: certKeyLocation{baseName: "sa", uxName: "service account"},
689+
expectedSuccess: false,
690+
},
669691
}
670692

671693
for _, test := range tests {

cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,31 @@ type kubeConfigSpec struct {
6767
// CreateJoinControlPlaneKubeConfigFiles will create and write to disk the kubeconfig files required by kubeadm
6868
// join --control-plane workflow, plus the admin kubeconfig file used by the administrator and kubeadm itself; the
6969
// kubelet.conf file must not be created because it will be created and signed by the kubelet TLS bootstrap process.
70-
// If any kubeconfig files already exists, it used only if evaluated equal; otherwise an error is returned.
70+
// When not using external CA mode, if a kubeconfig file already exists it is used only if evaluated equal,
71+
// otherwise an error is returned. For external CA mode, the creation of kubeconfig files is skipped.
7172
func CreateJoinControlPlaneKubeConfigFiles(outDir string, cfg *kubeadmapi.InitConfiguration) error {
72-
return createKubeConfigFiles(
73-
outDir,
74-
cfg,
73+
var externaCA bool
74+
caKeyPath := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)
75+
if _, err := os.Stat(caKeyPath); os.IsNotExist(err) {
76+
externaCA = true
77+
}
78+
79+
files := []string{
7580
kubeadmconstants.AdminKubeConfigFileName,
7681
kubeadmconstants.ControllerManagerKubeConfigFileName,
7782
kubeadmconstants.SchedulerKubeConfigFileName,
78-
)
83+
}
84+
85+
for _, file := range files {
86+
if externaCA {
87+
fmt.Printf("[kubeconfig] External CA mode: Using user provided %s\n", file)
88+
continue
89+
}
90+
if err := createKubeConfigFiles(outDir, cfg, file); err != nil {
91+
return err
92+
}
93+
}
94+
return nil
7995
}
8096

8197
// CreateKubeConfigFile creates a kubeconfig file.

0 commit comments

Comments
 (0)