Merge pull request #67605 from liztio/cert-list-2

Automatic merge from submit-queue (batch tested with PRs 67596, 67520, 67605). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Cert list 2

**What this PR does / why we need it**:

Continuation of #67208. Uses the newly created declarative list of certificates kubeadm requires for the certs phase and upgrade steps.


**Special notes for your reviewer**:

**Release note**:

```release-note

```
This commit is contained in:
Kubernetes Submit Queue 2018-08-20 15:03:02 -07:00 committed by GitHub
commit 6d76e35b39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 482 additions and 948 deletions

View File

@ -18,13 +18,13 @@ package phases
import ( import (
"fmt" "fmt"
"strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3" kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
@ -38,12 +38,12 @@ var (
Generates a self-signed CA to provision identities for each component in the cluster (including nodes) 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. 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 If a given certificate and private key pair both exist, kubeadm skips the generation step and
existing files will be used. existing files will be used.
` + cmdutil.AlphaDisclaimer) ` + cmdutil.AlphaDisclaimer)
allCertsExample = normalizer.Examples(` allCertsExample = normalizer.Examples(`
# Creates all PKI assets necessary to establish the control plane, # Creates all PKI assets necessary to establish the control plane,
# functionally equivalent to what generated by kubeadm init. # functionally equivalent to what generated by kubeadm init.
kubeadm alpha phase certs all kubeadm alpha phase certs all
@ -51,85 +51,17 @@ var (
kubeadm alpha phase certs all --config masterconfiguration.yaml kubeadm alpha phase certs all --config masterconfiguration.yaml
`) `)
caCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the self-signed kubernetes certificate authority and related key, and saves them into %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.CACertName, kubeadmconstants.CAKeyName)
apiServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the API server serving certificate and key and saves them into %s and %s files.
The certificate includes default subject alternative names and additional SANs provided by the user;
default SANs are: <node-name>, <apiserver-advertise-address>, kubernetes, kubernetes.default, kubernetes.default.svc,
kubernetes.default.svc.<service-dns-domain>, <internalAPIServerVirtualIP> (that is the .10 address in <service-cidr> address space).
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName)
apiServerKubeletCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the client certificate for the API server to connect to the kubelet securely and the respective key,
and saves them into %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName)
etcdCaCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the self-signed etcd certificate authority and related key and saves them into %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName)
etcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the etcd serving certificate and key and saves them into %s and %s files.
The certificate includes default subject alternative names and additional SANs provided by the user;
default SANs are: localhost, 127.0.0.1.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName)
etcdPeerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the etcd peer certificate and key and saves them into %s and %s files.
The certificate includes default subject alternative names and additional SANs provided by the user;
default SANs are: <node-name>, <apiserver-advertise-address>.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName)
etcdHealthcheckClientCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the client certificate for liveness probes to healthcheck etcd and the respective key,
and saves them into %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName)
apiServerEtcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the client certificate for the API server to connect to etcd securely and the respective key,
and saves them into %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName)
saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(` saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the private key for signing service account tokens along with its public key, and saves them into Generates the private key for signing service account tokens along with its public key, and saves them into
%s and %s files. %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used. If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName) `+cmdutil.AlphaDisclaimer), kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName)
frontProxyCaCertLongDesc = fmt.Sprintf(normalizer.LongDesc(` genericLongDesc = normalizer.LongDesc(`
Generates the front proxy CA certificate and key and saves them into %s and %s files. Generates the %[1]s, and saves them into %[2]s.cert and %[2]s.key files.%[3]s
If both files already exist, kubeadm skips the generation step and existing files will be used. If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName) ` + cmdutil.AlphaDisclaimer)
frontProxyClientCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the front proxy client certificate and key and saves them into %s and %s files.
If both files already exist, kubeadm skips the generation step and existing files will be used.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName)
) )
// NewCmdCerts returns main command for certs phase // NewCmdCerts returns main command for certs phase
@ -154,147 +86,146 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
kubeadmscheme.Scheme.Default(cfg) kubeadmscheme.Scheme.Default(cfg)
var cfgPath string var cfgPath string
var subCmds []*cobra.Command
subCmdProperties := []struct { // Special case commands
use string // All runs CreatePKIAssets, which isn't a particular certificate
short string allCmd := &cobra.Command{
long string Use: "all",
examples string Short: "Generates all PKI assets necessary to establish the control plane",
cmdFunc func(cfg *kubeadmapi.InitConfiguration) error Long: allCertsLongDesc,
}{ Example: allCertsExample,
{ Run: func(cmd *cobra.Command, args []string) {
use: "all", internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
short: "Generates all PKI assets necessary to establish the control plane", kubeadmutil.CheckErr(err)
long: allCertsLongDesc,
examples: allCertsExample, err = certsphase.CreatePKIAssets(internalcfg)
cmdFunc: certsphase.CreatePKIAssets, kubeadmutil.CheckErr(err)
},
{
use: "ca",
short: "Generates a self-signed kubernetes CA to provision identities for components of the cluster",
long: caCertLongDesc,
cmdFunc: certsphase.CreateCACertAndKeyFiles,
},
{
use: "apiserver",
short: "Generates an API server serving certificate and key",
long: apiServerCertLongDesc,
cmdFunc: certsphase.CreateAPIServerCertAndKeyFiles,
},
{
use: "apiserver-kubelet-client",
short: "Generates a client certificate for the API server to connect to the kubelets securely",
long: apiServerKubeletCertLongDesc,
cmdFunc: certsphase.CreateAPIServerKubeletClientCertAndKeyFiles,
},
{
use: "etcd-ca",
short: "Generates a self-signed CA to provision identities for etcd",
long: etcdCaCertLongDesc,
cmdFunc: certsphase.CreateEtcdCACertAndKeyFiles,
},
{
use: "etcd-server",
short: "Generates an etcd serving certificate and key",
long: etcdServerCertLongDesc,
cmdFunc: certsphase.CreateEtcdServerCertAndKeyFiles,
},
{
use: "etcd-peer",
short: "Generates an etcd peer certificate and key",
long: etcdPeerCertLongDesc,
cmdFunc: certsphase.CreateEtcdPeerCertAndKeyFiles,
},
{
use: "etcd-healthcheck-client",
short: "Generates a client certificate for liveness probes to healthcheck etcd",
long: etcdHealthcheckClientCertLongDesc,
cmdFunc: certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles,
},
{
use: "apiserver-etcd-client",
short: "Generates a client certificate for the API server to connect to etcd securely",
long: apiServerEtcdServerCertLongDesc,
cmdFunc: certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
},
{
use: "sa",
short: "Generates a private key for signing service account tokens along with its public key",
long: saKeyLongDesc,
cmdFunc: certsphase.CreateServiceAccountKeyAndPublicKeyFiles,
},
{
use: "front-proxy-ca",
short: "Generates a front proxy CA certificate and key for a Kubernetes cluster",
long: frontProxyCaCertLongDesc,
cmdFunc: certsphase.CreateFrontProxyCACertAndKeyFiles,
},
{
use: "front-proxy-client",
short: "Generates a front proxy CA client certificate and key for a Kubernetes cluster",
long: frontProxyClientCertLongDesc,
cmdFunc: certsphase.CreateFrontProxyClientCertAndKeyFiles,
}, },
} }
addFlags(allCmd, &cfgPath, cfg, true)
for _, properties := range subCmdProperties { // SA creates the private/public key pair, which doesn't use x509 at all
// Creates the UX Command saCmd := &cobra.Command{
cmd := &cobra.Command{ Use: "sa",
Use: properties.use, Short: "Generates a private key for signing service account tokens along with its public key",
Short: properties.short, Long: saKeyLongDesc,
Long: properties.long, Run: func(cmd *cobra.Command, args []string) {
Example: properties.examples, internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
Run: runCmdFunc(properties.cmdFunc, &cfgPath, cfg, defaultKubernetesVersion), kubeadmutil.CheckErr(err)
}
// Add flags to the command err = certsphase.CreateServiceAccountKeyAndPublicKeyFiles(internalcfg)
cmd.Flags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental") kubeadmutil.CheckErr(err)
cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where to save the certificates") },
if properties.use == "all" || properties.use == "apiserver" { }
cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, "Alternative domain for services, to use for the API server serving cert") addFlags(saCmd, &cfgPath, cfg, false)
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "Alternative range of IP address for service VIPs, from which derives the internal API server VIP that will be added to the API Server serving cert")
cmd.Flags().StringSliceVar(&cfg.APIServerCertSANs, "apiserver-cert-extra-sans", []string{}, "Optional extra altnames to use for the API server serving cert. Can be both IP addresses and DNS names")
cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address the API server is accessible on, to use for the API server serving cert")
}
subCmds = append(subCmds, cmd) subCmds := []*cobra.Command{allCmd, saCmd}
certTree, err := certsphase.GetDefaultCertList().AsMap().CertTree()
kubeadmutil.CheckErr(err)
for ca, certList := range certTree {
// Don't use pointers from for loops, they will be rewrittenb
caCmds := makeCommandsForCA(ca, certList, &cfgPath, cfg)
subCmds = append(subCmds, caCmds...)
} }
return subCmds return subCmds
} }
// runCmdFunc creates a cobra.Command Run function, by composing the call to the given cmdFunc with necessary additional steps (e.g preparation of input parameters) func makeCmd(certSpec *certsphase.KubeadmCert, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration) *cobra.Command {
func runCmdFunc(cmdFunc func(cfg *kubeadmapi.InitConfiguration) error, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration, defaultKubernetesVersion string) func(cmd *cobra.Command, args []string) { cmd := &cobra.Command{
Use: certSpec.Name,
Short: fmt.Sprintf("Generates the %s", certSpec.LongName),
Long: fmt.Sprintf(
genericLongDesc,
certSpec.LongName,
certSpec.BaseName,
getSANDescription(certSpec),
),
}
addFlags(cmd, cfgPath, cfg, certSpec.Name == "apiserver")
// Add flags to the command
return cmd
}
// the following statement build a closure that wraps a call to a cmdFunc, binding func getSANDescription(certSpec *certsphase.KubeadmCert) string {
// the function itself with the specific parameters of each sub command. //Defaulted config we will use to get SAN certs
// Please note that specific parameter should be passed as value, while other parameters - passed as reference - defaultConfig := &kubeadmapiv1alpha3.InitConfiguration{
// are shared between sub commands and gets access to current value e.g. flags value. API: kubeadmapiv1alpha3.API{
// GetAPIServerAltNames errors without an AdvertiseAddress; this is as good as any.
AdvertiseAddress: "127.0.0.1",
},
}
defaultInternalConfig := &kubeadmapi.InitConfiguration{}
return func(cmd *cobra.Command, args []string) { kubeadmscheme.Scheme.Default(defaultConfig)
if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil { kubeadmscheme.Scheme.Convert(defaultConfig, defaultInternalConfig, nil)
kubeadmutil.CheckErr(err)
certConfig, err := certSpec.GetConfig(defaultInternalConfig)
kubeadmutil.CheckErr(err)
if len(certConfig.AltNames.DNSNames) == 0 && len(certConfig.AltNames.IPs) == 0 {
return ""
}
// This mutates the certConfig, but we're throwing it after we construct the command anyway
sans := []string{}
for _, dnsName := range certConfig.AltNames.DNSNames {
if dnsName != "" {
sans = append(sans, dnsName)
} }
}
// This is used for unit testing only... for _, ip := range certConfig.AltNames.IPs {
// If we wouldn't set this to something, the code would dynamically look up the version from the internet sans = append(sans, ip.String())
// By setting this explicitly for tests workarounds that }
if defaultKubernetesVersion != "" { return fmt.Sprintf("\n\nDefault SANs are %s", strings.Join(sans, ", "))
cfg.KubernetesVersion = defaultKubernetesVersion }
} else {
// KubernetesVersion is not used, but we set it explicitly to avoid the lookup
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig
err := SetKubernetesVersion(nil, cfg)
kubeadmutil.CheckErr(err)
}
// This call returns the ready-to-use configuration based on the configuration file that might or might not exist and the default cfg populated by flags func addFlags(cmd *cobra.Command, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration, addAPIFlags bool) {
cmd.Flags().StringVar(cfgPath, "config", *cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental")
cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where to save the certificates")
if addAPIFlags {
cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, "Alternative domain for services, to use for the API server serving cert")
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "Alternative range of IP address for service VIPs, from which derives the internal API server VIP that will be added to the API Server serving cert")
cmd.Flags().StringSliceVar(&cfg.APIServerCertSANs, "apiserver-cert-extra-sans", []string{}, "Optional extra altnames to use for the API server serving cert. Can be both IP addresses and DNS names")
cmd.Flags().StringVar(&cfg.API.AdvertiseAddress, "apiserver-advertise-address", cfg.API.AdvertiseAddress, "The IP address the API server is accessible on, to use for the API server serving cert")
}
}
func makeCommandsForCA(ca *certsphase.KubeadmCert, certList []*certsphase.KubeadmCert, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration) []*cobra.Command {
subCmds := []*cobra.Command{}
caCmd := makeCmd(ca, cfgPath, cfg)
caCmd.Run = func(cmd *cobra.Command, args []string) {
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg) internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
// Execute the cmdFunc err = certsphase.CreateCACertAndKeyFiles(ca, internalcfg)
err = cmdFunc(internalcfg)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
} }
subCmds = append(subCmds, caCmd)
for _, cert := range certList {
certCmd := makeCommandForCert(cert, ca, cfgPath, cfg)
subCmds = append(subCmds, certCmd)
}
return subCmds
}
func makeCommandForCert(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration) *cobra.Command {
certCmd := makeCmd(cert, cfgPath, cfg)
certCmd.Run = func(cmd *cobra.Command, args []string) {
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg)
kubeadmutil.CheckErr(err)
err = certsphase.CreateCertAndKeyFilesWithCA(cert, caCert, internalcfg)
kubeadmutil.CheckErr(err)
}
return certCmd
} }

View File

@ -19,6 +19,7 @@ package phases
import ( import (
"fmt" "fmt"
"os" "os"
"strings"
"testing" "testing"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -146,18 +147,21 @@ func TestSubCmdCertsCreateFilesWithFlags(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
// Create temp folder for the test case t.Run(strings.Join(test.subCmds, ","), func(t *testing.T) {
tmpdir := testutil.SetupTempDir(t) // Create temp folder for the test case
defer os.RemoveAll(tmpdir) tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
// executes given sub commands // executes given sub commands
for _, subCmdName := range test.subCmds { for _, subCmdName := range test.subCmds {
certDirFlag := fmt.Sprintf("--cert-dir=%s", tmpdir) fmt.Printf("running command %q\n", subCmdName)
cmdtestutil.RunSubCommand(t, subCmds, subCmdName, certDirFlag) certDirFlag := fmt.Sprintf("--cert-dir=%s", tmpdir)
} cmdtestutil.RunSubCommand(t, subCmds, subCmdName, certDirFlag)
}
// verify expected files are there // verify expected files are there
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...) testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
})
} }
} }
@ -226,8 +230,12 @@ func TestSubCmdCertsCreateFilesWithConfigFile(t *testing.T) {
}, },
}, },
{ {
subCmds: []string{"ca", "apiserver", "apiserver-kubelet-client"}, subCmds: []string{"ca", "apiserver", "apiserver-kubelet-client"},
expectedFiles: []string{kubeadmconstants.CACertName, kubeadmconstants.CAKeyName, kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName, kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName}, expectedFiles: []string{
kubeadmconstants.CACertName, kubeadmconstants.CAKeyName,
kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName,
kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName,
},
}, },
{ {
subCmds: []string{"etcd-ca", "etcd-server", "etcd-peer", "etcd-healthcheck-client", "apiserver-etcd-client"}, subCmds: []string{"etcd-ca", "etcd-server", "etcd-peer", "etcd-healthcheck-client", "apiserver-etcd-client"},
@ -250,26 +258,28 @@ func TestSubCmdCertsCreateFilesWithConfigFile(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
// Create temp folder for the test case t.Run(strings.Join(test.subCmds, ","), func(t *testing.T) {
tmpdir := testutil.SetupTempDir(t) // Create temp folder for the test case
defer os.RemoveAll(tmpdir)
certdir := tmpdir tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
cfg := &kubeadmapi.InitConfiguration{ cfg := &kubeadmapi.InitConfiguration{
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
CertificatesDir: certdir, CertificatesDir: tmpdir,
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"}, NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
} }
configPath := testutil.SetupInitConfigurationFile(t, tmpdir, cfg) configPath := testutil.SetupInitConfigurationFile(t, tmpdir, cfg)
// executes given sub commands // executes given sub commands
for _, subCmdName := range test.subCmds { for _, subCmdName := range test.subCmds {
configFlag := fmt.Sprintf("--config=%s", configPath) t.Logf("running subcommand %q", subCmdName)
cmdtestutil.RunSubCommand(t, subCmds, subCmdName, configFlag) configFlag := fmt.Sprintf("--config=%s", configPath)
} cmdtestutil.RunSubCommand(t, subCmds, subCmdName, configFlag)
}
// verify expected files are there // verify expected files are there
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...) testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
})
} }
} }

View File

@ -32,6 +32,7 @@ type configMutatorsFunc func(*kubeadmapi.InitConfiguration, *certutil.Config) er
// KubeadmCert represents a certificate that Kubeadm will create to function properly. // KubeadmCert represents a certificate that Kubeadm will create to function properly.
type KubeadmCert struct { type KubeadmCert struct {
Name string Name string
LongName string
BaseName string BaseName string
CAName string CAName string
// Some attributes will depend on the InitConfiguration, only known at runtime. // Some attributes will depend on the InitConfiguration, only known at runtime.
@ -57,13 +58,14 @@ func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x50
if err != nil { if err != nil {
return fmt.Errorf("couldn't create %q certificate: %v", k.Name, err) return fmt.Errorf("couldn't create %q certificate: %v", k.Name, err)
} }
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, *cfg) cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, cfg)
if err != nil { if err != nil {
return err return err
} }
writeCertificateAuthorithyFilesIfNotExist( writeCertificateFilesIfNotExist(
ic.CertificatesDir, ic.CertificatesDir,
k.BaseName, k.BaseName,
caCert,
cert, cert,
key, key,
) )
@ -71,14 +73,42 @@ func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x50
return nil return nil
} }
// CreateAsCA creates a certificate authority, writing the files to disk and also returning the created CA so it can be used to sign child certs.
func (k *KubeadmCert) CreateAsCA(ic *kubeadmapi.InitConfiguration) (*x509.Certificate, *rsa.PrivateKey, error) {
cfg, err := k.GetConfig(ic)
if err != nil {
return nil, nil, fmt.Errorf("couldn't get configuration for %q CA certificate: %v", k.Name, err)
}
caCert, caKey, err := NewCACertAndKey(cfg)
if err != nil {
return nil, nil, fmt.Errorf("couldn't generate %q CA certificate: %v", k.Name, err)
}
err = writeCertificateAuthorithyFilesIfNotExist(
ic.CertificatesDir,
k.BaseName,
caCert,
caKey,
)
if err != nil {
return nil, nil, fmt.Errorf("couldn't write out %q CA certificate: %v", k.Name, err)
}
return caCert, caKey, nil
}
// CertificateTree is represents a one-level-deep tree, mapping a CA to the certs that depend on it. // CertificateTree is represents a one-level-deep tree, mapping a CA to the certs that depend on it.
type CertificateTree map[*KubeadmCert]Certificates type CertificateTree map[*KubeadmCert]Certificates
// CreateTree creates the CAs, certs signed by the CAs, and writes them all to disk. // CreateTree creates the CAs, certs signed by the CAs, and writes them all to disk.
func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error { func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
for ca, leaves := range t { for ca, leaves := range t {
// TODO: NewCACertAndKey should take an ic cfg, err := ca.GetConfig(ic)
caCert, caKey, err := NewCACertAndKey() if err != nil {
return err
}
caCert, caKey, err := NewCACertAndKey(cfg)
if err != nil { if err != nil {
return err return err
} }
@ -89,12 +119,13 @@ func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
} }
} }
if err := writeCertificateAuthorithyFilesIfNotExist( err = writeCertificateAuthorithyFilesIfNotExist(
ic.CertificatesDir, ic.CertificatesDir,
ca.BaseName, ca.BaseName,
caCert, caCert,
caKey, caKey,
); err != nil { )
if err != nil {
return err return err
} }
} }
@ -171,7 +202,8 @@ func GetCertsWithoutEtcd() Certificates {
var ( var (
// KubeadmCertRootCA is the definition of the Kubernetes Root CA for the API Server and kubelet. // KubeadmCertRootCA is the definition of the Kubernetes Root CA for the API Server and kubelet.
KubeadmCertRootCA = KubeadmCert{ KubeadmCertRootCA = KubeadmCert{
Name: "root-ca", Name: "ca",
LongName: "self-signed kubernetes CA to provision identities for other kuberenets components",
BaseName: kubeadmconstants.CACertAndKeyBaseName, BaseName: kubeadmconstants.CACertAndKeyBaseName,
config: certutil.Config{ config: certutil.Config{
CommonName: "kubernetes", CommonName: "kubernetes",
@ -179,9 +211,10 @@ var (
} }
// KubeadmCertAPIServer is the definition of the cert used to serve the kubernetes API. // KubeadmCertAPIServer is the definition of the cert used to serve the kubernetes API.
KubeadmCertAPIServer = KubeadmCert{ KubeadmCertAPIServer = KubeadmCert{
Name: "api-server", Name: "apiserver",
LongName: "certificate for serving the kubernetes API",
BaseName: kubeadmconstants.APIServerCertAndKeyBaseName, BaseName: kubeadmconstants.APIServerCertAndKeyBaseName,
CAName: "root-ca", CAName: "ca",
config: certutil.Config{ config: certutil.Config{
CommonName: kubeadmconstants.APIServerCertCommonName, CommonName: kubeadmconstants.APIServerCertCommonName,
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
@ -192,9 +225,10 @@ var (
} }
// KubeadmCertKubeletClient is the definition of the cert used by the API server to access the kubelet. // KubeadmCertKubeletClient is the definition of the cert used by the API server to access the kubelet.
KubeadmCertKubeletClient = KubeadmCert{ KubeadmCertKubeletClient = KubeadmCert{
Name: "api-server-kubelet-client", Name: "apiserver-kubelet-client",
LongName: "Client certificate for the API server to connect to kubelet",
BaseName: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName, BaseName: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
CAName: "root-ca", CAName: "ca",
config: certutil.Config{ config: certutil.Config{
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName, CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
Organization: []string{kubeadmconstants.MastersGroup}, Organization: []string{kubeadmconstants.MastersGroup},
@ -205,6 +239,7 @@ var (
// KubeadmCertFrontProxyCA is the definition of the CA used for the front end proxy. // KubeadmCertFrontProxyCA is the definition of the CA used for the front end proxy.
KubeadmCertFrontProxyCA = KubeadmCert{ KubeadmCertFrontProxyCA = KubeadmCert{
Name: "front-proxy-ca", Name: "front-proxy-ca",
LongName: "self-signed CA to provision identities for front proxy",
BaseName: kubeadmconstants.FrontProxyCACertAndKeyBaseName, BaseName: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
config: certutil.Config{ config: certutil.Config{
CommonName: "front-proxy-ca", CommonName: "front-proxy-ca",
@ -215,6 +250,7 @@ var (
KubeadmCertFrontProxyClient = KubeadmCert{ KubeadmCertFrontProxyClient = KubeadmCert{
Name: "front-proxy-client", Name: "front-proxy-client",
BaseName: kubeadmconstants.FrontProxyClientCertAndKeyBaseName, BaseName: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
LongName: "client for the front proxy",
CAName: "front-proxy-ca", CAName: "front-proxy-ca",
config: certutil.Config{ config: certutil.Config{
CommonName: kubeadmconstants.FrontProxyClientCertCommonName, CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
@ -225,6 +261,7 @@ var (
// KubeadmCertEtcdCA is the definition of the root CA used by the hosted etcd server. // KubeadmCertEtcdCA is the definition of the root CA used by the hosted etcd server.
KubeadmCertEtcdCA = KubeadmCert{ KubeadmCertEtcdCA = KubeadmCert{
Name: "etcd-ca", Name: "etcd-ca",
LongName: "self-signed CA to provision identities for etcd",
BaseName: kubeadmconstants.EtcdCACertAndKeyBaseName, BaseName: kubeadmconstants.EtcdCACertAndKeyBaseName,
config: certutil.Config{ config: certutil.Config{
CommonName: "etcd-ca", CommonName: "etcd-ca",
@ -233,6 +270,7 @@ var (
// KubeadmCertEtcdServer is the definition of the cert used to serve etcd to clients. // KubeadmCertEtcdServer is the definition of the cert used to serve etcd to clients.
KubeadmCertEtcdServer = KubeadmCert{ KubeadmCertEtcdServer = KubeadmCert{
Name: "etcd-server", Name: "etcd-server",
LongName: "certificate for serving etcd",
BaseName: kubeadmconstants.EtcdServerCertAndKeyBaseName, BaseName: kubeadmconstants.EtcdServerCertAndKeyBaseName,
CAName: "etcd-ca", CAName: "etcd-ca",
config: certutil.Config{ config: certutil.Config{
@ -250,6 +288,7 @@ var (
// KubeadmCertEtcdPeer is the definition of the cert used by etcd peers to access each other. // KubeadmCertEtcdPeer is the definition of the cert used by etcd peers to access each other.
KubeadmCertEtcdPeer = KubeadmCert{ KubeadmCertEtcdPeer = KubeadmCert{
Name: "etcd-peer", Name: "etcd-peer",
LongName: "credentials for etcd nodes to communicate with each other",
BaseName: kubeadmconstants.EtcdPeerCertAndKeyBaseName, BaseName: kubeadmconstants.EtcdPeerCertAndKeyBaseName,
CAName: "etcd-ca", CAName: "etcd-ca",
config: certutil.Config{ config: certutil.Config{
@ -262,7 +301,8 @@ var (
} }
// KubeadmCertEtcdHealthcheck is the definition of the cert used by Kubernetes to check the health of the etcd server. // KubeadmCertEtcdHealthcheck is the definition of the cert used by Kubernetes to check the health of the etcd server.
KubeadmCertEtcdHealthcheck = KubeadmCert{ KubeadmCertEtcdHealthcheck = KubeadmCert{
Name: "etcd-healthcheck", Name: "etcd-healthcheck-client",
LongName: "client certificate for liveness probes to healtcheck etcd",
BaseName: kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName, BaseName: kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName,
CAName: "etcd-ca", CAName: "etcd-ca",
config: certutil.Config{ config: certutil.Config{
@ -273,7 +313,8 @@ var (
} }
// KubeadmCertEtcdAPIClient is the definition of the cert used by the API server to access etcd. // KubeadmCertEtcdAPIClient is the definition of the cert used by the API server to access etcd.
KubeadmCertEtcdAPIClient = KubeadmCert{ KubeadmCertEtcdAPIClient = KubeadmCert{
Name: "etcd-api-client", Name: "apiserver-etcd-client",
LongName: "client apiserver uses to access etcd",
BaseName: kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName, BaseName: kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
CAName: "etcd-ca", CAName: "etcd-ca",
config: certutil.Config{ config: certutil.Config{
@ -288,7 +329,7 @@ func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNam
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error { return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
altNames, err := f(mc) altNames, err := f(mc)
if err != nil { if err != nil {
return nil return err
} }
cc.AltNames = *altNames cc.AltNames = *altNames
return nil return nil

View File

@ -66,186 +66,6 @@ func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
return nil return nil
} }
// CreateCACertAndKeyFiles create a new self signed cluster CA certificate and key files.
// If the CA certificate and key files already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
func CreateCACertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("create a new self signed cluster CA certificate and key files")
caCert, caKey, err := NewCACertAndKey()
if err != nil {
return err
}
return writeCertificateAuthorithyFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.CACertAndKeyBaseName,
caCert,
caKey,
)
}
// CreateAPIServerCertAndKeyFiles create a new certificate and key files for the apiserver.
// If the apiserver certificate and key files already exists in the target folder, they are used only if evaluated equal; otherwise an error is returned.
// It assumes the cluster CA certificate and key files exist in the CertificatesDir.
func CreateAPIServerCertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a new certificate and key files for the apiserver")
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return err
}
apiCert, apiKey, err := NewAPIServerCertAndKey(cfg, caCert, caKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.APIServerCertAndKeyBaseName,
caCert,
apiCert,
apiKey,
)
}
// CreateAPIServerKubeletClientCertAndKeyFiles create a new certificate for kubelets calling apiserver.
// If the apiserver-kubelet-client certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
// It assumes the cluster CA certificate and key files exist in the CertificatesDir.
func CreateAPIServerKubeletClientCertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a new certificate for kubelets calling apiserver")
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.CACertAndKeyBaseName)
if err != nil {
return err
}
apiKubeletClientCert, apiKubeletClientKey, err := NewAPIServerKubeletClientCertAndKey(cfg, caCert, caKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
caCert,
apiKubeletClientCert,
apiKubeletClientKey,
)
}
// CreateEtcdCACertAndKeyFiles create a self signed etcd CA certificate and key files.
// The etcd CA and client certs are used to secure communication between etcd peers and connections to etcd from the API server.
// This is a separate CA, so that kubernetes client identities cannot connect to etcd directly or peer with the etcd cluster.
// If the etcd CA certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
func CreateEtcdCACertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a self signed etcd CA certificate and key files")
etcdCACert, etcdCAKey, err := NewEtcdCACertAndKey()
if err != nil {
return err
}
return writeCertificateAuthorithyFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.EtcdCACertAndKeyBaseName,
etcdCACert,
etcdCAKey,
)
}
// CreateEtcdServerCertAndKeyFiles create a new certificate and key file for etcd.
// If the etcd serving certificate and key file already exist in the target folder, they are used only if evaluated equal; otherwise an error is returned.
// It assumes the etcd CA certificate and key file exist in the CertificatesDir
func CreateEtcdServerCertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a new server certificate and key files for etcd")
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
if err != nil {
return err
}
etcdServerCert, etcdServerKey, err := NewEtcdServerCertAndKey(cfg, etcdCACert, etcdCAKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.EtcdServerCertAndKeyBaseName,
etcdCACert,
etcdServerCert,
etcdServerKey,
)
}
// CreateEtcdPeerCertAndKeyFiles create a new certificate and key file for etcd peering.
// If the etcd peer certificate and key file already exist in the target folder, they are used only if evaluated equal; otherwise an error is returned.
// It assumes the etcd CA certificate and key file exist in the CertificatesDir
func CreateEtcdPeerCertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a new certificate and key files for etcd peering")
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
if err != nil {
return err
}
etcdPeerCert, etcdPeerKey, err := NewEtcdPeerCertAndKey(cfg, etcdCACert, etcdCAKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.EtcdPeerCertAndKeyBaseName,
etcdCACert,
etcdPeerCert,
etcdPeerKey,
)
}
// CreateEtcdHealthcheckClientCertAndKeyFiles create a new client certificate for liveness probes to healthcheck etcd
// If the etcd-healthcheck-client certificate and key file already exist in the target folder, they are used only if evaluated equal; otherwise an error is returned.
// It assumes the etcd CA certificate and key file exist in the CertificatesDir
func CreateEtcdHealthcheckClientCertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
if err != nil {
return err
}
etcdHealthcheckClientCert, etcdHealthcheckClientKey, err := NewEtcdHealthcheckClientCertAndKey(cfg, etcdCACert, etcdCAKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName,
etcdCACert,
etcdHealthcheckClientCert,
etcdHealthcheckClientKey,
)
}
// CreateAPIServerEtcdClientCertAndKeyFiles create a new client certificate for the apiserver calling etcd
// If the apiserver-etcd-client certificate and key file already exist in the target folder, they are used only if evaluated equal; otherwise an error is returned.
// It assumes the etcd CA certificate and key file exist in the CertificatesDir
func CreateAPIServerEtcdClientCertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a new client certificate for the apiserver calling etcd")
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
if err != nil {
return err
}
apiEtcdClientCert, apiEtcdClientKey, err := NewAPIServerEtcdClientCertAndKey(cfg, etcdCACert, etcdCAKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
etcdCACert,
apiEtcdClientCert,
apiEtcdClientKey,
)
}
// CreateServiceAccountKeyAndPublicKeyFiles create a new public/private key files for signing service account users. // CreateServiceAccountKeyAndPublicKeyFiles create a new public/private key files for signing service account users.
// If the sa public/private key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned. // If the sa public/private key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.InitConfiguration) error { func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
@ -262,118 +82,8 @@ func CreateServiceAccountKeyAndPublicKeyFiles(cfg *kubeadmapi.InitConfiguration)
) )
} }
// CreateFrontProxyCACertAndKeyFiles create a self signed front proxy CA certificate and key files.
// Front proxy CA and client certs are used to secure a front proxy authenticator which is used to assert identity
// without the client cert; This is a separate CA, so that front proxy identities cannot hit the API and normal client certs cannot be used
// as front proxies.
// If the front proxy CA certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
func CreateFrontProxyCACertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a self signed front proxy CA certificate and key files")
frontProxyCACert, frontProxyCAKey, err := NewFrontProxyCACertAndKey()
if err != nil {
return err
}
return writeCertificateAuthorithyFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.FrontProxyCACertAndKeyBaseName,
frontProxyCACert,
frontProxyCAKey,
)
}
// CreateFrontProxyClientCertAndKeyFiles create a new certificate for proxy server client.
// If the front-proxy-client certificate and key files already exists in the target folder, they are used only if evaluated equals; otherwise an error is returned.
// It assumes the front proxy CA certificate and key files exist in the CertificatesDir.
func CreateFrontProxyClientCertAndKeyFiles(cfg *kubeadmapi.InitConfiguration) error {
glog.V(1).Infoln("creating a new certificate for proxy server client")
frontProxyCACert, frontProxyCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName)
if err != nil {
return err
}
frontProxyClientCert, frontProxyClientKey, err := NewFrontProxyClientCertAndKey(cfg, frontProxyCACert, frontProxyCAKey)
if err != nil {
return err
}
return writeCertificateFilesIfNotExist(
cfg.CertificatesDir,
kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
frontProxyCACert,
frontProxyClientCert,
frontProxyClientKey,
)
}
// NewCACertAndKey will generate a self signed CA.
func NewCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
caCert, caKey, err := pkiutil.NewCertificateAuthority()
if err != nil {
return nil, nil, fmt.Errorf("failure while generating CA certificate and key: %v", err)
}
return caCert, caKey, nil
}
func newCertAndKeyFromSpec(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
certConfig, err := certSpec.GetConfig(cfg)
if err != nil {
return nil, nil, fmt.Errorf("failure while creating certificate %s: %v", certSpec.Name, err)
}
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, *certConfig)
if err != nil {
return nil, nil, fmt.Errorf("failure while creating %s key and certificate: %v", certSpec.Name, err)
}
return cert, key, err
}
// NewAPIServerCertAndKey generate certificate for apiserver, signed by the given CA.
func NewAPIServerCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
return newCertAndKeyFromSpec(&KubeadmCertAPIServer, cfg, caCert, caKey)
}
// NewAPIServerKubeletClientCertAndKey generate certificate for the apiservers to connect to the kubelets securely, signed by the given CA.
func NewAPIServerKubeletClientCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
return newCertAndKeyFromSpec(&KubeadmCertKubeletClient, cfg, caCert, caKey)
}
// NewEtcdCACertAndKey generate a self signed etcd CA.
func NewEtcdCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
etcdCACert, etcdCAKey, err := pkiutil.NewCertificateAuthority()
if err != nil {
return nil, nil, fmt.Errorf("failure while generating etcd CA certificate and key: %v", err)
}
return etcdCACert, etcdCAKey, nil
}
// NewEtcdServerCertAndKey generate certificate for etcd, signed by the given CA.
func NewEtcdServerCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
return newCertAndKeyFromSpec(&KubeadmCertEtcdServer, cfg, caCert, caKey)
}
// NewEtcdPeerCertAndKey generate certificate for etcd peering, signed by the given CA.
func NewEtcdPeerCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
return newCertAndKeyFromSpec(&KubeadmCertEtcdPeer, cfg, caCert, caKey)
}
// NewEtcdHealthcheckClientCertAndKey generate certificate for liveness probes to healthcheck etcd, signed by the given CA.
func NewEtcdHealthcheckClientCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
return newCertAndKeyFromSpec(&KubeadmCertEtcdHealthcheck, cfg, caCert, caKey)
}
// NewAPIServerEtcdClientCertAndKey generate certificate for the apiservers to connect to etcd securely, signed by the given CA.
func NewAPIServerEtcdClientCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
return newCertAndKeyFromSpec(&KubeadmCertEtcdHealthcheck, cfg, caCert, caKey)
}
// NewServiceAccountSigningKey generate public/private key pairs for signing service account tokens. // NewServiceAccountSigningKey generate public/private key pairs for signing service account tokens.
func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) { func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) {
// The key does NOT exist, let's generate it now // The key does NOT exist, let's generate it now
saSigningKey, err := certutil.NewPrivateKey() saSigningKey, err := certutil.NewPrivateKey()
if err != nil { if err != nil {
@ -383,23 +93,71 @@ func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) {
return saSigningKey, nil return saSigningKey, nil
} }
// NewFrontProxyCACertAndKey generate a self signed front proxy CA. // NewCACertAndKey will generate a self signed CA.
func NewFrontProxyCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) { func NewCACertAndKey(certSpec *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
frontProxyCACert, frontProxyCAKey, err := pkiutil.NewCertificateAuthority() caCert, caKey, err := pkiutil.NewCertificateAuthority(certSpec)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failure while generating front-proxy CA certificate and key: %v", err) return nil, nil, fmt.Errorf("failure while generating CA certificate and key: %v", err)
} }
return frontProxyCACert, frontProxyCAKey, nil return caCert, caKey, nil
} }
// NewFrontProxyClientCertAndKey generate certificate for proxy server client, signed by the given front proxy CA. // CreateCACertAndKeyFiles generates and writes out a given certificate authority.
func NewFrontProxyClientCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) { // The certSpec should be one of the variables from this package.
return newCertAndKeyFromSpec(&KubeadmCertFrontProxyClient, cfg, caCert, caKey) func CreateCACertAndKeyFiles(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) error {
if certSpec.CAName != "" {
return fmt.Errorf("This function should only be used for CAs, but cert %s has CA %s", certSpec.Name, certSpec.CAName)
}
glog.V(1).Infoln("creating a new certificate authority for %s", certSpec.Name)
certConfig, err := certSpec.GetConfig(cfg)
if err != nil {
return err
}
caCert, caKey, err := NewCACertAndKey(certConfig)
if err != nil {
return err
}
return writeCertificateAuthorithyFilesIfNotExist(
cfg.CertificatesDir,
certSpec.BaseName,
caCert,
caKey,
)
}
// CreateCertAndKeyFilesWithCA loads the given certificate authority from disk, then generates and writes out the given certificate and key.
// The certSpec and caCertSpec should both be one of the variables from this package.
func CreateCertAndKeyFilesWithCA(certSpec *KubeadmCert, caCertSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration) error {
if certSpec.CAName != caCertSpec.Name {
return fmt.Errorf("Expected CAname for %s to be %q, but was %s", certSpec.Name, certSpec.CAName, caCertSpec.Name)
}
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, caCertSpec.BaseName)
if err != nil {
return fmt.Errorf("Couldn't load CA certificate %s: %v", caCertSpec.Name, err)
}
return certSpec.CreateFromCA(cfg, caCert, caKey)
}
func newCertAndKeyFromSpec(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
certConfig, err := certSpec.GetConfig(cfg)
if err != nil {
return nil, nil, fmt.Errorf("failure while creating certificate %s: %v", certSpec.Name, err)
}
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, certConfig)
if err != nil {
return nil, nil, fmt.Errorf("failure while creating %s key and certificate: %v", certSpec.Name, err)
}
return cert, key, err
} }
// loadCertificateAuthority loads certificate authority
func loadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) { func loadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) {
// Checks if certificate authority exists in the PKI directory // Checks if certificate authority exists in the PKI directory
if !pkiutil.CertOrKeyExist(pkiDir, baseName) { if !pkiutil.CertOrKeyExist(pkiDir, baseName) {
@ -422,7 +180,7 @@ func loadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate
// writeCertificateAuthorithyFilesIfNotExist write a new certificate Authority to the given path. // writeCertificateAuthorithyFilesIfNotExist write a new certificate Authority to the given path.
// If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the // If there already is a certificate file at the given path; kubeadm tries to load it and check if the values in the
// existing and the expected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date, // existing and the eexpected certificate equals. If they do; kubeadm will just skip writing the file as it's up-to-date,
// otherwise this function returns an error. // otherwise this function returns an error.
func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey *rsa.PrivateKey) error { func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {

View File

@ -20,11 +20,12 @@ import (
"crypto/rsa" "crypto/rsa"
"crypto/x509" "crypto/x509"
"fmt" "fmt"
"net"
"os" "os"
"path"
"path/filepath" "path/filepath"
"testing" "testing"
certutil "k8s.io/client-go/util/cert"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil" "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
@ -32,10 +33,30 @@ import (
certstestutil "k8s.io/kubernetes/cmd/kubeadm/test/certs" certstestutil "k8s.io/kubernetes/cmd/kubeadm/test/certs"
) )
func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) { func createCACert(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
certCfg := &certutil.Config{CommonName: "kubernetes"}
cert, key, err := NewCACertAndKey(certCfg)
if err != nil {
t.Fatalf("couldn't create CA: %v", err)
}
return cert, key
}
setupCert, setupKey, _ := NewCACertAndKey() func createTestCert(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey) {
caCert, caKey, _ := NewCACertAndKey() cert, key, err := pkiutil.NewCertAndKey(caCert, caKey,
&certutil.Config{
CommonName: "testCert",
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
})
if err != nil {
t.Fatalf("couldn't create test cert: %v", err)
}
return cert, key
}
func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
setupCert, setupKey := createCACert(t)
caCert, caKey := createCACert(t)
var tests = []struct { var tests = []struct {
setupFunc func(pkiDir string) error setupFunc func(pkiDir string) error
@ -60,7 +81,7 @@ func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
}, },
{ // cert exists, but it is not a ca > err { // cert exists, but it is not a ca > err
setupFunc: func(pkiDir string) error { setupFunc: func(pkiDir string) error {
cert, key, _ := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, setupCert, setupKey) cert, key := createTestCert(t, setupCert, setupKey)
return writeCertificateFilesIfNotExist(pkiDir, "dummy", setupCert, cert, key) return writeCertificateFilesIfNotExist(pkiDir, "dummy", setupCert, cert, key)
}, },
expectedError: true, expectedError: true,
@ -110,9 +131,9 @@ func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
func TestWriteCertificateFilesIfNotExist(t *testing.T) { func TestWriteCertificateFilesIfNotExist(t *testing.T) {
caCert, caKey, _ := NewFrontProxyCACertAndKey() caCert, caKey := createCACert(t)
setupCert, setupKey, _ := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, caCert, caKey) setupCert, setupKey := createTestCert(t, caCert, caKey)
cert, key, _ := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, caCert, caKey) cert, key := createTestCert(t, caCert, caKey)
var tests = []struct { var tests = []struct {
setupFunc func(pkiDir string) error setupFunc func(pkiDir string) error
@ -137,8 +158,8 @@ func TestWriteCertificateFilesIfNotExist(t *testing.T) {
}, },
{ // cert exists, is signed by another ca > err { // cert exists, is signed by another ca > err
setupFunc: func(pkiDir string) error { setupFunc: func(pkiDir string) error {
anotherCaCert, anotherCaKey, _ := NewFrontProxyCACertAndKey() anotherCaCert, anotherCaKey := createCACert(t)
anotherCert, anotherKey, _ := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, anotherCaCert, anotherCaKey) anotherCert, anotherKey := createTestCert(t, anotherCaCert, anotherCaKey)
return writeCertificateFilesIfNotExist(pkiDir, "dummy", anotherCaCert, anotherCert, anotherKey) return writeCertificateFilesIfNotExist(pkiDir, "dummy", anotherCaCert, anotherCert, anotherKey)
}, },
@ -259,7 +280,8 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
} }
func TestNewCACertAndKey(t *testing.T) { func TestNewCACertAndKey(t *testing.T) {
caCert, _, err := NewCACertAndKey() certCfg := &certutil.Config{CommonName: "kubernetes"}
caCert, _, err := NewCACertAndKey(certCfg)
if err != nil { if err != nil {
t.Fatalf("failed call NewCACertAndKey: %v", err) t.Fatalf("failed call NewCACertAndKey: %v", err)
} }
@ -267,269 +289,90 @@ func TestNewCACertAndKey(t *testing.T) {
certstestutil.AssertCertificateIsCa(t, caCert) certstestutil.AssertCertificateIsCa(t, caCert)
} }
func TestNewAPIServerCertAndKey(t *testing.T) {
hostname := "valid-hostname"
advertiseAddresses := []string{"1.2.3.4", "1:2:3::4"}
for _, addr := range advertiseAddresses {
cfg := &kubeadmapi.InitConfiguration{
API: kubeadmapi.API{AdvertiseAddress: addr},
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: hostname},
}
caCert, caKey, err := NewCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
apiServerCert, _, err := NewAPIServerCertAndKey(cfg, caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, apiServerCert, caCert)
certstestutil.AssertCertificateHasServerAuthUsage(t, apiServerCert)
certstestutil.AssertCertificateHasDNSNames(t, apiServerCert, hostname, "kubernetes", "kubernetes.default", "kubernetes.default.svc", "kubernetes.default.svc.cluster.local")
certstestutil.AssertCertificateHasIPAddresses(t, apiServerCert, net.ParseIP("10.96.0.1"), net.ParseIP(addr))
}
}
func TestNewAPIServerKubeletClientCertAndKey(t *testing.T) {
caCert, caKey, err := NewCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
apiKubeletClientCert, _, err := NewAPIServerKubeletClientCertAndKey(&kubeadmapi.InitConfiguration{}, caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, apiKubeletClientCert, caCert)
certstestutil.AssertCertificateHasClientAuthUsage(t, apiKubeletClientCert)
certstestutil.AssertCertificateHasOrganizations(t, apiKubeletClientCert, kubeadmconstants.MastersGroup)
}
func TestNewEtcdCACertAndKey(t *testing.T) {
etcdCACert, _, err := NewEtcdCACertAndKey()
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsCa(t, etcdCACert)
}
func TestNewEtcdServerCertAndKey(t *testing.T) {
proxy := "user-etcd-proxy"
proxyIP := "10.10.10.100"
cfg := &kubeadmapi.InitConfiguration{
NodeRegistration: kubeadmapi.NodeRegistrationOptions{
Name: "etcd-server-cert",
},
Etcd: kubeadmapi.Etcd{
Local: &kubeadmapi.LocalEtcd{
ServerCertSANs: []string{
proxy,
proxyIP,
},
},
},
}
caCert, caKey, err := NewCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
etcdServerCert, _, err := NewEtcdServerCertAndKey(cfg, caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, etcdServerCert, caCert)
certstestutil.AssertCertificateHasServerAuthUsage(t, etcdServerCert)
certstestutil.AssertCertificateHasDNSNames(t, etcdServerCert, "localhost", proxy)
certstestutil.AssertCertificateHasIPAddresses(t, etcdServerCert, net.ParseIP("127.0.0.1"), net.ParseIP(proxyIP))
}
func TestNewEtcdPeerCertAndKey(t *testing.T) {
hostname := "valid-hostname"
proxy := "user-etcd-proxy"
proxyIP := "10.10.10.100"
advertiseAddresses := []string{"1.2.3.4", "1:2:3::4"}
for _, addr := range advertiseAddresses {
cfg := &kubeadmapi.InitConfiguration{
API: kubeadmapi.API{AdvertiseAddress: addr},
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: hostname},
Etcd: kubeadmapi.Etcd{
Local: &kubeadmapi.LocalEtcd{
PeerCertSANs: []string{
proxy,
proxyIP,
},
},
},
}
caCert, caKey, err := NewCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
etcdPeerCert, _, err := NewEtcdPeerCertAndKey(cfg, caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, etcdPeerCert, caCert)
certstestutil.AssertCertificateHasServerAuthUsage(t, etcdPeerCert)
certstestutil.AssertCertificateHasClientAuthUsage(t, etcdPeerCert)
certstestutil.AssertCertificateHasDNSNames(t, etcdPeerCert, hostname, proxy)
certstestutil.AssertCertificateHasIPAddresses(t, etcdPeerCert, net.ParseIP(addr), net.ParseIP(proxyIP))
}
}
func TestNewEtcdHealthcheckClientCertAndKey(t *testing.T) {
caCert, caKey, err := NewCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
etcdHealthcheckClientCert, _, err := NewEtcdHealthcheckClientCertAndKey(&kubeadmapi.InitConfiguration{}, caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, etcdHealthcheckClientCert, caCert)
certstestutil.AssertCertificateHasClientAuthUsage(t, etcdHealthcheckClientCert)
certstestutil.AssertCertificateHasOrganizations(t, etcdHealthcheckClientCert, kubeadmconstants.MastersGroup)
}
func TestNewAPIServerEtcdClientCertAndKey(t *testing.T) {
caCert, caKey, err := NewCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
apiEtcdClientCert, _, err := NewAPIServerEtcdClientCertAndKey(&kubeadmapi.InitConfiguration{}, caCert, caKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, apiEtcdClientCert, caCert)
certstestutil.AssertCertificateHasClientAuthUsage(t, apiEtcdClientCert)
certstestutil.AssertCertificateHasOrganizations(t, apiEtcdClientCert, kubeadmconstants.MastersGroup)
}
func TestNewNewServiceAccountSigningKey(t *testing.T) {
key, err := NewServiceAccountSigningKey()
if err != nil {
t.Fatalf("failed creation of key: %v", err)
}
if key.N.BitLen() < 2048 {
t.Error("Service account signing key has less than 2048 bits size")
}
}
func TestNewFrontProxyCACertAndKey(t *testing.T) {
frontProxyCACert, _, err := NewFrontProxyCACertAndKey()
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsCa(t, frontProxyCACert)
}
func TestNewFrontProxyClientCertAndKey(t *testing.T) {
frontProxyCACert, frontProxyCAKey, err := NewFrontProxyCACertAndKey()
if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
frontProxyClientCert, _, err := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, frontProxyCACert, frontProxyCAKey)
if err != nil {
t.Fatalf("failed creation of cert and key: %v", err)
}
certstestutil.AssertCertificateIsSignedByCa(t, frontProxyClientCert, frontProxyCACert)
certstestutil.AssertCertificateHasClientAuthUsage(t, frontProxyClientCert)
}
func TestSharedCertificateExists(t *testing.T) { func TestSharedCertificateExists(t *testing.T) {
caCert, caKey := createCACert(t)
_, key := createTestCert(t, caCert, caKey)
publicKey := &key.PublicKey
var tests = []struct { var tests = []struct {
setupFunc func(cfg *kubeadmapi.InitConfiguration) name string
files pkiFiles
expectedError bool expectedError bool
}{ }{
{ // expected certs exist, pass {
setupFunc: func(cfg *kubeadmapi.InitConfiguration) { name: "success",
CreateCACertAndKeyFiles(cfg) files: pkiFiles{
CreateServiceAccountKeyAndPublicKeyFiles(cfg) "ca.crt": caCert,
CreateFrontProxyCACertAndKeyFiles(cfg) "ca.key": caKey,
"front-proxy-ca.crt": caCert,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
"sa.key": key,
}, },
expectedError: false,
}, },
{ // expected ca.crt missing {
setupFunc: func(cfg *kubeadmapi.InitConfiguration) { name: "missing ca.crt",
// start from the condition created by the previous tests files: pkiFiles{
os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName)) "ca.key": caKey,
"front-proxy-ca.crt": caCert,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
"sa.key": key,
}, },
expectedError: true, expectedError: true,
}, },
{ // expected sa.key missing {
setupFunc: func(cfg *kubeadmapi.InitConfiguration) { name: "missing sa.key",
// start from the condition created by the previous tests files: pkiFiles{
CreateCACertAndKeyFiles(cfg) "ca.crt": caCert,
os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName)) "ca.key": caKey,
"front-proxy-ca.crt": caCert,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
}, },
expectedError: true, expectedError: true,
}, },
{ // expected front-proxy.crt missing {
setupFunc: func(cfg *kubeadmapi.InitConfiguration) { name: "expected front-proxy.crt missing",
// start from the condition created by the previous tests files: pkiFiles{
CreateServiceAccountKeyAndPublicKeyFiles(cfg) "ca.crt": caCert,
os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName)) "ca.key": caKey,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
"sa.key": key,
}, },
expectedError: true, expectedError: true,
}, },
} }
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
cfg := &kubeadmapi.InitConfiguration{
CertificatesDir: tmpdir,
}
for _, test := range tests { for _, test := range tests {
// executes setup func (if necessary) t.Run("", func(t *testing.T) {
if test.setupFunc != nil { tmpdir := testutil.SetupTempDir(t)
test.setupFunc(cfg) defer os.RemoveAll(tmpdir)
}
// executes create func cfg := &kubeadmapi.InitConfiguration{
ret, err := SharedCertificateExists(cfg) CertificatesDir: tmpdir,
}
if !test.expectedError && err != nil { // created expected keys
t.Errorf("error SharedCertificateExists failed when not expected to fail: %v", err) writePKIFiles(t, tmpdir, test.files)
continue
} else if test.expectedError && err == nil {
t.Error("error SharedCertificateExists didn't failed when expected")
continue
} else if test.expectedError {
continue
}
if ret != (err == nil) { // executes create func
t.Errorf("error SharedCertificateExists returned %v when expected to return %v", ret, err == nil) ret, err := SharedCertificateExists(cfg)
}
switch {
case !test.expectedError && err != nil:
t.Errorf("error SharedCertificateExists failed when not expected to fail: %v", err)
case test.expectedError && err == nil:
t.Errorf("error SharedCertificateExists didn't failed when expected")
case ret != (err == nil):
t.Errorf("error SharedCertificateExists returned %v when expected to return %v", ret, err == nil)
}
})
} }
} }
func TestUsingExternalCA(t *testing.T) { func TestUsingExternalCA(t *testing.T) {
tests := []struct { tests := []struct {
setupFuncs []func(cfg *kubeadmapi.InitConfiguration) error setupFuncs []func(cfg *kubeadmapi.InitConfiguration) error
expected bool expected bool
@ -575,17 +418,20 @@ func TestUsingExternalCA(t *testing.T) {
func TestValidateMethods(t *testing.T) { func TestValidateMethods(t *testing.T) {
caCert, caKey := createCACert(t)
cert, key := createTestCert(t, caCert, caKey)
tests := []struct { tests := []struct {
name string name string
setupFuncs []func(cfg *kubeadmapi.InitConfiguration) error files pkiFiles
validateFunc func(l certKeyLocation) error validateFunc func(l certKeyLocation) error
loc certKeyLocation loc certKeyLocation
expectedSuccess bool expectedSuccess bool
}{ }{
{ {
name: "validateCACert", name: "validateCACert",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{ files: pkiFiles{
CreateCACertAndKeyFiles, "ca.crt": caCert,
}, },
validateFunc: validateCACert, validateFunc: validateCACert,
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"}, loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
@ -593,28 +439,30 @@ func TestValidateMethods(t *testing.T) {
}, },
{ {
name: "validateCACertAndKey (files present)", name: "validateCACertAndKey (files present)",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{ files: pkiFiles{
CreateCACertAndKeyFiles, "ca.crt": caCert,
"ca.key": caKey,
}, },
validateFunc: validateCACertAndKey, validateFunc: validateCACertAndKey,
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"}, loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
expectedSuccess: true, expectedSuccess: true,
}, },
{ {
name: "validateCACertAndKey (key missing)", files: pkiFiles{
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{ "ca.crt": caCert,
CreatePKIAssets,
deleteCAKey,
}, },
name: "validateCACertAndKey (key missing)",
validateFunc: validateCACertAndKey, validateFunc: validateCACertAndKey,
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"}, loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
expectedSuccess: false, expectedSuccess: false,
}, },
{ {
name: "validateSignedCert", name: "validateSignedCert",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{ files: pkiFiles{
CreateCACertAndKeyFiles, "ca.crt": caCert,
CreateAPIServerCertAndKeyFiles, "ca.key": caKey,
"apiserver.crt": cert,
"apiserver.key": key,
}, },
validateFunc: validateSignedCert, validateFunc: validateSignedCert,
loc: certKeyLocation{caBaseName: "ca", baseName: "apiserver", uxName: "apiserver"}, loc: certKeyLocation{caBaseName: "ca", baseName: "apiserver", uxName: "apiserver"},
@ -622,8 +470,9 @@ func TestValidateMethods(t *testing.T) {
}, },
{ {
name: "validatePrivatePublicKey", name: "validatePrivatePublicKey",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{ files: pkiFiles{
CreateServiceAccountKeyAndPublicKeyFiles, "sa.pub": &key.PublicKey,
"sa.key": key,
}, },
validateFunc: validatePrivatePublicKey, validateFunc: validatePrivatePublicKey,
loc: certKeyLocation{baseName: "sa", uxName: "service account"}, loc: certKeyLocation{baseName: "sa", uxName: "service account"},
@ -632,25 +481,11 @@ func TestValidateMethods(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
dir := testutil.SetupTempDir(t) dir := testutil.SetupTempDir(t)
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
test.loc.pkiDir = dir test.loc.pkiDir = dir
cfg := &kubeadmapi.InitConfiguration{ writePKIFiles(t, dir, test.files)
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4"},
Networking: kubeadmapi.Networking{ServiceSubnet: "10.96.0.0/12", DNSDomain: "cluster.local"},
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-hostname"},
CertificatesDir: dir,
}
fmt.Println("Testing", test.name)
for _, f := range test.setupFuncs {
if err := f(cfg); err != nil {
t.Errorf("error executing setup function: %v", err)
}
}
err := test.validateFunc(test.loc) err := test.validateFunc(test.loc)
if test.expectedSuccess && err != nil { if test.expectedSuccess && err != nil {
@ -661,18 +496,29 @@ func TestValidateMethods(t *testing.T) {
} }
} }
func deleteCAKey(cfg *kubeadmapi.InitConfiguration) error { type pkiFiles map[string]interface{}
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)); err != nil {
return fmt.Errorf("failed removing %s: %v", kubeadmconstants.CAKeyName, err)
}
return nil
}
func deleteFrontProxyCAKey(cfg *kubeadmapi.InitConfiguration) error { func writePKIFiles(t *testing.T, dir string, files pkiFiles) {
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCAKeyName)); err != nil { for filename, body := range files {
return fmt.Errorf("failed removing %s: %v", kubeadmconstants.FrontProxyCAKeyName, err) switch body := body.(type) {
case *x509.Certificate:
if err := certutil.WriteCert(path.Join(dir, filename), certutil.EncodeCertPEM(body)); err != nil {
t.Errorf("unable to write certificate to file %q: [%v]", dir, err)
}
case *rsa.PublicKey:
publicKeyBytes, err := certutil.EncodePublicKeyPEM(body)
if err != nil {
t.Errorf("unable to write public key to file %q: [%v]", filename, err)
}
if err := certutil.WriteKey(path.Join(dir, filename), publicKeyBytes); err != nil {
t.Errorf("unable to write public key to file %q: [%v]", filename, err)
}
case *rsa.PrivateKey:
if err := certutil.WriteKey(path.Join(dir, filename), certutil.EncodePrivateKeyPEM(body)); err != nil {
t.Errorf("unable to write private key to file %q: [%v]", filename, err)
}
}
} }
return nil
} }
func TestCreateCertificateFilesMethods(t *testing.T) { func TestCreateCertificateFilesMethods(t *testing.T) {
@ -711,57 +557,6 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName, kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName,
}, },
}, },
{
createFunc: CreateCACertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.CACertName, kubeadmconstants.CAKeyName},
},
{
setupFunc: CreateCACertAndKeyFiles,
createFunc: CreateAPIServerCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName},
},
{
setupFunc: CreateCACertAndKeyFiles,
createFunc: CreateAPIServerKubeletClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName},
},
{
createFunc: CreateEtcdCACertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName},
},
{
setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateEtcdServerCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName},
},
{
setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateEtcdPeerCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName},
},
{
setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateEtcdHealthcheckClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName},
},
{
setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateAPIServerEtcdClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName},
},
{
createFunc: CreateServiceAccountKeyAndPublicKeyFiles,
expectedFiles: []string{kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName},
},
{
createFunc: CreateFrontProxyCACertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName},
},
{
setupFunc: CreateFrontProxyCACertAndKeyFiles,
createFunc: CreateFrontProxyClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName},
},
} }
for _, test := range tests { for _, test := range tests {
@ -785,14 +580,6 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
cfg.Etcd.External.Endpoints = []string{"192.168.1.1:2379"} cfg.Etcd.External.Endpoints = []string{"192.168.1.1:2379"}
} }
// executes setup func (if necessary)
if test.setupFunc != nil {
if err := test.setupFunc(cfg); err != nil {
t.Errorf("error executing setupFunc: %v", err)
continue
}
}
// executes create func // executes create func
if err := test.createFunc(cfg); err != nil { if err := test.createFunc(cfg); err != nil {
t.Errorf("error executing createFunc: %v", err) t.Errorf("error executing createFunc: %v", err)
@ -803,3 +590,17 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...) testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
} }
} }
func deleteCAKey(cfg *kubeadmapi.InitConfiguration) error {
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName)); err != nil {
return fmt.Errorf("failed removing %s: %v", kubeadmconstants.CAKeyName, err)
}
return nil
}
func deleteFrontProxyCAKey(cfg *kubeadmapi.InitConfiguration) error {
if err := os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCAKeyName)); err != nil {
return fmt.Errorf("failed removing %s: %v", kubeadmconstants.FrontProxyCAKeyName, err)
}
return nil
}

View File

@ -34,16 +34,13 @@ import (
) )
// NewCertificateAuthority creates new certificate and private key for the certificate authority // NewCertificateAuthority creates new certificate and private key for the certificate authority
func NewCertificateAuthority() (*x509.Certificate, *rsa.PrivateKey, error) { func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
key, err := certutil.NewPrivateKey() key, err := certutil.NewPrivateKey()
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unable to create private key [%v]", err) return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
} }
config := certutil.Config{ cert, err := certutil.NewSelfSignedCACert(*config, key)
CommonName: "kubernetes",
}
cert, err := certutil.NewSelfSignedCACert(config, key)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unable to create self-signed certificate [%v]", err) return nil, nil, fmt.Errorf("unable to create self-signed certificate [%v]", err)
} }
@ -52,13 +49,13 @@ func NewCertificateAuthority() (*x509.Certificate, *rsa.PrivateKey, error) {
} }
// NewCertAndKey creates new certificate and key by passing the certificate authority certificate and key // NewCertAndKey creates new certificate and key by passing the certificate authority certificate and key
func NewCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey, config certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) { func NewCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey, config *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
key, err := certutil.NewPrivateKey() key, err := certutil.NewPrivateKey()
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unable to create private key [%v]", err) return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
} }
cert, err := certutil.NewSignedCert(config, key, caCert, caKey) cert, err := certutil.NewSignedCert(*config, key, caCert, caKey)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("unable to sign certificate [%v]", err) return nil, nil, fmt.Errorf("unable to sign certificate [%v]", err)
} }

View File

@ -30,7 +30,7 @@ import (
) )
func TestNewCertificateAuthority(t *testing.T) { func TestNewCertificateAuthority(t *testing.T) {
cert, key, err := NewCertificateAuthority() cert, key, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
if cert == nil { if cert == nil {
t.Errorf( t.Errorf(
@ -73,7 +73,7 @@ func TestNewCertAndKey(t *testing.T) {
t.Fatalf("Couldn't create rsa Private Key") t.Fatalf("Couldn't create rsa Private Key")
} }
caCert := &x509.Certificate{} caCert := &x509.Certificate{}
config := certutil.Config{ config := &certutil.Config{
CommonName: "test", CommonName: "test",
Organization: []string{"test"}, Organization: []string{"test"},
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
@ -90,7 +90,7 @@ func TestNewCertAndKey(t *testing.T) {
} }
func TestHasServerAuth(t *testing.T) { func TestHasServerAuth(t *testing.T) {
caCert, caKey, _ := NewCertificateAuthority() caCert, caKey, _ := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
var tests = []struct { var tests = []struct {
config certutil.Config config certutil.Config
@ -113,7 +113,7 @@ func TestHasServerAuth(t *testing.T) {
} }
for _, rt := range tests { for _, rt := range tests {
cert, _, err := NewCertAndKey(caCert, caKey, rt.config) cert, _, err := NewCertAndKey(caCert, caKey, &rt.config)
if err != nil { if err != nil {
t.Fatalf("Couldn't create cert: %v", err) t.Fatalf("Couldn't create cert: %v", err)
} }
@ -261,7 +261,7 @@ func TestTryLoadCertAndKeyFromDisk(t *testing.T) {
} }
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
caCert, caKey, err := NewCertificateAuthority() caCert, caKey, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
if err != nil { if err != nil {
t.Errorf( t.Errorf(
"failed to create cert and key with an error: %v", "failed to create cert and key with an error: %v",
@ -311,7 +311,7 @@ func TestTryLoadCertFromDisk(t *testing.T) {
} }
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
caCert, _, err := NewCertificateAuthority() caCert, _, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
if err != nil { if err != nil {
t.Errorf( t.Errorf(
"failed to create cert and key with an error: %v", "failed to create cert and key with an error: %v",
@ -361,7 +361,7 @@ func TestTryLoadKeyFromDisk(t *testing.T) {
} }
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
_, caKey, err := NewCertificateAuthority() _, caKey, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
if err != nil { if err != nil {
t.Errorf( t.Errorf(
"failed to create cert and key with an error: %v", "failed to create cert and key with an error: %v",

View File

@ -222,7 +222,7 @@ func buildKubeConfigFromSpec(spec *kubeConfigSpec, clustername string) (*clientc
Organization: spec.ClientCertAuth.Organizations, Organization: spec.ClientCertAuth.Organizations,
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
} }
clientCert, clientKey, err := pkiutil.NewCertAndKey(spec.CACert, spec.ClientCertAuth.CAKey, clientCertConfig) clientCert, clientKey, err := pkiutil.NewCertAndKey(spec.CACert, spec.ClientCertAuth.CAKey, &clientCertConfig)
if err != nil { if err != nil {
return nil, fmt.Errorf("failure while creating %s client certificate: %v", spec.ClientName, err) return nil, fmt.Errorf("failure while creating %s client certificate: %v", spec.ClientName, err)
} }

View File

@ -80,7 +80,6 @@ go_test(
"//cmd/kubeadm/app/apis/kubeadm/v1alpha3:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1alpha3:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/phases/certs:go_default_library", "//cmd/kubeadm/app/phases/certs:go_default_library",
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
"//cmd/kubeadm/app/phases/controlplane:go_default_library", "//cmd/kubeadm/app/phases/controlplane:go_default_library",
"//cmd/kubeadm/app/phases/etcd:go_default_library", "//cmd/kubeadm/app/phases/etcd:go_default_library",
"//cmd/kubeadm/app/util/apiclient:go_default_library", "//cmd/kubeadm/app/util/apiclient:go_default_library",

View File

@ -195,7 +195,11 @@ func backupAPIServerCertIfNeeded(cfg *kubeadmapi.InitConfiguration, dryRun bool)
if err := backupAPIServerCertAndKey(certAndKeyDir); err != nil { if err := backupAPIServerCertAndKey(certAndKeyDir); err != nil {
fmt.Printf("[postupgrade] WARNING: failed to backup kube-apiserver cert and key: %v", err) fmt.Printf("[postupgrade] WARNING: failed to backup kube-apiserver cert and key: %v", err)
} }
return certsphase.CreateAPIServerCertAndKeyFiles(cfg) return certsphase.CreateCertAndKeyFilesWithCA(
&certsphase.KubeadmCertAPIServer,
&certsphase.KubeadmCertRootCA,
cfg,
)
} }
func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, newK8sVer *version.Version, dryRun bool) error { func writeKubeletConfigFiles(client clientset.Interface, cfg *kubeadmapi.InitConfiguration, newK8sVer *version.Version, dryRun bool) error {

View File

@ -27,7 +27,6 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/constants"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
testutil "k8s.io/kubernetes/cmd/kubeadm/test" testutil "k8s.io/kubernetes/cmd/kubeadm/test"
) )
@ -148,23 +147,21 @@ func TestShouldBackupAPIServerCertAndKey(t *testing.T) {
expected: true, expected: true,
}, },
} { } {
caCert, caKey, err := certsphase.NewCACertAndKey() tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
cfg.CertificatesDir = tmpdir
caCert, caKey, err := certsphase.KubeadmCertRootCA.CreateAsCA(cfg)
if err != nil { if err != nil {
t.Fatalf("failed creation of ca cert and key: %v", err) t.Fatalf("failed creation of ca cert and key: %v", err)
} }
caCert.NotBefore = caCert.NotBefore.Add(-test.adjustedExpiry).UTC() caCert.NotBefore = caCert.NotBefore.Add(-test.adjustedExpiry).UTC()
apiCert, apiKey, err := certsphase.NewAPIServerCertAndKey(cfg, caCert, caKey)
err = certsphase.KubeadmCertAPIServer.CreateFromCA(cfg, caCert, caKey)
if err != nil { if err != nil {
t.Fatalf("Test %s: failed creation of cert and key: %v", desc, err) t.Fatalf("Test %s: failed creation of cert and key: %v", desc, err)
} }
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
if err := pkiutil.WriteCertAndKey(tmpdir, constants.APIServerCertAndKeyBaseName, apiCert, apiKey); err != nil {
t.Fatalf("Test %s: failure while saving %s certificate and key: %v", desc, constants.APIServerCertAndKeyBaseName, err)
}
certAndKey := []string{filepath.Join(tmpdir, constants.APIServerCertName), filepath.Join(tmpdir, constants.APIServerKeyName)} certAndKey := []string{filepath.Join(tmpdir, constants.APIServerCertName), filepath.Join(tmpdir, constants.APIServerKeyName)}
for _, path := range certAndKey { for _, path := range certAndKey {
if _, err := os.Stat(path); os.IsNotExist(err) { if _, err := os.Stat(path); os.IsNotExist(err) {

View File

@ -187,24 +187,27 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
// ensure etcd certs are generated for etcd and kube-apiserver // ensure etcd certs are generated for etcd and kube-apiserver
if component == constants.Etcd || component == constants.KubeAPIServer { if component == constants.Etcd || component == constants.KubeAPIServer {
if err := certsphase.CreateEtcdCACertAndKeyFiles(cfg); err != nil {
caCert, caKey, err := certsphase.KubeadmCertEtcdCA.CreateAsCA(cfg)
if err != nil {
return fmt.Errorf("failed to upgrade the %s CA certificate and key: %v", constants.Etcd, err) return fmt.Errorf("failed to upgrade the %s CA certificate and key: %v", constants.Etcd, err)
} }
}
if component == constants.Etcd { if component == constants.Etcd {
if err := certsphase.CreateEtcdServerCertAndKeyFiles(cfg); err != nil { if err := certsphase.KubeadmCertEtcdServer.CreateFromCA(cfg, caCert, caKey); err != nil {
return fmt.Errorf("failed to upgrade the %s certificate and key: %v", constants.Etcd, err) return fmt.Errorf("failed to upgrade the %s certificate and key: %v", constants.Etcd, err)
}
if err := certsphase.KubeadmCertEtcdPeer.CreateFromCA(cfg, caCert, caKey); err != nil {
return fmt.Errorf("failed to upgrade the %s peer certificate and key: %v", constants.Etcd, err)
}
if err := certsphase.KubeadmCertEtcdHealthcheck.CreateFromCA(cfg, caCert, caKey); err != nil {
return fmt.Errorf("failed to upgrade the %s healthcheck certificate and key: %v", constants.Etcd, err)
}
} }
if err := certsphase.CreateEtcdPeerCertAndKeyFiles(cfg); err != nil { if component == constants.KubeAPIServer {
return fmt.Errorf("failed to upgrade the %s peer certificate and key: %v", constants.Etcd, err) if err := certsphase.KubeadmCertEtcdAPIClient.CreateFromCA(cfg, caCert, caKey); err != nil {
} return fmt.Errorf("failed to upgrade the %s %s-client certificate and key: %v", constants.KubeAPIServer, constants.Etcd, err)
if err := certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles(cfg); err != nil { }
return fmt.Errorf("failed to upgrade the %s healthcheck certificate and key: %v", constants.Etcd, err)
}
}
if component == constants.KubeAPIServer {
if err := certsphase.CreateAPIServerEtcdClientCertAndKeyFiles(cfg); err != nil {
return fmt.Errorf("failed to upgrade the %s %s-client certificate and key: %v", constants.KubeAPIServer, constants.Etcd, err)
} }
} }

View File

@ -420,27 +420,16 @@ func TestStaticPodControlPlane(t *testing.T) {
t.Fatalf("couldn't create config: %v", err) t.Fatalf("couldn't create config: %v", err)
} }
// Initialize PKI minus any etcd certificates to simulate etcd PKI upgrade tree, err := certsphase.GetCertsWithoutEtcd().AsMap().CertTree()
certActions := []func(cfg *kubeadmapi.InitConfiguration) error{ if err != nil {
certsphase.CreateCACertAndKeyFiles, t.Fatalf("couldn't get cert tree: %v", err)
certsphase.CreateAPIServerCertAndKeyFiles,
certsphase.CreateAPIServerKubeletClientCertAndKeyFiles,
// certsphase.CreateEtcdCACertAndKeyFiles,
// certsphase.CreateEtcdServerCertAndKeyFiles,
// certsphase.CreateEtcdPeerCertAndKeyFiles,
// certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles,
// certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
certsphase.CreateServiceAccountKeyAndPublicKeyFiles,
certsphase.CreateFrontProxyCACertAndKeyFiles,
certsphase.CreateFrontProxyClientCertAndKeyFiles,
} }
for _, action := range certActions {
err := action(oldcfg) if err := tree.CreateTree(oldcfg); err != nil {
if err != nil { t.Fatalf("couldn't get create cert tree: %v", err)
t.Fatalf("couldn't initialize pre-upgrade certificate: %v", err)
}
} }
fmt.Printf("Wrote certs to %s\n", oldcfg.CertificatesDir)
t.Logf("Wrote certs to %s\n", oldcfg.CertificatesDir)
// Initialize the directory with v1.7 manifests; should then be upgraded to v1.8 using the method // Initialize the directory with v1.7 manifests; should then be upgraded to v1.8 using the method
err = controlplanephase.CreateInitStaticPodManifestFiles(pathMgr.RealManifestDir(), oldcfg) err = controlplanephase.CreateInitStaticPodManifestFiles(pathMgr.RealManifestDir(), oldcfg)

View File

@ -9,7 +9,10 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["util.go"], srcs = ["util.go"],
importpath = "k8s.io/kubernetes/cmd/kubeadm/test/certs", importpath = "k8s.io/kubernetes/cmd/kubeadm/test/certs",
deps = ["//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library"], deps = [
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
],
) )
filegroup( filegroup(

View File

@ -22,13 +22,14 @@ import (
"net" "net"
"testing" "testing"
certutil "k8s.io/client-go/util/cert"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil" "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
) )
// SetupCertificateAuthorithy is a utility function for kubeadm testing that creates a // SetupCertificateAuthorithy is a utility function for kubeadm testing that creates a
// CertificateAuthorithy cert/key pair // CertificateAuthorithy cert/key pair
func SetupCertificateAuthorithy(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) { func SetupCertificateAuthorithy(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
caCert, caKey, err := pkiutil.NewCertificateAuthority() caCert, caKey, err := pkiutil.NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
if err != nil { if err != nil {
t.Fatalf("failure while generating CA certificate and key: %v", err) t.Fatalf("failure while generating CA certificate and key: %v", err)
} }