Generate client certificates for healthchecking kubeadm etcd static pods

Add new phase command: `certs etcd-healthcheck`
Certs are placed at /etc/kubernetes/pki/etcd/healthcheck-client.{crt,key}
pull/6/head
leigh schrandt 2018-03-02 15:25:38 -07:00
parent ae1fc13aee
commit 7a1a3aa3df
11 changed files with 138 additions and 4 deletions

View File

@ -98,6 +98,13 @@ var (
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.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName) `+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(` apiServerEtcdServerCertLongDesc = fmt.Sprintf(normalizer.LongDesc(`
Generates the client certificate for the API server to connect to etcd securely and the respective key, 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. and saves them into %s and %s files.
@ -206,6 +213,12 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
long: etcdPeerCertLongDesc, long: etcdPeerCertLongDesc,
cmdFunc: certsphase.CreateEtcdPeerCertAndKeyFiles, 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", use: "apiserver-etcd-client",
short: "Generates a client certificate for the API server to connect to etcd securely", short: "Generates a client certificate for the API server to connect to etcd securely",

View File

@ -73,6 +73,21 @@ func TestCertsSubCommandsHasFlags(t *testing.T) {
{ {
command: "apiserver-kubelet-client", command: "apiserver-kubelet-client",
}, },
{
command: "etcd-ca",
},
{
command: "etcd-server",
},
{
command: "etcd-peer",
},
{
command: "etcd-healthcheck-client",
},
{
command: "apiserver-etcd-client",
},
{ {
command: "sa", command: "sa",
}, },
@ -113,6 +128,16 @@ func TestSubCmdCertsCreateFilesWithFlags(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"},
expectedFiles: []string{
kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName,
kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName,
kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName,
kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName,
kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName,
},
},
{ {
subCmds: []string{"sa"}, subCmds: []string{"sa"},
expectedFiles: []string{kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName}, expectedFiles: []string{kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName},
@ -204,6 +229,16 @@ 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"},
expectedFiles: []string{
kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName,
kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName,
kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName,
kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName,
kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName,
},
},
{ {
subCmds: []string{"front-proxy-ca", "front-proxy-client"}, subCmds: []string{"front-proxy-ca", "front-proxy-client"},
expectedFiles: []string{kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName, kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName}, expectedFiles: []string{kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName, kubeadmconstants.FrontProxyClientCertName, kubeadmconstants.FrontProxyClientKeyName},

View File

@ -90,13 +90,22 @@ const (
// EtcdPeerCertCommonName defines etcd's peer certificate common name (CN) // EtcdPeerCertCommonName defines etcd's peer certificate common name (CN)
EtcdPeerCertCommonName = "kube-etcd-peer" EtcdPeerCertCommonName = "kube-etcd-peer"
// APIServerEtcdClientCertAndKeyBaseName defines etcd client certificate and key base name // EtcdHealthcheckClientCertAndKeyBaseName defines etcd's healthcheck client certificate and key base name
EtcdHealthcheckClientCertAndKeyBaseName = "etcd/healthcheck-client"
// EtcdHealthcheckClientCertName defines etcd's healthcheck client certificate name
EtcdHealthcheckClientCertName = "etcd/healthcheck-client.crt"
// EtcdHealthcheckClientKeyName defines etcd's healthcheck client key name
EtcdHealthcheckClientKeyName = "etcd/healthcheck-client.key"
// EtcdHealthcheckClientCertCommonName defines etcd's healthcheck client certificate common name (CN)
EtcdHealthcheckClientCertCommonName = "kube-etcd-healthcheck-client"
// APIServerEtcdClientCertAndKeyBaseName defines apiserver's etcd client certificate and key base name
APIServerEtcdClientCertAndKeyBaseName = "apiserver-etcd-client" APIServerEtcdClientCertAndKeyBaseName = "apiserver-etcd-client"
// APIServerEtcdClientCertName defines etcd client certificate name // APIServerEtcdClientCertName defines apiserver's etcd client certificate name
APIServerEtcdClientCertName = "apiserver-etcd-client.crt" APIServerEtcdClientCertName = "apiserver-etcd-client.crt"
// APIServerEtcdClientKeyName defines etcd client key name // APIServerEtcdClientKeyName defines apiserver's etcd client key name
APIServerEtcdClientKeyName = "apiserver-etcd-client.key" APIServerEtcdClientKeyName = "apiserver-etcd-client.key"
// APIServerEtcdClientCertCommonName defines etcd client certificate common name (CN) // APIServerEtcdClientCertCommonName defines apiserver's etcd client certificate common name (CN)
APIServerEtcdClientCertCommonName = "kube-apiserver-etcd-client" APIServerEtcdClientCertCommonName = "kube-apiserver-etcd-client"
// ServiceAccountKeyBaseName defines SA key base name // ServiceAccountKeyBaseName defines SA key base name

View File

@ -40,6 +40,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error {
CreateEtcdCACertAndKeyFiles, CreateEtcdCACertAndKeyFiles,
CreateEtcdServerCertAndKeyFiles, CreateEtcdServerCertAndKeyFiles,
CreateEtcdPeerCertAndKeyFiles, CreateEtcdPeerCertAndKeyFiles,
CreateEtcdHealthcheckClientCertAndKeyFiles,
CreateAPIServerEtcdClientCertAndKeyFiles, CreateAPIServerEtcdClientCertAndKeyFiles,
CreateServiceAccountKeyAndPublicKeyFiles, CreateServiceAccountKeyAndPublicKeyFiles,
CreateFrontProxyCACertAndKeyFiles, CreateFrontProxyCACertAndKeyFiles,
@ -190,6 +191,30 @@ func CreateEtcdPeerCertAndKeyFiles(cfg *kubeadmapi.MasterConfiguration) error {
) )
} }
// 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.MasterConfiguration) error {
etcdCACert, etcdCAKey, err := loadCertificateAuthority(cfg.CertificatesDir, kubeadmconstants.EtcdCACertAndKeyBaseName)
if err != nil {
return err
}
etcdHealthcheckClientCert, etcdHealthcheckClientKey, err := NewEtcdHealthcheckClientCertAndKey(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 // 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. // 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 // It assumes the etcd CA certificate and key file exist in the CertificatesDir
@ -375,6 +400,22 @@ func NewEtcdPeerCertAndKey(cfg *kubeadmapi.MasterConfiguration, caCert *x509.Cer
return etcdPeerCert, etcdPeerKey, nil return etcdPeerCert, etcdPeerKey, nil
} }
// NewEtcdHealthcheckClientCertAndKey generate certificate for liveness probes to healthcheck etcd, signed by the given CA.
func NewEtcdHealthcheckClientCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
config := certutil.Config{
CommonName: kubeadmconstants.EtcdHealthcheckClientCertCommonName,
Organization: []string{kubeadmconstants.MastersGroup},
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
etcdHealcheckClientCert, etcdHealcheckClientKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
if err != nil {
return nil, nil, fmt.Errorf("failure while creating etcd healthcheck client key and certificate: %v", err)
}
return etcdHealcheckClientCert, etcdHealcheckClientKey, nil
}
// NewAPIServerEtcdClientCertAndKey generate certificate for the apiservers to connect to etcd securely, signed by the given CA. // NewAPIServerEtcdClientCertAndKey generate certificate for the apiservers to connect to etcd securely, signed by the given CA.
func NewAPIServerEtcdClientCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) { func NewAPIServerEtcdClientCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {

View File

@ -382,6 +382,22 @@ func TestNewEtcdPeerCertAndKey(t *testing.T) {
} }
} }
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(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) { func TestNewAPIServerEtcdClientCertAndKey(t *testing.T) {
caCert, caKey, err := NewCACertAndKey() caCert, caKey, err := NewCACertAndKey()
if err != nil { if err != nil {
@ -595,6 +611,7 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName, kubeadmconstants.EtcdCACertName, kubeadmconstants.EtcdCAKeyName,
kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName, kubeadmconstants.EtcdServerCertName, kubeadmconstants.EtcdServerKeyName,
kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName, kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName,
kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName,
kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName, kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName,
kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName, kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName,
kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName, kubeadmconstants.FrontProxyCACertName, kubeadmconstants.FrontProxyCAKeyName,
@ -629,6 +646,11 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
createFunc: CreateEtcdPeerCertAndKeyFiles, createFunc: CreateEtcdPeerCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName}, expectedFiles: []string{kubeadmconstants.EtcdPeerCertName, kubeadmconstants.EtcdPeerKeyName},
}, },
{
setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateEtcdHealthcheckClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName},
},
{ {
setupFunc: CreateEtcdCACertAndKeyFiles, setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateAPIServerEtcdClientCertAndKeyFiles, createFunc: CreateAPIServerEtcdClientCertAndKeyFiles,

View File

@ -46,6 +46,8 @@ package certs
- etcd/server.key - etcd/server.key
- etcd/peer.crt - etcd/peer.crt
- etcd/peer.key - etcd/peer.key
- etcd/healthcheck-client.crt
- etcd/healthcheck-client.key
- sa.pub - sa.pub
- sa.key - sa.key
- front-proxy-ca.crt - front-proxy-ca.crt

View File

@ -148,6 +148,9 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP
if err := certsphase.CreateEtcdPeerCertAndKeyFiles(cfg); err != nil { if err := certsphase.CreateEtcdPeerCertAndKeyFiles(cfg); err != nil {
return fmt.Errorf("failed to upgrade the %s peer certificate and key: %v", constants.Etcd, err) 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 component == constants.KubeAPIServer {
if err := certsphase.CreateAPIServerEtcdClientCertAndKeyFiles(cfg); err != nil { if err := certsphase.CreateAPIServerEtcdClientCertAndKeyFiles(cfg); err != nil {

View File

@ -327,6 +327,7 @@ func TestStaticPodControlPlane(t *testing.T) {
// certsphase.CreateEtcdCACertAndKeyFiles, // certsphase.CreateEtcdCACertAndKeyFiles,
// certsphase.CreateEtcdServerCertAndKeyFiles, // certsphase.CreateEtcdServerCertAndKeyFiles,
// certsphase.CreateEtcdPeerCertAndKeyFiles, // certsphase.CreateEtcdPeerCertAndKeyFiles,
// certsphase.CreateEtcdHealthcheckClientCertAndKeyFiles,
// certsphase.CreateAPIServerEtcdClientCertAndKeyFiles, // certsphase.CreateAPIServerEtcdClientCertAndKeyFiles,
certsphase.CreateServiceAccountKeyAndPublicKeyFiles, certsphase.CreateServiceAccountKeyAndPublicKeyFiles,
certsphase.CreateFrontProxyCACertAndKeyFiles, certsphase.CreateFrontProxyCACertAndKeyFiles,

View File

@ -25,6 +25,7 @@ docs/admin/kubeadm_alpha_phase_certs_apiserver-kubelet-client.md
docs/admin/kubeadm_alpha_phase_certs_apiserver.md docs/admin/kubeadm_alpha_phase_certs_apiserver.md
docs/admin/kubeadm_alpha_phase_certs_ca.md docs/admin/kubeadm_alpha_phase_certs_ca.md
docs/admin/kubeadm_alpha_phase_certs_etcd-ca.md docs/admin/kubeadm_alpha_phase_certs_etcd-ca.md
docs/admin/kubeadm_alpha_phase_certs_etcd-healthcheck-client.md
docs/admin/kubeadm_alpha_phase_certs_etcd-peer.md docs/admin/kubeadm_alpha_phase_certs_etcd-peer.md
docs/admin/kubeadm_alpha_phase_certs_etcd-server.md docs/admin/kubeadm_alpha_phase_certs_etcd-server.md
docs/admin/kubeadm_alpha_phase_certs_front-proxy-ca.md docs/admin/kubeadm_alpha_phase_certs_front-proxy-ca.md
@ -92,6 +93,7 @@ docs/man/man1/kubeadm-alpha-phase-certs-apiserver-kubelet-client.1
docs/man/man1/kubeadm-alpha-phase-certs-apiserver.1 docs/man/man1/kubeadm-alpha-phase-certs-apiserver.1
docs/man/man1/kubeadm-alpha-phase-certs-ca.1 docs/man/man1/kubeadm-alpha-phase-certs-ca.1
docs/man/man1/kubeadm-alpha-phase-certs-etcd-ca.1 docs/man/man1/kubeadm-alpha-phase-certs-etcd-ca.1
docs/man/man1/kubeadm-alpha-phase-certs-etcd-healthcheck-client.1
docs/man/man1/kubeadm-alpha-phase-certs-etcd-peer.1 docs/man/man1/kubeadm-alpha-phase-certs-etcd-peer.1
docs/man/man1/kubeadm-alpha-phase-certs-etcd-server.1 docs/man/man1/kubeadm-alpha-phase-certs-etcd-server.1
docs/man/man1/kubeadm-alpha-phase-certs-front-proxy-ca.1 docs/man/man1/kubeadm-alpha-phase-certs-front-proxy-ca.1

View File

@ -0,0 +1,3 @@
This file is autogenerated, but we've stopped checking such files into the
repository to reduce the need for rebases. Please run hack/generate-docs.sh to
populate this file.

View File

@ -0,0 +1,3 @@
This file is autogenerated, but we've stopped checking such files into the
repository to reduce the need for rebases. Please run hack/generate-docs.sh to
populate this file.