kubeadm: avoid requiring a CA key during kubeconfig expiration checks

When the "kubeadm certs check-expiration" command is used and
if the ca.key is not present, regular on disk certificate reads
pass fine, but fail for kubeconfig files. The reason for the
failure is that reading of kubeconfig files currently
requires reading both the CA key and cert from disk. Reading the CA
is done to ensure that the CA cert in the kubeconfig is not out of date
during renewal.

Instead of requiring both a CA key and cert to be read, only read
the CA cert from disk, as only the cert is needed for kubeconfig files.

This fixes printing the cert expiration table even if the ca.key
is missing on a host (i.e. the CA is considered external).
This commit is contained in:
Lubomir I. Ivanov 2021-12-07 20:46:05 +02:00
parent 0153febd9f
commit 847b2e1085
2 changed files with 12 additions and 4 deletions

View File

@ -29,7 +29,6 @@ import (
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
"k8s.io/client-go/util/keyutil" "k8s.io/client-go/util/keyutil"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil" pkiutil "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
) )
@ -141,11 +140,15 @@ func (rw *kubeConfigReadWriter) Read() (*x509.Certificate, error) {
// For local CA renewal, the local CA on disk could have changed, thus a reload is needed. // For local CA renewal, the local CA on disk could have changed, thus a reload is needed.
// For CSR renewal we assume the same CA on disk is mounted for usage with KCM's // For CSR renewal we assume the same CA on disk is mounted for usage with KCM's
// '--cluster-signing-cert-file' flag. // '--cluster-signing-cert-file' flag.
caCert, _, err := certsphase.LoadCertificateAuthority(rw.certificateDir, rw.baseName) certificatePath, _ := pkiutil.PathsForCertAndKey(rw.certificateDir, rw.baseName)
caCerts, err := certutil.CertsFromFile(certificatePath)
if err != nil { if err != nil {
return nil, err return nil, errors.Wrapf(err, "failed to load existing certificate %s", rw.baseName)
} }
rw.caCert = caCert if len(caCerts) != 1 {
return nil, errors.Errorf("wanted exactly one certificate, got %d", len(caCerts))
}
rw.caCert = caCerts[0]
// get current context // get current context
if _, ok := kubeConfig.Contexts[kubeConfig.CurrentContext]; !ok { if _, ok := kubeConfig.Contexts[kubeConfig.CurrentContext]; !ok {

View File

@ -127,6 +127,11 @@ func TestKubeconfigReadWriter(t *testing.T) {
t.Fatalf("couldn't write new embedded certificate: %v", err) t.Fatalf("couldn't write new embedded certificate: %v", err)
} }
// Make sure that CA key is not present during Read() as it is not needed.
// This covers testing when the CA is external and not present on the host.
_, caKeyPath := pkiutil.PathsForCertAndKey(dirPKI, caName)
os.Remove(caKeyPath)
// Reads back the new certificate embedded in a kubeconfig writer // Reads back the new certificate embedded in a kubeconfig writer
readCert, err = kubeconfigReadWriter.Read() readCert, err = kubeconfigReadWriter.Read()
if err != nil { if err != nil {