From bc26c69b6149379a3800da8447445caf828a9983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Fern=C3=A1ndez=20L=C3=B3pez?= Date: Fri, 15 Mar 2019 19:47:18 +0100 Subject: [PATCH] kubeadm: Allow certain certs/keys to be missing on the secret. Under certain circumstances, specially when using an insecure external etcd cluster (no certificates), or when using external certificates ( no CA key), some keys inside the kubeadm-certs secret data can contain the key with an empty value on the map. When downloading certs just ignore those that are blank and inform the user about it. --- cmd/kubeadm/app/phases/copycerts/BUILD | 1 + cmd/kubeadm/app/phases/copycerts/copycerts.go | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/cmd/kubeadm/app/phases/copycerts/BUILD b/cmd/kubeadm/app/phases/copycerts/BUILD index 09699b6114..c8219074ea 100644 --- a/cmd/kubeadm/app/phases/copycerts/BUILD +++ b/cmd/kubeadm/app/phases/copycerts/BUILD @@ -22,6 +22,7 @@ go_library( "//staging/src/k8s.io/client-go/util/keyutil:go_default_library", "//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library", "//vendor/github.com/pkg/errors:go_default_library", + "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/cmd/kubeadm/app/phases/copycerts/copycerts.go b/cmd/kubeadm/app/phases/copycerts/copycerts.go index d8c073d9f6..438a152dae 100644 --- a/cmd/kubeadm/app/phases/copycerts/copycerts.go +++ b/cmd/kubeadm/app/phases/copycerts/copycerts.go @@ -35,6 +35,7 @@ import ( certutil "k8s.io/client-go/util/cert" keyutil "k8s.io/client-go/util/keyutil" bootstraputil "k8s.io/cluster-bootstrap/token/util" + "k8s.io/klog" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" nodebootstraptokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" @@ -191,6 +192,7 @@ func certsToTransfer(cfg *kubeadmapi.InitConfiguration) map[string]string { certs[externalEtcdCert] = cfg.Etcd.External.CertFile certs[externalEtcdKey] = cfg.Etcd.External.KeyFile } + return certs } @@ -209,7 +211,7 @@ func getDataFromDisk(cfg *kubeadmapi.InitConfiguration, key []byte) (map[string] // DownloadCerts downloads the certificates needed to join a new control plane. func DownloadCerts(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, key string) error { - fmt.Printf("[download-certs] downloading the certificates in Secret %q in the %q Namespace\n", kubeadmconstants.KubeadmCertsSecret, metav1.NamespaceSystem) + fmt.Printf("[download-certs] Downloading the certificates in Secret %q in the %q Namespace\n", kubeadmconstants.KubeadmCertsSecret, metav1.NamespaceSystem) decodedKey, err := hex.DecodeString(key) if err != nil { @@ -231,6 +233,10 @@ func DownloadCerts(client clientset.Interface, cfg *kubeadmapi.InitConfiguration if !found { return errors.New("couldn't find required certificate or key in Secret") } + if len(certOrKeyData) == 0 { + klog.V(1).Infof("[download-certs] Not saving %q to disk, since it is empty in the %q Secret\n", certOrKeyName, kubeadmconstants.KubeadmCertsSecret) + continue + } if err := writeCertOrKey(certOrKeyPath, certOrKeyData); err != nil { return err } @@ -261,14 +267,20 @@ func getSecret(client clientset.Interface) (*v1.Secret, error) { func getDataFromSecret(secret *v1.Secret, key []byte) (map[string][]byte, error) { secretData := map[string][]byte{} - for certName, encryptedCert := range secret.Data { - cert, err := cryptoutil.DecryptBytes(encryptedCert, key) - if err != nil { - // If any of the decrypt operations fail do not return a partial result, - // return an empty result immediately - return map[string][]byte{}, err + for secretName, encryptedSecret := range secret.Data { + // In some cases the secret might have empty data if the secrets were not present on disk + // when uploading. This can specially happen with external insecure etcd (no certs) + if len(encryptedSecret) > 0 { + cert, err := cryptoutil.DecryptBytes(encryptedSecret, key) + if err != nil { + // If any of the decrypt operations fail do not return a partial result, + // return an empty result immediately + return map[string][]byte{}, err + } + secretData[secretName] = cert + } else { + secretData[secretName] = []byte{} } - secretData[certName] = cert } return secretData, nil }