From b1936853c47379046b9ec1a0344932ab5ffb4b95 Mon Sep 17 00:00:00 2001 From: Yago Nobre Date: Wed, 27 Feb 2019 15:02:54 -0300 Subject: [PATCH] Add certificate-key to kubeadm init upload-certs phase, and improve init output --- cmd/kubeadm/app/cmd/init.go | 87 +++++++++++-------- cmd/kubeadm/app/cmd/options/constant.go | 3 + .../app/cmd/phases/init/uploadcerts.go | 1 + cmd/kubeadm/app/cmd/token.go | 3 +- cmd/kubeadm/app/cmd/util/join.go | 14 ++- 5 files changed, 68 insertions(+), 40 deletions(-) diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 8261ca3e27d41..85c5eec165590 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -75,16 +75,18 @@ var ( // Please note that this structure includes the public kubeadm config API, but only a subset of the options // supported by this api will be exposed as a flag. type initOptions struct { - cfgPath string - skipTokenPrint bool - dryRun bool - kubeconfigDir string - kubeconfigPath string - featureGatesString string - ignorePreflightErrors []string - bto *options.BootstrapTokenOptions - externalcfg *kubeadmapiv1beta1.InitConfiguration - uploadCerts bool + cfgPath string + skipTokenPrint bool + dryRun bool + kubeconfigDir string + kubeconfigPath string + featureGatesString string + ignorePreflightErrors []string + bto *options.BootstrapTokenOptions + externalcfg *kubeadmapiv1beta1.InitConfiguration + uploadCerts bool + certificateKey string + skipCertificateKeyPrint bool } // compile-time assert that the local data object satisfies the phases data interface. @@ -93,20 +95,21 @@ var _ phases.InitData = &initData{} // initData defines all the runtime information used when running the kubeadm init worklow; // 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.String - certificatesDir string - dryRunDir string - externalCA bool - client clientset.Interface - waiter apiclient.Waiter - outputWriter io.Writer - uploadCerts bool - certificateKey string + cfg *kubeadmapi.InitConfiguration + skipTokenPrint bool + dryRun bool + kubeconfigDir string + kubeconfigPath string + ignorePreflightErrors sets.String + certificatesDir string + dryRunDir string + externalCA bool + client clientset.Interface + waiter apiclient.Waiter + outputWriter io.Writer + uploadCerts bool + certificateKey string + skipCertificateKeyPrint bool } // NewCmdInit returns "kubeadm init" command. @@ -241,7 +244,15 @@ func AddInitOtherFlags(flagSet *flag.FlagSet, initOptions *initOptions) { ) flagSet.BoolVar( &initOptions.uploadCerts, options.UploadCerts, initOptions.uploadCerts, - "Upload certfificates to kubeadm-certs secret.", + "Upload control-plane certificates to the kubeadm-certs Secret.", + ) + flagSet.StringVar( + &initOptions.certificateKey, options.CertificateKey, "", + "Key used to encrypt the control-plane certificates in the kubeadm-certs Secret.", + ) + flagSet.BoolVar( + &initOptions.skipCertificateKeyPrint, options.SkipCertificateKeyPrint, initOptions.skipCertificateKeyPrint, + "Don't print the key used to encrypt the control-plane certificates.", ) } @@ -337,17 +348,19 @@ func newInitData(cmd *cobra.Command, args []string, options *initOptions, out io } return &initData{ - cfg: cfg, - certificatesDir: cfg.CertificatesDir, - skipTokenPrint: options.skipTokenPrint, - dryRun: options.dryRun, - dryRunDir: dryRunDir, - kubeconfigDir: options.kubeconfigDir, - kubeconfigPath: options.kubeconfigPath, - ignorePreflightErrors: ignorePreflightErrorsSet, - externalCA: externalCA, - outputWriter: out, - uploadCerts: options.uploadCerts, + cfg: cfg, + certificatesDir: cfg.CertificatesDir, + skipTokenPrint: options.skipTokenPrint, + dryRun: options.dryRun, + dryRunDir: dryRunDir, + kubeconfigDir: options.kubeconfigDir, + kubeconfigPath: options.kubeconfigPath, + ignorePreflightErrors: ignorePreflightErrorsSet, + externalCA: externalCA, + outputWriter: out, + uploadCerts: options.uploadCerts, + certificateKey: options.certificateKey, + skipCertificateKeyPrint: options.skipCertificateKeyPrint, }, nil } @@ -472,7 +485,7 @@ func (d *initData) Tokens() []string { } func printJoinCommand(out io.Writer, adminKubeConfigPath, token string, i *initData) error { - joinCommand, err := cmdutil.GetJoinCommand(adminKubeConfigPath, token, i.certificateKey, i.skipTokenPrint, i.uploadCerts) + joinCommand, err := cmdutil.GetJoinCommand(adminKubeConfigPath, token, i.certificateKey, i.skipTokenPrint, i.uploadCerts, i.skipCertificateKeyPrint) if err != nil { return err } diff --git a/cmd/kubeadm/app/cmd/options/constant.go b/cmd/kubeadm/app/cmd/options/constant.go index f89b6dfab00e2..251cd20133403 100644 --- a/cmd/kubeadm/app/cmd/options/constant.go +++ b/cmd/kubeadm/app/cmd/options/constant.go @@ -124,4 +124,7 @@ const ( // CertificateKey flag sets the key used to encrypt and decrypt certificate secrets CertificateKey = "certificate-key" + + // SkipCertificateKeyPrint flag instruct kubeadm to skip printing certificate key used to encrypt certs by 'kubeadm init'. + SkipCertificateKeyPrint = "skip-certificate-key-print" ) diff --git a/cmd/kubeadm/app/cmd/phases/init/uploadcerts.go b/cmd/kubeadm/app/cmd/phases/init/uploadcerts.go index dac07a18ad514..bd24cbcff1cff 100644 --- a/cmd/kubeadm/app/cmd/phases/init/uploadcerts.go +++ b/cmd/kubeadm/app/cmd/phases/init/uploadcerts.go @@ -39,6 +39,7 @@ func NewUploadCertsPhase() workflow.Phase { InheritFlags: []string{ options.CfgPath, options.UploadCerts, + options.CertificateKey, }, } } diff --git a/cmd/kubeadm/app/cmd/token.go b/cmd/kubeadm/app/cmd/token.go index 6745ff3f5d9de..881f3cb7f540c 100644 --- a/cmd/kubeadm/app/cmd/token.go +++ b/cmd/kubeadm/app/cmd/token.go @@ -231,7 +231,8 @@ func RunCreateToken(out io.Writer, client clientset.Interface, cfgPath string, c key := "" skipTokenPrint := false uploadCerts := false - joinCommand, err := cmdutil.GetJoinCommand(kubeConfigFile, internalcfg.BootstrapTokens[0].Token.String(), key, skipTokenPrint, uploadCerts) + skipCertificateKeyPrint := false + joinCommand, err := cmdutil.GetJoinCommand(kubeConfigFile, internalcfg.BootstrapTokens[0].Token.String(), key, skipTokenPrint, uploadCerts, skipCertificateKeyPrint) if err != nil { return errors.Wrap(err, "failed to get join command") } diff --git a/cmd/kubeadm/app/cmd/util/join.go b/cmd/kubeadm/app/cmd/util/join.go index 1229ab64f0ced..a4f73d25d8362 100644 --- a/cmd/kubeadm/app/cmd/util/join.go +++ b/cmd/kubeadm/app/cmd/util/join.go @@ -30,12 +30,19 @@ import ( ) var joinCommandTemplate = template.Must(template.New("join").Parse(`` + - `kubeadm join {{.ControlPlaneHostPort}} --token {{.Token}}{{range $h := .CAPubKeyPins}} --discovery-token-ca-cert-hash {{$h}}{{end}}{{if .UploadCerts}} --certificate-key {{.CertificateKey}}{{end}}`, + `{{if .UploadCerts}}You can now join any number of control-plane node running the following command on each as a root:{{else}}You can now join any number of control-plane node by copying the required certificate authorities on each node and then running the following as root:{{end}} + kubeadm join {{.ControlPlaneHostPort}} --token {{.Token}}{{range $h := .CAPubKeyPins}} --discovery-token-ca-cert-hash {{$h}}{{end}} --experimental-control-plane {{if .UploadCerts}}--certificate-key {{.CertificateKey}} + + Please note that the certificate-key gives access to cluster sensitive data, keep it secret! + As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use kubeadm init phase upload-certs to reload certs afterward.{{end}} + + Then you can join any number of worker nodes by running the following on each as root: + kubeadm join {{.ControlPlaneHostPort}} --token {{.Token}}{{range $h := .CAPubKeyPins}} --discovery-token-ca-cert-hash {{$h}}{{end}}`, )) // GetJoinCommand returns the kubeadm join command for a given token and // and Kubernetes cluster (the current cluster in the kubeconfig file) -func GetJoinCommand(kubeConfigFile, token, key string, skipTokenPrint, uploadCerts bool) (string, error) { +func GetJoinCommand(kubeConfigFile, token, key string, skipTokenPrint, uploadCerts, skipCertificateKeyPrint bool) (string, error) { // load the kubeconfig file to get the CA certificate and endpoint config, err := clientcmd.LoadFromFile(kubeConfigFile) if err != nil { @@ -81,6 +88,9 @@ func GetJoinCommand(kubeConfigFile, token, key string, skipTokenPrint, uploadCer if skipTokenPrint { ctx["Token"] = template.HTML("") } + if skipCertificateKeyPrint { + ctx["CertificateKey"] = template.HTML("") + } var out bytes.Buffer err = joinCommandTemplate.Execute(&out, ctx)