From affdf829a33f1326d2c10aa5682a14f895cb552e Mon Sep 17 00:00:00 2001 From: deads2k Date: Wed, 15 Feb 2017 10:47:58 -0500 Subject: [PATCH] add front proxy to kubeadm created kube-apiservers --- cmd/kubeadm/app/constants/constants.go | 8 +++ cmd/kubeadm/app/master/manifests.go | 7 +++ cmd/kubeadm/app/master/manifests_test.go | 15 ++++++ cmd/kubeadm/app/phases/certs/certs.go | 65 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+) diff --git a/cmd/kubeadm/app/constants/constants.go b/cmd/kubeadm/app/constants/constants.go index 05e6754bae5..9bd11b3baf5 100644 --- a/cmd/kubeadm/app/constants/constants.go +++ b/cmd/kubeadm/app/constants/constants.go @@ -35,6 +35,14 @@ const ( ServiceAccountPublicKeyName = "sa.pub" ServiceAccountPrivateKeyName = "sa.key" + FrontProxyCACertAndKeyBaseName = "front-proxy-ca" + FrontProxyCACertName = "front-proxy-ca.crt" + FrontProxyCAKeyName = "front-proxy-ca.key" + + FrontProxyClientCertAndKeyBaseName = "front-proxy-client" + FrontProxyClientCertName = "front-proxy-client.crt" + FrontProxyClientKeyName = "front-proxy-client.key" + // TODO: These constants should actually come from pkg/kubeapiserver/authorizer, but we can't vendor that package in now // because of all the other sub-packages that would get vendored. To fix this, a pkg/kubeapiserver/authorizer/modes package // or similar should exist that only has these constants; then we can vendor it. diff --git a/cmd/kubeadm/app/master/manifests.go b/cmd/kubeadm/app/master/manifests.go index 7632eabc900..ad6717e9299 100644 --- a/cmd/kubeadm/app/master/manifests.go +++ b/cmd/kubeadm/app/master/manifests.go @@ -320,6 +320,13 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, selfHosted bool) [ "--allow-privileged", "--storage-backend=etcd3", "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", + // add options to configure the front proxy. Without the generated client cert, this will never be useable + // so add it unconditionally with recommended values + "--requestheader-username-headers=X-Remote-User", + "--requestheader-group-headers=X-Remote-Group", + "--requestheader-extra-headers-prefix=X-Remote-Extra-", + "--requestheader-client-ca-file="+getCertFilePath(kubeadmconstants.FrontProxyCACertName), + "--requestheader-allowed-names=front-proxy-client", ) if cfg.AuthorizationMode != "" { diff --git a/cmd/kubeadm/app/master/manifests_test.go b/cmd/kubeadm/app/master/manifests_test.go index c8bf75932c4..7b9d9d5625b 100644 --- a/cmd/kubeadm/app/master/manifests_test.go +++ b/cmd/kubeadm/app/master/manifests_test.go @@ -383,6 +383,11 @@ func TestGetAPIServerCommand(t *testing.T) { "--allow-privileged", "--storage-backend=etcd3", "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", + "--requestheader-username-headers=X-Remote-User", + "--requestheader-group-headers=X-Remote-Group", + "--requestheader-extra-headers-prefix=X-Remote-Extra-", + "--requestheader-client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/front-proxy-ca.crt", + "--requestheader-allowed-names=front-proxy-client", "--etcd-servers=http://127.0.0.1:2379", }, }, @@ -407,6 +412,11 @@ func TestGetAPIServerCommand(t *testing.T) { "--allow-privileged", "--storage-backend=etcd3", "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", + "--requestheader-username-headers=X-Remote-User", + "--requestheader-group-headers=X-Remote-Group", + "--requestheader-extra-headers-prefix=X-Remote-Extra-", + "--requestheader-client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/front-proxy-ca.crt", + "--requestheader-allowed-names=front-proxy-client", "--advertise-address=foo", "--etcd-servers=http://127.0.0.1:2379", }, @@ -433,6 +443,11 @@ func TestGetAPIServerCommand(t *testing.T) { "--allow-privileged", "--storage-backend=etcd3", "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", + "--requestheader-username-headers=X-Remote-User", + "--requestheader-group-headers=X-Remote-Group", + "--requestheader-extra-headers-prefix=X-Remote-Extra-", + "--requestheader-client-ca-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/front-proxy-ca.crt", + "--requestheader-allowed-names=front-proxy-client", "--etcd-servers=http://127.0.0.1:2379", "--etcd-certfile=fiz", "--etcd-keyfile=faz", diff --git a/cmd/kubeadm/app/phases/certs/certs.go b/cmd/kubeadm/app/phases/certs/certs.go index c5271b6999d..abba646d459 100644 --- a/cmd/kubeadm/app/phases/certs/certs.go +++ b/cmd/kubeadm/app/phases/certs/certs.go @@ -192,6 +192,71 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration, pkiDir string) error { fmt.Println("[certificates] Generated service account token signing public key.") } + // front proxy CA and client certs are used to secure a front proxy authenticator which is used to assert identity + // without the client cert, you cannot make use of the front proxy and the kube-aggregator uses this connection + // so we generate and enable it unconditionally + // This is a separte CA, so that front proxy identities cannot hit the API and normal client certs cannot be used + // as front proxies. + var frontProxyCACert *x509.Certificate + var frontProxyCAKey *rsa.PrivateKey + // 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.FrontProxyCACertAndKeyBaseName) { + // Try to load front-proxy-ca.crt and front-proxy-ca.key from the PKI directory + frontProxyCACert, frontProxyCAKey, err = pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName) + if err != nil || frontProxyCACert == nil || frontProxyCAKey == nil { + return fmt.Errorf("certificate and/or key existed but they could not be loaded properly") + } + + // The certificate and key could be loaded, but the certificate is not a CA + if !frontProxyCACert.IsCA { + return fmt.Errorf("certificate and key could be loaded but the certificate is not a CA") + } + + fmt.Println("[certificates] Using the existing front-proxy CA certificate and key.") + } else { + // The certificate and the key did NOT exist, let's generate them now + frontProxyCACert, frontProxyCAKey, err = pkiutil.NewCertificateAuthority() + if err != nil { + return fmt.Errorf("failure while generating front-proxy CA certificate and key [%v]", err) + } + + if err = pkiutil.WriteCertAndKey(pkiDir, kubeadmconstants.FrontProxyCACertAndKeyBaseName, frontProxyCACert, frontProxyCAKey); err != nil { + return fmt.Errorf("failure while saving front-proxy CA certificate and key [%v]", err) + } + fmt.Println("[certificates] Generated front-proxy CA certificate and key.") + } + + // At this point we have a front proxy CA signing key. We can use that create the front proxy client cert if + // it doesn't already exist. + // 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.FrontProxyClientCertAndKeyBaseName) { + // Try to load apiserver-kubelet-client.crt and apiserver-kubelet-client.key from the PKI directory + apiCert, apiKey, err := pkiutil.TryLoadCertAndKeyFromDisk(pkiDir, kubeadmconstants.FrontProxyClientCertAndKeyBaseName) + 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 front-proxy 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: "front-proxy-client", + Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, + } + apiClientCert, apiClientKey, err := pkiutil.NewCertAndKey(frontProxyCACert, frontProxyCAKey, config) + if err != nil { + return fmt.Errorf("failure while creating front-proxy client key and certificate [%v]", err) + } + + if err = pkiutil.WriteCertAndKey(pkiDir, kubeadmconstants.FrontProxyClientCertAndKeyBaseName, apiClientCert, apiClientKey); err != nil { + return fmt.Errorf("failure while saving front-proxy client certificate and key [%v]", err) + } + fmt.Println("[certificates] Generated front-proxy client certificate and key.") + } + fmt.Printf("[certificates] Valid certificates and keys now exist in %q\n", pkiDir) return nil