Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add certificate-key to kubeadm upload-certs phase, and improve init output #74671

Merged
merged 1 commit into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 50 additions & 37 deletions cmd/kubeadm/app/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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.",
)
}

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
Expand Down
3 changes: 3 additions & 0 deletions cmd/kubeadm/app/cmd/options/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
1 change: 1 addition & 0 deletions cmd/kubeadm/app/cmd/phases/init/uploadcerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func NewUploadCertsPhase() workflow.Phase {
InheritFlags: []string{
options.CfgPath,
options.UploadCerts,
options.CertificateKey,
yagonobre marked this conversation as resolved.
Show resolved Hide resolved
},
}
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/kubeadm/app/cmd/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
14 changes: 12 additions & 2 deletions cmd/kubeadm/app/cmd/util/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -81,6 +88,9 @@ func GetJoinCommand(kubeConfigFile, token, key string, skipTokenPrint, uploadCer
if skipTokenPrint {
ctx["Token"] = template.HTML("<value withheld>")
}
if skipCertificateKeyPrint {
ctx["CertificateKey"] = template.HTML("<value withheld>")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oddly enough, we use html/template here. This might cause problems when we try to feed a template with non-alphanumeric characters (< is turned into &lt;, etc.).
But anyway, this again is out of the scope of this PR.

}

var out bytes.Buffer
err = joinCommandTemplate.Execute(&out, ctx)
Expand Down