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

```
pull/8/head
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 (
"fmt"
"strings"
"github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
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"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
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)
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.
` + cmdutil.AlphaDisclaimer)
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.
kubeadm alpha phase certs all
@ -51,85 +51,17 @@ var (
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(`
Generates the private key for signing service account tokens along with its public 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.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName)
frontProxyCaCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the front proxy CA certificate and key and saves them into %s and %s files.
genericLongDesc = normalizer.LongDesc(`
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.
`+cmdutil.AlphaDisclaimer), kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName)
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)
` + cmdutil.AlphaDisclaimer)
)
// NewCmdCerts returns main command for certs phase
@ -154,147 +86,146 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
kubeadmscheme.Scheme.Default(cfg)
var cfgPath string
var subCmds []*cobra.Command
subCmdProperties := []struct {
use string
short string
long string
examples string
cmdFunc func(cfg *kubeadmapi.InitConfiguration) error
}{
{
use: "all",
short: "Generates all PKI assets necessary to establish the control plane",
long: allCertsLongDesc,
examples: allCertsExample,
cmdFunc: certsphase.CreatePKIAssets,
},
{
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,
// Special case commands
// All runs CreatePKIAssets, which isn't a particular certificate
allCmd := &cobra.Command{
Use: "all",
Short: "Generates all PKI assets necessary to establish the control plane",
Long: allCertsLongDesc,
Example: allCertsExample,
Run: func(cmd *cobra.Command, args []string) {
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
kubeadmutil.CheckErr(err)
err = certsphase.CreatePKIAssets(internalcfg)
kubeadmutil.CheckErr(err)
},
}
addFlags(allCmd, &cfgPath, cfg, true)
for _, properties := range subCmdProperties {
// Creates the UX Command
cmd := &cobra.Command{
Use: properties.use,
Short: properties.short,
Long: properties.long,
Example: properties.examples,
Run: runCmdFunc(properties.cmdFunc, &cfgPath, cfg, defaultKubernetesVersion),
}
// SA creates the private/public key pair, which doesn't use x509 at all
saCmd := &cobra.Command{
Use: "sa",
Short: "Generates a private key for signing service account tokens along with its public key",
Long: saKeyLongDesc,
Run: func(cmd *cobra.Command, args []string) {
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
kubeadmutil.CheckErr(err)
// Add flags to the command
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 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")
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")
}
err = certsphase.CreateServiceAccountKeyAndPublicKeyFiles(internalcfg)
kubeadmutil.CheckErr(err)
},
}
addFlags(saCmd, &cfgPath, cfg, false)
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
}
// 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 runCmdFunc(cmdFunc func(cfg *kubeadmapi.InitConfiguration) error, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration, defaultKubernetesVersion string) func(cmd *cobra.Command, args []string) {
func makeCmd(certSpec *certsphase.KubeadmCert, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration) *cobra.Command {
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
// the function itself with the specific parameters of each sub command.
// Please note that specific parameter should be passed as value, while other parameters - passed as reference -
// are shared between sub commands and gets access to current value e.g. flags value.
func getSANDescription(certSpec *certsphase.KubeadmCert) string {
//Defaulted config we will use to get SAN certs
defaultConfig := &kubeadmapiv1alpha3.InitConfiguration{
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) {
if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
kubeadmutil.CheckErr(err)
kubeadmscheme.Scheme.Default(defaultConfig)
kubeadmscheme.Scheme.Convert(defaultConfig, defaultInternalConfig, nil)
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...
// If we wouldn't set this to something, the code would dynamically look up the version from the internet
// By setting this explicitly for tests workarounds that
if defaultKubernetesVersion != "" {
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)
}
for _, ip := range certConfig.AltNames.IPs {
sans = append(sans, ip.String())
}
return fmt.Sprintf("\n\nDefault SANs are %s", strings.Join(sans, ", "))
}
// 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)
kubeadmutil.CheckErr(err)
// Execute the cmdFunc
err = cmdFunc(internalcfg)
err = certsphase.CreateCACertAndKeyFiles(ca, internalcfg)
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 (
"fmt"
"os"
"strings"
"testing"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -146,18 +147,21 @@ func TestSubCmdCertsCreateFilesWithFlags(t *testing.T) {
}
for _, test := range tests {
// Create temp folder for the test case
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
t.Run(strings.Join(test.subCmds, ","), func(t *testing.T) {
// Create temp folder for the test case
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
// executes given sub commands
for _, subCmdName := range test.subCmds {
certDirFlag := fmt.Sprintf("--cert-dir=%s", tmpdir)
cmdtestutil.RunSubCommand(t, subCmds, subCmdName, certDirFlag)
}
// executes given sub commands
for _, subCmdName := range test.subCmds {
fmt.Printf("running command %q\n", subCmdName)
certDirFlag := fmt.Sprintf("--cert-dir=%s", tmpdir)
cmdtestutil.RunSubCommand(t, subCmds, subCmdName, certDirFlag)
}
// verify expected files are there
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
// verify expected files are there
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
})
}
}
@ -226,8 +230,12 @@ func TestSubCmdCertsCreateFilesWithConfigFile(t *testing.T) {
},
},
{
subCmds: []string{"ca", "apiserver", "apiserver-kubelet-client"},
expectedFiles: []string{kubeadmconstants.CACertName, kubeadmconstants.CAKeyName, kubeadmconstants.APIServerCertName, kubeadmconstants.APIServerKeyName, kubeadmconstants.APIServerKubeletClientCertName, kubeadmconstants.APIServerKubeletClientKeyName},
subCmds: []string{"ca", "apiserver", "apiserver-kubelet-client"},
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"},
@ -250,26 +258,28 @@ func TestSubCmdCertsCreateFilesWithConfigFile(t *testing.T) {
}
for _, test := range tests {
// Create temp folder for the test case
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
t.Run(strings.Join(test.subCmds, ","), func(t *testing.T) {
// Create temp folder for the test case
certdir := tmpdir
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
cfg := &kubeadmapi.InitConfiguration{
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
CertificatesDir: certdir,
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
}
configPath := testutil.SetupInitConfigurationFile(t, tmpdir, cfg)
cfg := &kubeadmapi.InitConfiguration{
API: kubeadmapi.API{AdvertiseAddress: "1.2.3.4", BindPort: 1234},
CertificatesDir: tmpdir,
NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"},
}
configPath := testutil.SetupInitConfigurationFile(t, tmpdir, cfg)
// executes given sub commands
for _, subCmdName := range test.subCmds {
configFlag := fmt.Sprintf("--config=%s", configPath)
cmdtestutil.RunSubCommand(t, subCmds, subCmdName, configFlag)
}
// executes given sub commands
for _, subCmdName := range test.subCmds {
t.Logf("running subcommand %q", subCmdName)
configFlag := fmt.Sprintf("--config=%s", configPath)
cmdtestutil.RunSubCommand(t, subCmds, subCmdName, configFlag)
}
// verify expected files are there
testutil.AssertFileExists(t, tmpdir, test.expectedFiles...)
// verify expected files are there
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.
type KubeadmCert struct {
Name string
LongName string
BaseName string
CAName string
// 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 {
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 {
return err
}
writeCertificateAuthorithyFilesIfNotExist(
writeCertificateFilesIfNotExist(
ic.CertificatesDir,
k.BaseName,
caCert,
cert,
key,
)
@ -71,14 +73,42 @@ func (k *KubeadmCert) CreateFromCA(ic *kubeadmapi.InitConfiguration, caCert *x50
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.
type CertificateTree map[*KubeadmCert]Certificates
// CreateTree creates the CAs, certs signed by the CAs, and writes them all to disk.
func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
for ca, leaves := range t {
// TODO: NewCACertAndKey should take an ic
caCert, caKey, err := NewCACertAndKey()
cfg, err := ca.GetConfig(ic)
if err != nil {
return err
}
caCert, caKey, err := NewCACertAndKey(cfg)
if err != nil {
return err
}
@ -89,12 +119,13 @@ func (t CertificateTree) CreateTree(ic *kubeadmapi.InitConfiguration) error {
}
}
if err := writeCertificateAuthorithyFilesIfNotExist(
err = writeCertificateAuthorithyFilesIfNotExist(
ic.CertificatesDir,
ca.BaseName,
caCert,
caKey,
); err != nil {
)
if err != nil {
return err
}
}
@ -171,7 +202,8 @@ func GetCertsWithoutEtcd() Certificates {
var (
// KubeadmCertRootCA is the definition of the Kubernetes Root CA for the API Server and kubelet.
KubeadmCertRootCA = KubeadmCert{
Name: "root-ca",
Name: "ca",
LongName: "self-signed kubernetes CA to provision identities for other kuberenets components",
BaseName: kubeadmconstants.CACertAndKeyBaseName,
config: certutil.Config{
CommonName: "kubernetes",
@ -179,9 +211,10 @@ var (
}
// KubeadmCertAPIServer is the definition of the cert used to serve the kubernetes API.
KubeadmCertAPIServer = KubeadmCert{
Name: "api-server",
Name: "apiserver",
LongName: "certificate for serving the kubernetes API",
BaseName: kubeadmconstants.APIServerCertAndKeyBaseName,
CAName: "root-ca",
CAName: "ca",
config: certutil.Config{
CommonName: kubeadmconstants.APIServerCertCommonName,
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 = KubeadmCert{
Name: "api-server-kubelet-client",
Name: "apiserver-kubelet-client",
LongName: "Client certificate for the API server to connect to kubelet",
BaseName: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
CAName: "root-ca",
CAName: "ca",
config: certutil.Config{
CommonName: kubeadmconstants.APIServerKubeletClientCertCommonName,
Organization: []string{kubeadmconstants.MastersGroup},
@ -205,6 +239,7 @@ var (
// KubeadmCertFrontProxyCA is the definition of the CA used for the front end proxy.
KubeadmCertFrontProxyCA = KubeadmCert{
Name: "front-proxy-ca",
LongName: "self-signed CA to provision identities for front proxy",
BaseName: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
config: certutil.Config{
CommonName: "front-proxy-ca",
@ -215,6 +250,7 @@ var (
KubeadmCertFrontProxyClient = KubeadmCert{
Name: "front-proxy-client",
BaseName: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
LongName: "client for the front proxy",
CAName: "front-proxy-ca",
config: certutil.Config{
CommonName: kubeadmconstants.FrontProxyClientCertCommonName,
@ -225,6 +261,7 @@ var (
// KubeadmCertEtcdCA is the definition of the root CA used by the hosted etcd server.
KubeadmCertEtcdCA = KubeadmCert{
Name: "etcd-ca",
LongName: "self-signed CA to provision identities for etcd",
BaseName: kubeadmconstants.EtcdCACertAndKeyBaseName,
config: certutil.Config{
CommonName: "etcd-ca",
@ -233,6 +270,7 @@ var (
// KubeadmCertEtcdServer is the definition of the cert used to serve etcd to clients.
KubeadmCertEtcdServer = KubeadmCert{
Name: "etcd-server",
LongName: "certificate for serving etcd",
BaseName: kubeadmconstants.EtcdServerCertAndKeyBaseName,
CAName: "etcd-ca",
config: certutil.Config{
@ -250,6 +288,7 @@ var (
// KubeadmCertEtcdPeer is the definition of the cert used by etcd peers to access each other.
KubeadmCertEtcdPeer = KubeadmCert{
Name: "etcd-peer",
LongName: "credentials for etcd nodes to communicate with each other",
BaseName: kubeadmconstants.EtcdPeerCertAndKeyBaseName,
CAName: "etcd-ca",
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 = KubeadmCert{
Name: "etcd-healthcheck",
Name: "etcd-healthcheck-client",
LongName: "client certificate for liveness probes to healtcheck etcd",
BaseName: kubeadmconstants.EtcdHealthcheckClientCertAndKeyBaseName,
CAName: "etcd-ca",
config: certutil.Config{
@ -273,7 +313,8 @@ var (
}
// KubeadmCertEtcdAPIClient is the definition of the cert used by the API server to access etcd.
KubeadmCertEtcdAPIClient = KubeadmCert{
Name: "etcd-api-client",
Name: "apiserver-etcd-client",
LongName: "client apiserver uses to access etcd",
BaseName: kubeadmconstants.APIServerEtcdClientCertAndKeyBaseName,
CAName: "etcd-ca",
config: certutil.Config{
@ -288,7 +329,7 @@ func makeAltNamesMutator(f func(*kubeadmapi.InitConfiguration) (*certutil.AltNam
return func(mc *kubeadmapi.InitConfiguration, cc *certutil.Config) error {
altNames, err := f(mc)
if err != nil {
return nil
return err
}
cc.AltNames = *altNames
return nil

View File

@ -66,186 +66,6 @@ func CreatePKIAssets(cfg *kubeadmapi.InitConfiguration) error {
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.
// 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 {
@ -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.
func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) {
// The key does NOT exist, let's generate it now
saSigningKey, err := certutil.NewPrivateKey()
if err != nil {
@ -383,23 +93,71 @@ func NewServiceAccountSigningKey() (*rsa.PrivateKey, error) {
return saSigningKey, nil
}
// NewFrontProxyCACertAndKey generate a self signed front proxy CA.
func NewFrontProxyCACertAndKey() (*x509.Certificate, *rsa.PrivateKey, error) {
// NewCACertAndKey will generate a self signed CA.
func NewCACertAndKey(certSpec *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
frontProxyCACert, frontProxyCAKey, err := pkiutil.NewCertificateAuthority()
caCert, caKey, err := pkiutil.NewCertificateAuthority(certSpec)
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.
func NewFrontProxyClientCertAndKey(cfg *kubeadmapi.InitConfiguration, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
return newCertAndKeyFromSpec(&KubeadmCertFrontProxyClient, cfg, caCert, caKey)
// CreateCACertAndKeyFiles generates and writes out a given certificate authority.
// The certSpec should be one of the variables from this package.
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) {
// Checks if certificate authority exists in the PKI directory
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.
// 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.
func writeCertificateAuthorithyFilesIfNotExist(pkiDir string, baseName string, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {

View File

@ -20,11 +20,12 @@ import (
"crypto/rsa"
"crypto/x509"
"fmt"
"net"
"os"
"path"
"path/filepath"
"testing"
certutil "k8s.io/client-go/util/cert"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
@ -32,10 +33,30 @@ import (
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()
caCert, caKey, _ := NewCACertAndKey()
func createTestCert(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey) {
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 {
setupFunc func(pkiDir string) error
@ -60,7 +81,7 @@ func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
},
{ // cert exists, but it is not a ca > err
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)
},
expectedError: true,
@ -110,9 +131,9 @@ func TestWriteCertificateAuthorithyFilesIfNotExist(t *testing.T) {
func TestWriteCertificateFilesIfNotExist(t *testing.T) {
caCert, caKey, _ := NewFrontProxyCACertAndKey()
setupCert, setupKey, _ := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, caCert, caKey)
cert, key, _ := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, caCert, caKey)
caCert, caKey := createCACert(t)
setupCert, setupKey := createTestCert(t, caCert, caKey)
cert, key := createTestCert(t, caCert, caKey)
var tests = []struct {
setupFunc func(pkiDir string) error
@ -137,8 +158,8 @@ func TestWriteCertificateFilesIfNotExist(t *testing.T) {
},
{ // cert exists, is signed by another ca > err
setupFunc: func(pkiDir string) error {
anotherCaCert, anotherCaKey, _ := NewFrontProxyCACertAndKey()
anotherCert, anotherKey, _ := NewFrontProxyClientCertAndKey(&kubeadmapi.InitConfiguration{}, anotherCaCert, anotherCaKey)
anotherCaCert, anotherCaKey := createCACert(t)
anotherCert, anotherKey := createTestCert(t, anotherCaCert, anotherCaKey)
return writeCertificateFilesIfNotExist(pkiDir, "dummy", anotherCaCert, anotherCert, anotherKey)
},
@ -259,7 +280,8 @@ func TestWriteKeyFilesIfNotExist(t *testing.T) {
}
func TestNewCACertAndKey(t *testing.T) {
caCert, _, err := NewCACertAndKey()
certCfg := &certutil.Config{CommonName: "kubernetes"}
caCert, _, err := NewCACertAndKey(certCfg)
if err != nil {
t.Fatalf("failed call NewCACertAndKey: %v", err)
}
@ -267,269 +289,90 @@ func TestNewCACertAndKey(t *testing.T) {
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) {
caCert, caKey := createCACert(t)
_, key := createTestCert(t, caCert, caKey)
publicKey := &key.PublicKey
var tests = []struct {
setupFunc func(cfg *kubeadmapi.InitConfiguration)
name string
files pkiFiles
expectedError bool
}{
{ // expected certs exist, pass
setupFunc: func(cfg *kubeadmapi.InitConfiguration) {
CreateCACertAndKeyFiles(cfg)
CreateServiceAccountKeyAndPublicKeyFiles(cfg)
CreateFrontProxyCACertAndKeyFiles(cfg)
{
name: "success",
files: pkiFiles{
"ca.crt": caCert,
"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) {
// start from the condition created by the previous tests
os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.CACertName))
{
name: "missing ca.crt",
files: pkiFiles{
"ca.key": caKey,
"front-proxy-ca.crt": caCert,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
"sa.key": key,
},
expectedError: true,
},
{ // expected sa.key missing
setupFunc: func(cfg *kubeadmapi.InitConfiguration) {
// start from the condition created by the previous tests
CreateCACertAndKeyFiles(cfg)
os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName))
{
name: "missing sa.key",
files: pkiFiles{
"ca.crt": caCert,
"ca.key": caKey,
"front-proxy-ca.crt": caCert,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
},
expectedError: true,
},
{ // expected front-proxy.crt missing
setupFunc: func(cfg *kubeadmapi.InitConfiguration) {
// start from the condition created by the previous tests
CreateServiceAccountKeyAndPublicKeyFiles(cfg)
os.Remove(filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyCACertName))
{
name: "expected front-proxy.crt missing",
files: pkiFiles{
"ca.crt": caCert,
"ca.key": caKey,
"front-proxy-ca.key": caKey,
"sa.pub": publicKey,
"sa.key": key,
},
expectedError: true,
},
}
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
cfg := &kubeadmapi.InitConfiguration{
CertificatesDir: tmpdir,
}
for _, test := range tests {
// executes setup func (if necessary)
if test.setupFunc != nil {
test.setupFunc(cfg)
}
t.Run("", func(t *testing.T) {
tmpdir := testutil.SetupTempDir(t)
defer os.RemoveAll(tmpdir)
// executes create func
ret, err := SharedCertificateExists(cfg)
cfg := &kubeadmapi.InitConfiguration{
CertificatesDir: tmpdir,
}
if !test.expectedError && err != nil {
t.Errorf("error SharedCertificateExists failed when not expected to fail: %v", err)
continue
} else if test.expectedError && err == nil {
t.Error("error SharedCertificateExists didn't failed when expected")
continue
} else if test.expectedError {
continue
}
// created expected keys
writePKIFiles(t, tmpdir, test.files)
if ret != (err == nil) {
t.Errorf("error SharedCertificateExists returned %v when expected to return %v", ret, err == nil)
}
// executes create func
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) {
tests := []struct {
setupFuncs []func(cfg *kubeadmapi.InitConfiguration) error
expected bool
@ -575,17 +418,20 @@ func TestUsingExternalCA(t *testing.T) {
func TestValidateMethods(t *testing.T) {
caCert, caKey := createCACert(t)
cert, key := createTestCert(t, caCert, caKey)
tests := []struct {
name string
setupFuncs []func(cfg *kubeadmapi.InitConfiguration) error
files pkiFiles
validateFunc func(l certKeyLocation) error
loc certKeyLocation
expectedSuccess bool
}{
{
name: "validateCACert",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
CreateCACertAndKeyFiles,
files: pkiFiles{
"ca.crt": caCert,
},
validateFunc: validateCACert,
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
@ -593,28 +439,30 @@ func TestValidateMethods(t *testing.T) {
},
{
name: "validateCACertAndKey (files present)",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
CreateCACertAndKeyFiles,
files: pkiFiles{
"ca.crt": caCert,
"ca.key": caKey,
},
validateFunc: validateCACertAndKey,
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
expectedSuccess: true,
},
{
name: "validateCACertAndKey (key missing)",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
CreatePKIAssets,
deleteCAKey,
files: pkiFiles{
"ca.crt": caCert,
},
name: "validateCACertAndKey (key missing)",
validateFunc: validateCACertAndKey,
loc: certKeyLocation{caBaseName: "ca", baseName: "", uxName: "CA"},
expectedSuccess: false,
},
{
name: "validateSignedCert",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
CreateCACertAndKeyFiles,
CreateAPIServerCertAndKeyFiles,
files: pkiFiles{
"ca.crt": caCert,
"ca.key": caKey,
"apiserver.crt": cert,
"apiserver.key": key,
},
validateFunc: validateSignedCert,
loc: certKeyLocation{caBaseName: "ca", baseName: "apiserver", uxName: "apiserver"},
@ -622,8 +470,9 @@ func TestValidateMethods(t *testing.T) {
},
{
name: "validatePrivatePublicKey",
setupFuncs: []func(cfg *kubeadmapi.InitConfiguration) error{
CreateServiceAccountKeyAndPublicKeyFiles,
files: pkiFiles{
"sa.pub": &key.PublicKey,
"sa.key": key,
},
validateFunc: validatePrivatePublicKey,
loc: certKeyLocation{baseName: "sa", uxName: "service account"},
@ -632,25 +481,11 @@ func TestValidateMethods(t *testing.T) {
}
for _, test := range tests {
dir := testutil.SetupTempDir(t)
defer os.RemoveAll(dir)
test.loc.pkiDir = dir
cfg := &kubeadmapi.InitConfiguration{
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)
}
}
writePKIFiles(t, dir, test.files)
err := test.validateFunc(test.loc)
if test.expectedSuccess && err != nil {
@ -661,18 +496,29 @@ func TestValidateMethods(t *testing.T) {
}
}
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
}
type pkiFiles map[string]interface{}
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)
func writePKIFiles(t *testing.T, dir string, files pkiFiles) {
for filename, body := range files {
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) {
@ -711,57 +557,6 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
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 {
@ -785,14 +580,6 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
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
if err := test.createFunc(cfg); err != nil {
t.Errorf("error executing createFunc: %v", err)
@ -803,3 +590,17 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
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
func NewCertificateAuthority() (*x509.Certificate, *rsa.PrivateKey, error) {
func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
key, err := certutil.NewPrivateKey()
if err != nil {
return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
}
config := certutil.Config{
CommonName: "kubernetes",
}
cert, err := certutil.NewSelfSignedCACert(config, key)
cert, err := certutil.NewSelfSignedCACert(*config, key)
if err != nil {
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
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()
if err != nil {
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 {
return nil, nil, fmt.Errorf("unable to sign certificate [%v]", err)
}

View File

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

View File

@ -27,7 +27,6 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
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"
)
@ -148,23 +147,21 @@ func TestShouldBackupAPIServerCertAndKey(t *testing.T) {
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 {
t.Fatalf("failed creation of ca cert and key: %v", err)
}
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 {
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)}
for _, path := range certAndKey {
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
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)
}
}
if component == constants.Etcd {
if err := certsphase.CreateEtcdServerCertAndKeyFiles(cfg); err != nil {
return fmt.Errorf("failed to upgrade the %s certificate and key: %v", constants.Etcd, err)
if component == constants.Etcd {
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)
}
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 {
return fmt.Errorf("failed to upgrade the %s peer certificate and key: %v", 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)
if component == constants.KubeAPIServer {
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)
}
}
}

View File

@ -420,27 +420,16 @@ func TestStaticPodControlPlane(t *testing.T) {
t.Fatalf("couldn't create config: %v", err)
}
// Initialize PKI minus any etcd certificates to simulate etcd PKI upgrade
certActions := []func(cfg *kubeadmapi.InitConfiguration) error{
certsphase.CreateCACertAndKeyFiles,
certsphase.CreateAPIServerCertAndKeyFiles,
certsphase.CreateAPIServerKubeletClientCertAndKeyFiles,
// certsphase.CreateEtcdCACertAndKeyFiles,
// certsphase.CreateEtcdServerCertAndKeyFiles,
// certsphase.CreateEtcdPeerCertAndKeyFiles,
// certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles,
// certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
certsphase.CreateServiceAccountKeyAndPublicKeyFiles,
certsphase.CreateFrontProxyCACertAndKeyFiles,
certsphase.CreateFrontProxyClientCertAndKeyFiles,
tree, err := certsphase.GetCertsWithoutEtcd().AsMap().CertTree()
if err != nil {
t.Fatalf("couldn't get cert tree: %v", err)
}
for _, action := range certActions {
err := action(oldcfg)
if err != nil {
t.Fatalf("couldn't initialize pre-upgrade certificate: %v", err)
}
if err := tree.CreateTree(oldcfg); err != nil {
t.Fatalf("couldn't get create cert tree: %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
err = controlplanephase.CreateInitStaticPodManifestFiles(pathMgr.RealManifestDir(), oldcfg)

View File

@ -9,7 +9,10 @@ go_library(
name = "go_default_library",
srcs = ["util.go"],
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(

View File

@ -22,13 +22,14 @@ import (
"net"
"testing"
certutil "k8s.io/client-go/util/cert"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
)
// SetupCertificateAuthorithy is a utility function for kubeadm testing that creates a
// CertificateAuthorithy cert/key pair
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 {
t.Fatalf("failure while generating CA certificate and key: %v", err)
}