2017-11-02 10:07:10 +00:00
|
|
|
package cluster
|
|
|
|
|
|
|
|
import (
|
2018-01-09 22:10:56 +00:00
|
|
|
"context"
|
2017-11-02 10:07:10 +00:00
|
|
|
"crypto/rsa"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
2018-01-16 23:10:14 +00:00
|
|
|
"github.com/rancher/rke/hosts"
|
2017-11-02 10:07:10 +00:00
|
|
|
"github.com/rancher/rke/k8s"
|
2018-01-09 22:10:56 +00:00
|
|
|
"github.com/rancher/rke/log"
|
2017-11-02 10:07:10 +00:00
|
|
|
"github.com/rancher/rke/pki"
|
2017-11-13 21:28:38 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2018-02-01 14:27:28 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
2017-11-02 10:07:10 +00:00
|
|
|
"k8s.io/client-go/kubernetes"
|
|
|
|
"k8s.io/client-go/util/cert"
|
|
|
|
)
|
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
func SetUpAuthentication(ctx context.Context, kubeCluster, currentCluster *Cluster) error {
|
2017-11-14 18:11:21 +00:00
|
|
|
if kubeCluster.Authentication.Strategy == X509AuthenticationProvider {
|
2017-11-02 10:07:10 +00:00
|
|
|
var err error
|
|
|
|
if currentCluster != nil {
|
2017-11-15 02:54:26 +00:00
|
|
|
kubeCluster.Certificates = currentCluster.Certificates
|
2017-11-02 10:07:10 +00:00
|
|
|
} else {
|
2018-02-15 03:25:36 +00:00
|
|
|
var backupHost *hosts.Host
|
|
|
|
if len(kubeCluster.Services.Etcd.ExternalURLs) > 0 {
|
|
|
|
backupHost = kubeCluster.ControlPlaneHosts[0]
|
|
|
|
} else {
|
|
|
|
backupHost = kubeCluster.EtcdHosts[0]
|
|
|
|
}
|
|
|
|
log.Infof(ctx, "[certificates] Attempting to recover certificates from backup on host [%s]", backupHost.Address)
|
|
|
|
kubeCluster.Certificates, err = pki.FetchCertificatesFromHost(ctx, kubeCluster.EtcdHosts, backupHost, kubeCluster.SystemImages.Alpine, kubeCluster.LocalKubeConfigPath, kubeCluster.PrivateRegistriesMap)
|
2018-01-10 23:03:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if kubeCluster.Certificates != nil {
|
2018-02-15 03:25:36 +00:00
|
|
|
log.Infof(ctx, "[certificates] Certificate backup found on host [%s]", backupHost.Address)
|
|
|
|
// this is the case of adding controlplane node on empty cluster with only etcd nodes
|
|
|
|
if kubeCluster.Certificates[pki.KubeAdminCertName].Config == "" && len(kubeCluster.ControlPlaneHosts) > 0 {
|
|
|
|
if err := rebuildLocalAdminConfig(ctx, kubeCluster); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
kubeCluster.Certificates, err = regenerateAPICertificate(kubeCluster, kubeCluster.Certificates)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to regenerate KubeAPI certificate %v", err)
|
|
|
|
}
|
|
|
|
}
|
2018-01-10 23:03:08 +00:00
|
|
|
return nil
|
|
|
|
}
|
2018-02-15 03:25:36 +00:00
|
|
|
log.Infof(ctx, "[certificates] No Certificate backup found on host [%s]", backupHost.Address)
|
2018-01-10 23:03:08 +00:00
|
|
|
|
2018-02-06 19:25:54 +00:00
|
|
|
kubeCluster.Certificates, err = pki.GenerateRKECerts(ctx, kubeCluster.RancherKubernetesEngineConfig, kubeCluster.LocalKubeConfigPath, "")
|
2017-11-02 10:07:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to generate Kubernetes certificates: %v", err)
|
|
|
|
}
|
2018-02-15 03:25:36 +00:00
|
|
|
log.Infof(ctx, "[certificates] Temporarily saving certs to control host [%s]", backupHost.Address)
|
|
|
|
if err := pki.DeployCertificatesOnHost(ctx, backupHost, kubeCluster.Certificates, kubeCluster.SystemImages.CertDownloader, pki.TempCertPath, kubeCluster.PrivateRegistriesMap); err != nil {
|
2018-01-10 23:03:08 +00:00
|
|
|
return err
|
|
|
|
}
|
2018-02-15 03:25:36 +00:00
|
|
|
log.Infof(ctx, "[certificates] Saved certs to control host [%s]", backupHost.Address)
|
2017-11-02 10:07:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-11-21 19:25:08 +00:00
|
|
|
func regenerateAPICertificate(c *Cluster, certificates map[string]pki.CertificatePKI) (map[string]pki.CertificatePKI, error) {
|
|
|
|
logrus.Debugf("[certificates] Regenerating kubeAPI certificate")
|
2018-03-22 18:36:25 +00:00
|
|
|
kubeAPIAltNames := pki.GetAltNames(c.ControlPlaneHosts, c.ClusterDomain, c.KubernetesServiceIP, c.Authentication.SANs)
|
2017-11-21 19:25:08 +00:00
|
|
|
caCrt := certificates[pki.CACertName].Certificate
|
|
|
|
caKey := certificates[pki.CACertName].Key
|
2017-11-26 22:29:52 +00:00
|
|
|
kubeAPIKey := certificates[pki.KubeAPICertName].Key
|
2018-01-16 23:10:14 +00:00
|
|
|
kubeAPICert, _, err := pki.GenerateSignedCertAndKey(caCrt, caKey, true, pki.KubeAPICertName, kubeAPIAltNames, kubeAPIKey, nil)
|
2017-11-21 19:25:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-01-16 23:10:14 +00:00
|
|
|
certificates[pki.KubeAPICertName] = pki.ToCertObject(pki.KubeAPICertName, "", "", kubeAPICert, kubeAPIKey)
|
2017-11-21 19:25:08 +00:00
|
|
|
return certificates, nil
|
|
|
|
}
|
|
|
|
|
2018-01-16 23:10:14 +00:00
|
|
|
func getClusterCerts(ctx context.Context, kubeClient *kubernetes.Clientset, etcdHosts []*hosts.Host) (map[string]pki.CertificatePKI, error) {
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "[certificates] Getting Cluster certificates from Kubernetes")
|
2017-11-02 10:07:10 +00:00
|
|
|
certificatesNames := []string{
|
|
|
|
pki.CACertName,
|
|
|
|
pki.KubeAPICertName,
|
2018-01-16 23:10:14 +00:00
|
|
|
pki.KubeNodeCertName,
|
|
|
|
pki.KubeProxyCertName,
|
|
|
|
pki.KubeControllerCertName,
|
|
|
|
pki.KubeSchedulerCertName,
|
|
|
|
pki.KubeAdminCertName,
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, etcdHost := range etcdHosts {
|
|
|
|
etcdName := pki.GetEtcdCrtName(etcdHost.InternalAddress)
|
|
|
|
certificatesNames = append(certificatesNames, etcdName)
|
2017-11-02 10:07:10 +00:00
|
|
|
}
|
2018-01-16 23:10:14 +00:00
|
|
|
|
2017-11-02 10:07:10 +00:00
|
|
|
certMap := make(map[string]pki.CertificatePKI)
|
|
|
|
for _, certName := range certificatesNames {
|
2017-11-07 15:44:17 +00:00
|
|
|
secret, err := k8s.GetSecret(kubeClient, certName)
|
2017-11-02 10:07:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
secretCert, _ := cert.ParseCertsPEM(secret.Data["Certificate"])
|
|
|
|
secretKey, _ := cert.ParsePrivateKeyPEM(secret.Data["Key"])
|
|
|
|
secretConfig := string(secret.Data["Config"])
|
|
|
|
certMap[certName] = pki.CertificatePKI{
|
2017-11-14 18:11:21 +00:00
|
|
|
Certificate: secretCert[0],
|
|
|
|
Key: secretKey.(*rsa.PrivateKey),
|
|
|
|
Config: secretConfig,
|
|
|
|
EnvName: string(secret.Data["EnvName"]),
|
|
|
|
ConfigEnvName: string(secret.Data["ConfigEnvName"]),
|
|
|
|
KeyEnvName: string(secret.Data["KeyEnvName"]),
|
2017-11-02 10:07:10 +00:00
|
|
|
}
|
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "[certificates] Successfully fetched Cluster certificates from Kubernetes")
|
2017-11-02 10:07:10 +00:00
|
|
|
return certMap, nil
|
|
|
|
}
|
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
func saveClusterCerts(ctx context.Context, kubeClient *kubernetes.Clientset, crts map[string]pki.CertificatePKI) error {
|
|
|
|
log.Infof(ctx, "[certificates] Save kubernetes certificates as secrets")
|
2018-02-01 14:27:28 +00:00
|
|
|
var errgrp errgroup.Group
|
2017-11-02 10:07:10 +00:00
|
|
|
for crtName, crt := range crts {
|
2018-02-01 14:27:28 +00:00
|
|
|
name := crtName
|
|
|
|
certificate := crt
|
|
|
|
errgrp.Go(func() error {
|
|
|
|
return saveCertToKubernetes(kubeClient, name, certificate)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if err := errgrp.Wait(); err != nil {
|
|
|
|
return err
|
|
|
|
|
2017-11-02 10:07:10 +00:00
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "[certificates] Successfully saved certificates as kubernetes secret [%s]", pki.CertificatesSecretName)
|
2017-11-02 10:07:10 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-11-07 15:44:17 +00:00
|
|
|
func saveCertToKubernetes(kubeClient *kubernetes.Clientset, crtName string, crt pki.CertificatePKI) error {
|
2017-11-02 10:07:10 +00:00
|
|
|
logrus.Debugf("[certificates] Saving certificate [%s] to kubernetes", crtName)
|
|
|
|
timeout := make(chan bool, 1)
|
2018-02-01 14:27:28 +00:00
|
|
|
|
|
|
|
// build secret Data
|
2018-02-14 20:58:35 +00:00
|
|
|
secretData := make(map[string][]byte)
|
|
|
|
if crt.Certificate != nil {
|
|
|
|
secretData["Certificate"] = cert.EncodeCertPEM(crt.Certificate)
|
|
|
|
secretData["EnvName"] = []byte(crt.EnvName)
|
|
|
|
}
|
|
|
|
if crt.Key != nil {
|
|
|
|
secretData["Key"] = cert.EncodePrivateKeyPEM(crt.Key)
|
|
|
|
secretData["KeyEnvName"] = []byte(crt.KeyEnvName)
|
2018-02-01 14:27:28 +00:00
|
|
|
}
|
|
|
|
if len(crt.Config) > 0 {
|
|
|
|
secretData["ConfigEnvName"] = []byte(crt.ConfigEnvName)
|
|
|
|
secretData["Config"] = []byte(crt.Config)
|
|
|
|
}
|
2017-11-02 10:07:10 +00:00
|
|
|
go func() {
|
|
|
|
for {
|
2018-02-01 14:27:28 +00:00
|
|
|
err := k8s.UpdateSecret(kubeClient, secretData, crtName)
|
2017-11-14 18:11:21 +00:00
|
|
|
if err != nil {
|
|
|
|
time.Sleep(time.Second * 5)
|
|
|
|
continue
|
|
|
|
}
|
2017-11-02 10:07:10 +00:00
|
|
|
timeout <- true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
select {
|
|
|
|
case <-timeout:
|
|
|
|
return nil
|
|
|
|
case <-time.After(time.Second * KubernetesClientTimeOut):
|
|
|
|
return fmt.Errorf("[certificates] Timeout waiting for kubernetes to be ready")
|
|
|
|
}
|
|
|
|
}
|