Commit 7a1a3aa3 authored by leigh schrandt's avatar leigh schrandt

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}
parent ae1fc13a
...@@ -98,6 +98,13 @@ var ( ...@@ -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.
...@@ -207,6 +214,12 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command { ...@@ -207,6 +214,12 @@ func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
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",
long: apiServerEtcdServerCertLongDesc, long: apiServerEtcdServerCertLongDesc,
......
...@@ -74,6 +74,21 @@ func TestCertsSubCommandsHasFlags(t *testing.T) { ...@@ -74,6 +74,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",
}, },
{ {
...@@ -114,6 +129,16 @@ func TestSubCmdCertsCreateFilesWithFlags(t *testing.T) { ...@@ -114,6 +129,16 @@ func TestSubCmdCertsCreateFilesWithFlags(t *testing.T) {
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},
}, },
...@@ -205,6 +230,16 @@ func TestSubCmdCertsCreateFilesWithConfigFile(t *testing.T) { ...@@ -205,6 +230,16 @@ func TestSubCmdCertsCreateFilesWithConfigFile(t *testing.T) {
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},
}, },
......
...@@ -90,13 +90,22 @@ const ( ...@@ -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
......
...@@ -40,6 +40,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error { ...@@ -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 { ...@@ -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 ...@@ -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) {
......
...@@ -382,6 +382,22 @@ func TestNewEtcdPeerCertAndKey(t *testing.T) { ...@@ -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) { ...@@ -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,
...@@ -631,6 +648,11 @@ func TestCreateCertificateFilesMethods(t *testing.T) { ...@@ -631,6 +648,11 @@ func TestCreateCertificateFilesMethods(t *testing.T) {
}, },
{ {
setupFunc: CreateEtcdCACertAndKeyFiles, setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateEtcdHealthcheckClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.EtcdHealthcheckClientCertName, kubeadmconstants.EtcdHealthcheckClientKeyName},
},
{
setupFunc: CreateEtcdCACertAndKeyFiles,
createFunc: CreateAPIServerEtcdClientCertAndKeyFiles, createFunc: CreateAPIServerEtcdClientCertAndKeyFiles,
expectedFiles: []string{kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName}, expectedFiles: []string{kubeadmconstants.APIServerEtcdClientCertName, kubeadmconstants.APIServerEtcdClientKeyName},
}, },
......
...@@ -46,6 +46,8 @@ package certs ...@@ -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
......
...@@ -148,6 +148,9 @@ func upgradeComponent(component string, waiter apiclient.Waiter, pathMgr StaticP ...@@ -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 {
......
...@@ -327,6 +327,7 @@ func TestStaticPodControlPlane(t *testing.T) { ...@@ -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,
......
...@@ -25,6 +25,7 @@ docs/admin/kubeadm_alpha_phase_certs_apiserver-kubelet-client.md ...@@ -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 ...@@ -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
......
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.
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.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment