Skip to content

Commit

Permalink
Merge pull request kubernetes#70098 from fabriziopandini/kubeadm-grad…
Browse files Browse the repository at this point in the history
…uate-kubeconfig

Kubeadm graduate kubeconfig phase
  • Loading branch information
k8s-ci-robot authored Oct 30, 2018
2 parents 0a405f4 + 4f26d1d commit 739998f
Show file tree
Hide file tree
Showing 21 changed files with 265 additions and 539 deletions.
28 changes: 13 additions & 15 deletions cmd/kubeadm/app/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import (
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
controlplanephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
kubeletphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubelet"
markmasterphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/markmaster"
patchnodephase "k8s.io/kubernetes/cmd/kubeadm/app/phases/patchnode"
Expand Down Expand Up @@ -130,6 +129,7 @@ type initData struct {
ignorePreflightErrors sets.String
certificatesDir string
dryRunDir string
externalCA bool
client clientset.Interface
}

Expand All @@ -146,7 +146,7 @@ func NewCmdInit(out io.Writer) *cobra.Command {
kubeadmutil.CheckErr(err)

data := c.(initData)
fmt.Printf("[init] using Kubernetes version: %s\n", data.cfg.KubernetesVersion)
fmt.Printf("[init] Using Kubernetes version: %s\n", data.cfg.KubernetesVersion)

err = initRunner.Run()
kubeadmutil.CheckErr(err)
Expand All @@ -166,8 +166,9 @@ func NewCmdInit(out io.Writer) *cobra.Command {

// initialize the workflow runner with the list of phases
initRunner.AppendPhase(phases.NewPreflightMasterPhase())
initRunner.AppendPhase(phases.NewCertsPhase())
initRunner.AppendPhase(phases.NewKubeletStartPhase())
initRunner.AppendPhase(phases.NewCertsPhase())
initRunner.AppendPhase(phases.NewKubeConfigPhase())
// TODO: add other phases to the runner.

// sets the data builder function, that will be used by the runner
Expand Down Expand Up @@ -313,13 +314,17 @@ func newInitData(cmd *cobra.Command, options *initOptions) (initData, error) {
}
}

// Checks if an external CA is provided by the user.
externalCA, _ := certsphase.UsingExternalCA(cfg)

return initData{
cfg: cfg,
certificatesDir: cfg.CertificatesDir,
skipTokenPrint: options.skipTokenPrint,
dryRun: options.dryRun,
dryRunDir: dryRunDir,
ignorePreflightErrors: ignorePreflightErrorsSet,
externalCA: externalCA,
}, nil
}

Expand Down Expand Up @@ -380,6 +385,11 @@ func (d initData) KubeletDir() string {
return kubeadmconstants.KubeletRunDirectory
}

// ExternalCA returns true if an external CA is provided by the user.
func (d initData) ExternalCA() bool {
return d.externalCA
}

// Client returns a Kubernetes client to be used by kubeadm.
// This function is implemented as a singleton, thus avoiding to recreate the client when it is used by different phases.
// Important. This function must be called after the admin.conf kubeconfig file is created.
Expand Down Expand Up @@ -426,18 +436,6 @@ func runInit(i *initData, out io.Writer) error {

adminKubeConfigPath := filepath.Join(kubeConfigDir, kubeadmconstants.AdminKubeConfigFileName)

if res, _ := certsphase.UsingExternalCA(i.cfg); !res {

// PHASE 2: Generate kubeconfig files for the admin and the kubelet
glog.V(2).Infof("[init] generating kubeconfig files")
if err := kubeconfigphase.CreateInitKubeConfigFiles(kubeConfigDir, i.cfg); err != nil {
return err
}

} else {
fmt.Println("[externalca] the file 'ca.key' was not found, yet all other certificates are present. Using external CA mode - certificates or kubeconfig will not be generated")
}

if features.Enabled(i.cfg.FeatureGates, features.Auditing) {
// Setup the AuditPolicy (either it was passed in and exists or it wasn't passed in and generate a default policy)
if i.cfg.AuditPolicyConfiguration.Path != "" {
Expand Down
1 change: 0 additions & 1 deletion cmd/kubeadm/app/cmd/phases/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/v1beta1:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
Expand Down
100 changes: 64 additions & 36 deletions cmd/kubeadm/app/cmd/phases/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (

"github.com/pkg/errors"
"github.com/spf13/cobra"

kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
Expand All @@ -36,23 +35,6 @@ import (
)

var (
allCertsLongDesc = normalizer.LongDesc(`
Generates a self-signed CA to provision identities for each component in the cluster (including nodes)
and client certificates to be used by various components.
If a given certificate and private key pair both exist, kubeadm skips the generation step and
existing files will be used.
` + cmdutil.AlphaDisclaimer)

allCertsExample = normalizer.Examples(`
# Creates all PKI assets necessary to establish the control plane,
# functionally equivalent to what generated by kubeadm init.
kubeadm alpha phase certs all
# Creates all PKI assets using options read from a configuration file.
kubeadm alpha phase certs all --config masterconfiguration.yaml
`)

saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the private key for signing service account tokens along with its public key, and saves them into
%s and %s files.
Expand All @@ -71,6 +53,7 @@ var (
// (and thus with different runtime data struct, all of them requested to be compliant to this interface)
type certsData interface {
Cfg() *kubeadmapi.InitConfiguration
ExternalCA() bool
CertificateDir() string
CertificateWriteDir() string
}
Expand All @@ -80,7 +63,8 @@ func NewCertsPhase() workflow.Phase {
return workflow.Phase{
Name: "certs",
Short: "Certificate generation",
Phases: getCertsSubPhases(),
Phases: newCertSubPhases(),
Run: runCerts,
}
}

Expand All @@ -102,8 +86,8 @@ func getCertsSubCommands() []*cobra.Command {
return []*cobra.Command{certscmdphase.NewCmdCertsRenewal()}
}

// getCertsSubPhases returns sub phases for certs phase
func getCertsSubPhases() []workflow.Phase {
// newCertSubPhases returns sub phases for certs phase
func newCertSubPhases() []workflow.Phase {
subPhases := []workflow.Phase{}

certTree, _ := certsphase.GetDefaultCertList().AsMap().CertTree()
Expand All @@ -116,8 +100,6 @@ func getCertsSubPhases() []workflow.Phase {
certPhase := newCertSubPhase(cert, runCertPhase(cert, ca))
subPhases = append(subPhases, certPhase)
}

subPhases = append(subPhases, caPhase)
}

// SA creates the private/public key pair, which doesn't use x509 at all
Expand All @@ -133,19 +115,6 @@ func getCertsSubPhases() []workflow.Phase {
return subPhases
}

func runCertsSa(c workflow.RunData) error {
data, ok := c.(certsData)
if !ok {
return errors.New("certs phase invoked with an invalid data struct")
}

cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()

return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(cfg)
}

func newCertSubPhase(certSpec *certsphase.KubeadmCert, run func(c workflow.RunData) error) workflow.Phase {
phase := workflow.Phase{
Name: certSpec.Name,
Expand Down Expand Up @@ -195,17 +164,62 @@ func getSANDescription(certSpec *certsphase.KubeadmCert) string {
return fmt.Sprintf("\n\nDefault SANs are %s", strings.Join(sans, ", "))
}

func runCertsSa(c workflow.RunData) error {
data, ok := c.(certsData)
if !ok {
return errors.New("certs phase invoked with an invalid data struct")
}

// if external CA mode, skip service account key generation
if data.ExternalCA() {
fmt.Printf("[certs] External CA mode: Using existing sa keys\n")
return nil
}

// if dryrunning, write certificates to a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()

// create the new service account key (or use existing)
return certsphase.CreateServiceAccountKeyAndPublicKeyFiles(cfg)
}

func runCerts(c workflow.RunData) error {
data, ok := c.(certsData)
if !ok {
return errors.New("certs phase invoked with an invalid data struct")
}

fmt.Printf("[certs] Using certificateDir folder %q\n", data.CertificateWriteDir())
return nil
}

func runCAPhase(ca *certsphase.KubeadmCert) func(c workflow.RunData) error {
return func(c workflow.RunData) error {
data, ok := c.(certsData)
if !ok {
return errors.New("certs phase invoked with an invalid data struct")
}

// if external CA mode, skips certificate authority generation
if data.ExternalCA() {
fmt.Printf("[certs] External CA mode: Using existing %s certificate authority\n", ca.BaseName)
return nil
}

// if using external etcd, skips etcd certificate authority generation
if data.Cfg().Etcd.External != nil && ca.Name == "etcd-ca" {
fmt.Printf("[certs] External etcd mode: Skipping %s certificate authority generation\n", ca.BaseName)
return nil
}

// if dryrunning, write certificates authority to a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()

// create the new certificate authority (or use existing)
return certsphase.CreateCACertAndKeyFiles(ca, cfg)
}
}
Expand All @@ -217,10 +231,24 @@ func runCertPhase(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert)
return errors.New("certs phase invoked with an invalid data struct")
}

// if external CA mode, skip certificate generation
if data.ExternalCA() {
fmt.Printf("[certs] External CA mode: Using existing %s certificate\n", cert.BaseName)
return nil
}

// if using external etcd, skips etcd certificates generation
if data.Cfg().Etcd.External != nil && cert.CAName == "etcd-ca" {
fmt.Printf("[certs] External etcd mode: Skipping %s certificate authority generation\n", cert.BaseName)
return nil
}

// if dryrunning, write certificates to a temporary folder (and defer restore to the path originally specified by the user)
cfg := data.Cfg()
cfg.CertificatesDir = data.CertificateWriteDir()
defer func() { cfg.CertificatesDir = data.CertificateDir() }()

// create the new certificate (or use existing)
return certsphase.CreateCertAndKeyFilesWithCA(cert, caCert, cfg)
}
}
Loading

0 comments on commit 739998f

Please sign in to comment.