From d2212b840d95a355a557648ddeca2f219b99fa85 Mon Sep 17 00:00:00 2001 From: "bo.jiang" Date: Thu, 28 May 2026 12:43:17 +0800 Subject: [PATCH] kubeadm: fix dry-run CA copy paths in init certs Signed-off-by: bo.jiang --- cmd/kubeadm/app/cmd/phases/init/certs.go | 14 +++-- cmd/kubeadm/app/cmd/phases/init/certs_test.go | 55 +++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/cmd/kubeadm/app/cmd/phases/init/certs.go b/cmd/kubeadm/app/cmd/phases/init/certs.go index 5d1df7453f0..84280e52d9e 100644 --- a/cmd/kubeadm/app/cmd/phases/init/certs.go +++ b/cmd/kubeadm/app/cmd/phases/init/certs.go @@ -18,6 +18,7 @@ package phases import ( "fmt" + "os" "path/filepath" "strings" @@ -216,20 +217,25 @@ func runCAPhase(ca *certsphase.KubeadmCert) func(c workflow.RunData) error { if cert, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), ca.BaseName); err == nil { certsphase.CheckCertificatePeriodValidity(ca.BaseName, cert) + srcCertPath, srcKeyPath := pkiutil.PathsForCertAndKey(data.CertificateDir(), ca.BaseName) + dryRunCertPath, dryRunKeyPath := pkiutil.PathsForCertAndKey(data.CertificateWriteDir(), ca.BaseName) // If CA Cert existed while dryrun, copy CA Cert to dryrun dir for later use if data.DryRun() { - err := kubeadmutil.CopyFile(filepath.Join(data.CertificateDir(), kubeadmconstants.CACertName), filepath.Join(data.CertificateWriteDir(), kubeadmconstants.CACertName)) + if err := os.MkdirAll(filepath.Dir(dryRunCertPath), os.FileMode(0700)); err != nil { + return errors.Wrapf(err, "failed to create directory %s", filepath.Dir(dryRunCertPath)) + } + err := kubeadmutil.CopyFile(srcCertPath, dryRunCertPath) if err != nil { - return errors.Wrapf(err, "could not copy %s to dry run directory %s", kubeadmconstants.CACertName, data.CertificateWriteDir()) + return errors.Wrapf(err, "could not copy %s to dry run directory %s", fmt.Sprintf("%s.crt", ca.BaseName), data.CertificateWriteDir()) } } if _, err := pkiutil.TryLoadKeyFromDisk(data.CertificateDir(), ca.BaseName); err == nil { // If CA Key existed while dryrun, copy CA Key to dryrun dir for later use if data.DryRun() { - err := kubeadmutil.CopyFile(filepath.Join(data.CertificateDir(), kubeadmconstants.CAKeyName), filepath.Join(data.CertificateWriteDir(), kubeadmconstants.CAKeyName)) + err := kubeadmutil.CopyFile(srcKeyPath, dryRunKeyPath) if err != nil { - return errors.Wrapf(err, "could not copy %s to dry run directory %s", kubeadmconstants.CAKeyName, data.CertificateWriteDir()) + return errors.Wrapf(err, "could not copy %s to dry run directory %s", fmt.Sprintf("%s.key", ca.BaseName), data.CertificateWriteDir()) } } fmt.Printf("[certs] Using existing %s certificate authority\n", ca.BaseName) diff --git a/cmd/kubeadm/app/cmd/phases/init/certs_test.go b/cmd/kubeadm/app/cmd/phases/init/certs_test.go index 7ee76b6459c..fb8d3a97dc7 100644 --- a/cmd/kubeadm/app/cmd/phases/init/certs_test.go +++ b/cmd/kubeadm/app/cmd/phases/init/certs_test.go @@ -17,13 +17,17 @@ limitations under the License. package phases import ( + "os" + "path/filepath" "testing" "github.com/spf13/cobra" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" + certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" certstestutil "k8s.io/kubernetes/cmd/kubeadm/app/util/certs" + "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil" pkiutiltesting "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil/testing" testutil "k8s.io/kubernetes/cmd/kubeadm/test" ) @@ -33,10 +37,19 @@ type testCertsData struct { cfg *kubeadmapi.InitConfiguration } +type testDryRunCertsData struct { + testCertsData + certificateDir string + certificateWriteDir string +} + func (t *testCertsData) Cfg() *kubeadmapi.InitConfiguration { return t.cfg } func (t *testCertsData) ExternalCA() bool { return false } func (t *testCertsData) CertificateDir() string { return t.cfg.CertificatesDir } func (t *testCertsData) CertificateWriteDir() string { return t.cfg.CertificatesDir } +func (t *testDryRunCertsData) DryRun() bool { return true } +func (t *testDryRunCertsData) CertificateDir() string { return t.certificateDir } +func (t *testDryRunCertsData) CertificateWriteDir() string { return t.certificateWriteDir } func TestCreateSparseCerts(t *testing.T) { for _, test := range certstestutil.GetSparseCertTestCases(t) { @@ -63,3 +76,45 @@ func TestCreateSparseCerts(t *testing.T) { }) } } + +func TestRunCAPhaseCopiesExistingCAFilesToDryRunDir(t *testing.T) { + for _, ca := range []*certsphase.KubeadmCert{ + certsphase.KubeadmCertRootCA(), + certsphase.KubeadmCertFrontProxyCA(), + certsphase.KubeadmCertEtcdCA(), + } { + t.Run(ca.Name, func(t *testing.T) { + pkiutiltesting.Reset() + + sourceDir := t.TempDir() + writeDir := t.TempDir() + caCert, caKey := certstestutil.SetupCertificateAuthority(t) + certPath, _ := pkiutil.PathsForCertAndKey(sourceDir, ca.BaseName) + if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0700)); err != nil { + t.Fatalf("failed to create source directory for %s: %v", ca.BaseName, err) + } + if err := pkiutil.WriteCertAndKey(sourceDir, ca.BaseName, caCert, caKey); err != nil { + t.Fatalf("failed to write source CA files for %s: %v", ca.BaseName, err) + } + + cfg := testutil.GetDefaultInternalConfig(t) + cfg.CertificatesDir = sourceDir + data := &testDryRunCertsData{ + testCertsData: testCertsData{cfg: cfg}, + certificateDir: sourceDir, + certificateWriteDir: writeDir, + } + + if err := runCAPhase(ca)(data); err != nil { + t.Fatalf("runCAPhase(%s) returned error: %v", ca.Name, err) + } + + if _, err := pkiutil.TryLoadCertFromDisk(writeDir, ca.BaseName); err != nil { + t.Fatalf("expected copied cert for %s in dry-run dir: %v", ca.BaseName, err) + } + if _, err := pkiutil.TryLoadKeyFromDisk(writeDir, ca.BaseName); err != nil { + t.Fatalf("expected copied key for %s in dry-run dir: %v", ca.BaseName, err) + } + }) + } +}