From 837090135f885964ba5b83914091b77ed2d5f1d2 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 19 Oct 2023 20:41:23 +0300 Subject: [PATCH] kubeadm: make super-admin.conf changes to app/cmd - Update unit tests in certs_test.go related to the "renew" CLI command. - In /init, (d *initData) Client(), make sure that the new logic for bootstrapping an "admin.conf" user is performed, by calling EnsureAdminClusterRoleBinding() from the phases backend. Add a "adminKubeConfigBootstrapped" flag that helps call this logic only once per "kubeadm init" binary execution. - In /phases/init include a new subphase for generating the "super-admin.conf" file. - In /phases/reset make sure the file "super-admin.conf" is cleaned if present. Update unit tests. --- cmd/kubeadm/app/cmd/certs_test.go | 8 +++ cmd/kubeadm/app/cmd/init.go | 49 ++++++++++++------- cmd/kubeadm/app/cmd/phases/init/kubeconfig.go | 6 +++ .../app/cmd/phases/reset/cleanupnode.go | 1 + .../app/cmd/phases/reset/cleanupnode_test.go | 1 + 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/cmd/kubeadm/app/cmd/certs_test.go b/cmd/kubeadm/app/cmd/certs_test.go index 40f6770b52d..8dff90ad8e2 100644 --- a/cmd/kubeadm/app/cmd/certs_test.go +++ b/cmd/kubeadm/app/cmd/certs_test.go @@ -134,6 +134,7 @@ func TestRunRenewCommands(t *testing.T) { // Generate all the kubeconfig files with embedded certs for _, kubeConfig := range []string{ kubeadmconstants.AdminKubeConfigFileName, + kubeadmconstants.SuperAdminKubeConfigFileName, kubeadmconstants.SchedulerKubeConfigFileName, kubeadmconstants.ControllerManagerKubeConfigFileName, } { @@ -162,6 +163,7 @@ func TestRunRenewCommands(t *testing.T) { }, KubeconfigFiles: []string{ kubeadmconstants.AdminKubeConfigFileName, + kubeadmconstants.SuperAdminKubeConfigFileName, kubeadmconstants.SchedulerKubeConfigFileName, kubeadmconstants.ControllerManagerKubeConfigFileName, }, @@ -214,6 +216,12 @@ func TestRunRenewCommands(t *testing.T) { kubeadmconstants.AdminKubeConfigFileName, }, }, + { + command: "super-admin.conf", + KubeconfigFiles: []string{ + kubeadmconstants.SuperAdminKubeConfigFileName, + }, + }, { command: "scheduler.conf", KubeconfigFiles: []string{ diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 156b7a63ad7..f57acf12d8c 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -72,20 +72,21 @@ var _ phases.InitData = &initData{} // initData defines all the runtime information used when running the kubeadm init workflow; // this data is shared across all the phases that are included in the workflow. type initData struct { - cfg *kubeadmapi.InitConfiguration - skipTokenPrint bool - dryRun bool - kubeconfigDir string - kubeconfigPath string - ignorePreflightErrors sets.Set[string] - certificatesDir string - dryRunDir string - externalCA bool - client clientset.Interface - outputWriter io.Writer - uploadCerts bool - skipCertificateKeyPrint bool - patchesDir string + cfg *kubeadmapi.InitConfiguration + skipTokenPrint bool + dryRun bool + kubeconfigDir string + kubeconfigPath string + ignorePreflightErrors sets.Set[string] + certificatesDir string + dryRunDir string + externalCA bool + client clientset.Interface + outputWriter io.Writer + uploadCerts bool + skipCertificateKeyPrint bool + patchesDir string + adminKubeConfigBootstrapped bool } // newCmdInit returns "kubeadm init" command. @@ -495,12 +496,22 @@ func (d *initData) Client() (clientset.Interface, error) { // If we're dry-running, we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests dryRunGetter := apiclient.NewInitDryRunGetter(d.cfg.NodeRegistration.Name, svcSubnetCIDR.String()) d.client = apiclient.NewDryRunClient(dryRunGetter, os.Stdout) - } else { - // If we're acting for real, we should create a connection to the API server and wait for it to come up + } else { // Use a real client var err error - d.client, err = kubeconfigutil.ClientSetFromFile(d.KubeConfigPath()) - if err != nil { - return nil, err + if !d.adminKubeConfigBootstrapped { + // Call EnsureAdminClusterRoleBinding() to obtain a working client from admin.conf. + d.client, err = kubeconfigphase.EnsureAdminClusterRoleBinding(kubeadmconstants.KubernetesDir, nil) + if err != nil { + return nil, errors.Wrapf(err, "could not bootstrap the admin user in file %s", kubeadmconstants.AdminKubeConfigFileName) + } + d.adminKubeConfigBootstrapped = true + } else { + // In case adminKubeConfigBootstrapped is already set just return a client from the default + // kubeconfig location. + d.client, err = kubeconfigutil.ClientSetFromFile(d.KubeConfigPath()) + if err != nil { + return nil, err + } } } } diff --git a/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go b/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go index a5cd4bfb2fe..77432a13354 100644 --- a/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go +++ b/cmd/kubeadm/app/cmd/phases/init/kubeconfig.go @@ -41,6 +41,11 @@ var ( short: "Generate a kubeconfig file for the admin to use and for kubeadm itself", long: "Generate the kubeconfig file for the admin and for kubeadm itself, and save it to %s file.", }, + kubeadmconstants.SuperAdminKubeConfigFileName: { + name: "super-admin", + short: "Generate a kubeconfig file for the super-admin", + long: "Generate a kubeconfig file for the super-admin, and save it to %s file.", + }, kubeadmconstants.KubeletKubeConfigFileName: { name: "kubelet", short: "Generate a kubeconfig file for the kubelet to use *only* for cluster bootstrapping purposes", @@ -77,6 +82,7 @@ func NewKubeConfigPhase() workflow.Phase { RunAllSiblings: true, }, NewKubeConfigFilePhase(kubeadmconstants.AdminKubeConfigFileName), + NewKubeConfigFilePhase(kubeadmconstants.SuperAdminKubeConfigFileName), NewKubeConfigFilePhase(kubeadmconstants.KubeletKubeConfigFileName), NewKubeConfigFilePhase(kubeadmconstants.ControllerManagerKubeConfigFileName), NewKubeConfigFilePhase(kubeadmconstants.SchedulerKubeConfigFileName), diff --git a/cmd/kubeadm/app/cmd/phases/reset/cleanupnode.go b/cmd/kubeadm/app/cmd/phases/reset/cleanupnode.go index 671cda62df1..8a78509b951 100644 --- a/cmd/kubeadm/app/cmd/phases/reset/cleanupnode.go +++ b/cmd/kubeadm/app/cmd/phases/reset/cleanupnode.go @@ -169,6 +169,7 @@ func resetConfigDir(configPathDir string, dirsToClean []string, isDryRun bool) { filesToClean := []string{ filepath.Join(configPathDir, kubeadmconstants.AdminKubeConfigFileName), + filepath.Join(configPathDir, kubeadmconstants.SuperAdminKubeConfigFileName), filepath.Join(configPathDir, kubeadmconstants.KubeletKubeConfigFileName), filepath.Join(configPathDir, kubeadmconstants.KubeletBootstrapKubeConfigFileName), filepath.Join(configPathDir, kubeadmconstants.ControllerManagerKubeConfigFileName), diff --git a/cmd/kubeadm/app/cmd/phases/reset/cleanupnode_test.go b/cmd/kubeadm/app/cmd/phases/reset/cleanupnode_test.go index 7b6aff34082..de714cc8156 100644 --- a/cmd/kubeadm/app/cmd/phases/reset/cleanupnode_test.go +++ b/cmd/kubeadm/app/cmd/phases/reset/cleanupnode_test.go @@ -68,6 +68,7 @@ func TestConfigDirCleaner(t *testing.T) { "manifests/kube-apiserver.yaml", "pki/ca.pem", kubeadmconstants.AdminKubeConfigFileName, + kubeadmconstants.SuperAdminKubeConfigFileName, kubeadmconstants.KubeletKubeConfigFileName, }, verifyExists: []string{