Merge pull request #40316 from luxas/kubeadm_fix_apiserver_certs

Automatic merge from submit-queue (batch tested with PRs 40303, 40316)

kubeadm: Fix up the apiserver kubelet client cert

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

I didn't notice that the apiserver serving cert was _only_ a server cert, not both a server and client cert in https://github.com/kubernetes/kubernetes/pull/40292.

This PR fixes that misconception and generates a dedicated client cert for apiserver -> kubelet communication and harmonizes the `ca.crt` path to `/etc/kubernetes/pki/ca.crt` on both master and node.

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #

**Special notes for your reviewer**:

```console
$ systemctl cat kubelet
# /lib/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=http://kubernetes.io/docs/

[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--kubeconfig=/etc/kubernetes/kubelet.conf **--authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt** --require-kubeconfig=true"
Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true"
Environment="KUBELET_NETWORK_ARGS=--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin"
Environment="KUBELET_DNS_ARGS=--cluster-dns=10.96.0.10 --cluster-domain=cluster.local"
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_SYSTEM_PODS_ARGS $KUBELET_NETWORK_ARGS $KUBELET_DNS_ARGS $KUBELET_EXTRA_ARGS


$ curl -k https://localhost:10250/containerLogs/kube-system/weave-net-arm64-4t2xv/weave
Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy)
$ curl --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt --key /etc/kubernetes/pki/apiserver-kubelet-client.key -k https://localhost:10250/containerLogs/kube-system/weave-net-arm64-4t2xv/weave
[Works!!]
```

**Release note**:

```release-note
NONE
```

@liggitt @deads2k
This commit is contained in:
Kubernetes Submit Queue 2017-01-24 01:57:11 -08:00 committed by GitHub
commit 0fac54e65e
5 changed files with 46 additions and 15 deletions

View File

@ -146,7 +146,7 @@ func (j *Join) Run(out io.Writer) error {
// Write the ca certificate to disk so kubelet can use it for authentication
cluster := cfg.Contexts[cfg.CurrentContext].Cluster
caCertFile := filepath.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeadmconstants.CACertName)
caCertFile := filepath.Join(kubeadmapi.GlobalEnvParams.HostPKIPath, kubeadmconstants.CACertName)
err = certutil.WriteCert(caCertFile, cfg.Clusters[cluster].CertificateAuthorityData)
if err != nil {
return fmt.Errorf("couldn't save the CA certificate to disk: %v", err)

View File

@ -24,4 +24,8 @@ const (
APIServerCertAndKeyBaseName = "apiserver"
APIServerCertName = "apiserver.crt"
APIServerKeyName = "apiserver.key"
APIServerKubeletClientCertAndKeyBaseName = "apiserver-kubelet-client"
APIServerKubeletClientCertName = "apiserver-kubelet-client.crt"
APIServerKubeletClientKeyName = "apiserver-kubelet-client.key"
)

View File

@ -322,8 +322,8 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, selfHosted bool) [
"--client-ca-file="+getCertFilePath(kubeadmconstants.CACertName),
"--tls-cert-file="+getCertFilePath(kubeadmconstants.APIServerCertName),
"--tls-private-key-file="+getCertFilePath(kubeadmconstants.APIServerKeyName),
"--kubelet-client-certificate="+getCertFilePath(kubeadmconstants.APIServerCertName),
"--kubelet-client-key="+getCertFilePath(kubeadmconstants.APIServerKeyName),
"--kubelet-client-certificate="+getCertFilePath(kubeadmconstants.APIServerKubeletClientCertName),
"--kubelet-client-key="+getCertFilePath(kubeadmconstants.APIServerKubeletClientKeyName),
"--token-auth-file="+kubeadmapi.GlobalEnvParams.HostPKIPath+"/tokens.csv",
fmt.Sprintf("--secure-port=%d", cfg.API.Port),
"--allow-privileged",

View File

@ -376,8 +376,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
"--tls-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--tls-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.key",
"--token-auth-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/tokens.csv",
fmt.Sprintf("--secure-port=%d", 123),
"--allow-privileged",
@ -399,8 +399,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
"--tls-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--tls-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.key",
"--token-auth-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/tokens.csv",
fmt.Sprintf("--secure-port=%d", 123),
"--allow-privileged",
@ -424,8 +424,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
"--tls-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--tls-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.key",
"--token-auth-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/tokens.csv",
fmt.Sprintf("--secure-port=%d", 123),
"--allow-privileged",
@ -451,8 +451,8 @@ func TestGetAPIServerCommand(t *testing.T) {
"--client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.crt",
"--tls-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--tls-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver.key",
"--kubelet-client-certificate=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.crt",
"--kubelet-client-key=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-kubelet-client.key",
"--token-auth-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/tokens.csv",
fmt.Sprintf("--secure-port=%d", 123),
"--allow-privileged",

View File

@ -110,7 +110,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
// If at least one of them exists, we should try to load them
// In the case that only one exists, there will most likely be an error anyway
if pkiutil.CertOrKeyExist(pkiDir, kubeadmconstants.APIServerCertAndKeyBaseName) {
// Try to load ca.crt and ca.key from the PKI directory
// Try to load apiserver.crt and apiserver.key from the PKI directory
apiCert, apiKey, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, kubeadmconstants.APIServerCertAndKeyBaseName)
if err != nil || apiCert == nil || apiKey == nil {
return fmt.Errorf("certificate and/or key existed but they could not be loaded properly")
@ -123,9 +123,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
config := certutil.Config{
CommonName: "kube-apiserver",
AltNames: altNames,
// This makes the apiserver allowed to talk to the kubelets in the cluster
Organization: []string{"system:masters"},
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
apiCert, apiKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
if err != nil {
@ -138,6 +136,35 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error {
fmt.Println("[certificates] Generated API server certificate and key.")
}
// If at least one of them exists, we should try to load them
// In the case that only one exists, there will most likely be an error anyway
if pkiutil.CertOrKeyExist(pkiDir, kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName) {
// Try to load apiserver-kubelet-client.crt and apiserver-kubelet-client.key from the PKI directory
apiCert, apiKey, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName)
if err != nil || apiCert == nil || apiKey == nil {
return fmt.Errorf("certificate and/or key existed but they could not be loaded properly")
}
fmt.Println("[certificates] Using the existing API Server kubelet client certificate and key.")
} else {
// The certificate and the key did NOT exist, let's generate them now
// TODO: Add a test case to verify that this cert has the x509.ExtKeyUsageClientAuth flag
config := certutil.Config{
CommonName: "kube-apiserver-kubelet-client",
Organization: []string{"system:masters"},
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
apiClientCert, apiClientKey, err := pkiutil.NewCertAndKey(caCert, caKey, config)
if err != nil {
return fmt.Errorf("failure while creating API server kubelet client key and certificate [%v]", err)
}
if err = pkiutil.WriteCertAndKey(pkiDir, kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName, apiClientCert, apiClientKey); err != nil {
return fmt.Errorf("failure while saving API server kubelet client certificate and key [%v]", err)
}
fmt.Println("[certificates] Generated API server kubelet client certificate and key.")
}
fmt.Printf("[certificates] Valid certificates and keys now exist in %q\n", pkiDir)
return nil