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.
pull/564/head
Rafael Fernández López 2019-03-15 19:47:18 +01:00
parent b0494b081d
commit bc26c69b61
No known key found for this signature in database
GPG Key ID: 8902294E78418CF9
2 changed files with 21 additions and 8 deletions

View File

@ -22,6 +22,7 @@ go_library(
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library", "//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
"//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library", "//staging/src/k8s.io/cluster-bootstrap/token/util:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library", "//vendor/github.com/pkg/errors:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
], ],
) )

View File

@ -35,6 +35,7 @@ import (
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
keyutil "k8s.io/client-go/util/keyutil" keyutil "k8s.io/client-go/util/keyutil"
bootstraputil "k8s.io/cluster-bootstrap/token/util" bootstraputil "k8s.io/cluster-bootstrap/token/util"
"k8s.io/klog"
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"
nodebootstraptokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" 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[externalEtcdCert] = cfg.Etcd.External.CertFile
certs[externalEtcdKey] = cfg.Etcd.External.KeyFile certs[externalEtcdKey] = cfg.Etcd.External.KeyFile
} }
return certs 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. // DownloadCerts downloads the certificates needed to join a new control plane.
func DownloadCerts(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, key string) error { 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) decodedKey, err := hex.DecodeString(key)
if err != nil { if err != nil {
@ -231,6 +233,10 @@ func DownloadCerts(client clientset.Interface, cfg *kubeadmapi.InitConfiguration
if !found { if !found {
return errors.New("couldn't find required certificate or key in Secret") 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 { if err := writeCertOrKey(certOrKeyPath, certOrKeyData); err != nil {
return err 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) { func getDataFromSecret(secret *v1.Secret, key []byte) (map[string][]byte, error) {
secretData := map[string][]byte{} secretData := map[string][]byte{}
for certName, encryptedCert := range secret.Data { for secretName, encryptedSecret := range secret.Data {
cert, err := cryptoutil.DecryptBytes(encryptedCert, key) // In some cases the secret might have empty data if the secrets were not present on disk
if err != nil { // when uploading. This can specially happen with external insecure etcd (no certs)
// If any of the decrypt operations fail do not return a partial result, if len(encryptedSecret) > 0 {
// return an empty result immediately cert, err := cryptoutil.DecryptBytes(encryptedSecret, key)
return map[string][]byte{}, err 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 return secretData, nil
} }