1
0
mirror of https://github.com/rancher/rke.git synced 2025-09-17 23:49:06 +00:00

Add Rotate certificates command to rke

This commit is contained in:
galal-hussein
2018-08-20 06:37:04 +02:00
committed by Alena Prokharchyk
parent 7582083e7a
commit 3551e6e4b6
25 changed files with 798 additions and 205 deletions

View File

@@ -28,6 +28,9 @@ const (
IngressAddonJobName = "rke-ingress-controller-deploy-job"
IngressAddonDeleteJobName = "rke-ingress-controller-delete-job"
MetricsServerAddonResourceName = "rke-metrics-addon"
NginxIngressAddonAppName = "ingress-nginx"
KubeDNSAddonAppName = "kube-dns"
KubeDNSAutoscalerAppName = "kube-dns-autoscaler"
)
type ingressOptions struct {

View File

@@ -71,7 +71,7 @@ func SetUpAuthentication(ctx context.Context, kubeCluster, currentCluster *Clust
if err := rebuildLocalAdminConfig(ctx, kubeCluster); err != nil {
return err
}
kubeCluster.Certificates, err = regenerateAPICertificate(kubeCluster, kubeCluster.Certificates)
err = pki.GenerateKubeAPICertificate(ctx, kubeCluster.Certificates, kubeCluster.RancherKubernetesEngineConfig, "", "")
if err != nil {
return fmt.Errorf("Failed to regenerate KubeAPI certificate %v", err)
}
@@ -129,6 +129,7 @@ func getClusterCerts(ctx context.Context, kubeClient *kubernetes.Clientset, etcd
pki.KubeAdminCertName,
pki.APIProxyClientCertName,
pki.RequestHeaderCACertName,
pki.ServiceAccountTokenKeyName,
}
for _, etcdHost := range etcdHosts {
@@ -141,14 +142,16 @@ func getClusterCerts(ctx context.Context, kubeClient *kubernetes.Clientset, etcd
secret, err := k8s.GetSecret(kubeClient, certName)
if err != nil && !strings.HasPrefix(certName, "kube-etcd") &&
!strings.Contains(certName, pki.RequestHeaderCACertName) &&
!strings.Contains(certName, pki.APIProxyClientCertName) {
!strings.Contains(certName, pki.APIProxyClientCertName) &&
!strings.Contains(certName, pki.ServiceAccountTokenKeyName) {
return nil, err
}
// If I can't find an etcd, requestheader, or proxy client cert, I will not fail and will create it later.
if (secret == nil || secret.Data == nil) &&
(strings.HasPrefix(certName, "kube-etcd") ||
strings.Contains(certName, pki.RequestHeaderCACertName) ||
strings.Contains(certName, pki.APIProxyClientCertName)) {
strings.Contains(certName, pki.APIProxyClientCertName) ||
strings.Contains(certName, pki.ServiceAccountTokenKeyName)) {
certMap[certName] = pki.CertificatePKI{}
continue
}
@@ -346,7 +349,7 @@ func (c *Cluster) getBackupHosts() []*hosts.Host {
func regenerateAPIAggregationCerts(c *Cluster, certificates map[string]pki.CertificatePKI) (map[string]pki.CertificatePKI, error) {
logrus.Debugf("[certificates] Regenerating Kubernetes API server aggregation layer requestheader client CA certificates")
requestHeaderCACrt, requestHeaderCAKey, err := pki.GenerateCACertAndKey(pki.RequestHeaderCACertName)
requestHeaderCACrt, requestHeaderCAKey, err := pki.GenerateCACertAndKey(pki.RequestHeaderCACertName, nil)
if err != nil {
return nil, err
}
@@ -361,3 +364,54 @@ func regenerateAPIAggregationCerts(c *Cluster, certificates map[string]pki.Certi
certificates[pki.APIProxyClientCertName] = pki.ToCertObject(pki.APIProxyClientCertName, "", "", apiserverProxyClientCrt, apiserverProxyClientKey)
return certificates, nil
}
func RotateRKECertificates(ctx context.Context, c *Cluster, configPath, configDir string, components []string, rotateCACerts bool) error {
var (
serviceAccountTokenKey string
)
componentsCertsFuncMap := map[string]pki.GenFunc{
services.KubeAPIContainerName: pki.GenerateKubeAPICertificate,
services.KubeControllerContainerName: pki.GenerateKubeControllerCertificate,
services.SchedulerContainerName: pki.GenerateKubeSchedulerCertificate,
services.KubeproxyContainerName: pki.GenerateKubeProxyCertificate,
services.KubeletContainerName: pki.GenerateKubeNodeCertificate,
services.EtcdContainerName: pki.GenerateEtcdCertificates,
}
if rotateCACerts {
// rotate CA cert and RequestHeader CA cert
if err := pki.GenerateRKECACerts(ctx, c.Certificates, configPath, configDir); err != nil {
return err
}
components = nil
}
for _, k8sComponent := range components {
genFunc := componentsCertsFuncMap[k8sComponent]
if genFunc != nil {
if err := genFunc(ctx, c.Certificates, c.RancherKubernetesEngineConfig, configPath, configDir); err != nil {
return err
}
}
}
if len(components) == 0 {
// do not rotate service account token
if c.Certificates[pki.ServiceAccountTokenKeyName].Key != nil {
serviceAccountTokenKey = string(cert.EncodePrivateKeyPEM(c.Certificates[pki.ServiceAccountTokenKeyName].Key))
}
if err := pki.GenerateRKEServicesCerts(ctx, c.Certificates, c.RancherKubernetesEngineConfig, configPath, configDir); err != nil {
return err
}
if serviceAccountTokenKey != "" {
privateKey, err := cert.ParsePrivateKeyPEM([]byte(serviceAccountTokenKey))
if err != nil {
return err
}
c.Certificates[pki.ServiceAccountTokenKeyName] = pki.ToCertObject(
pki.ServiceAccountTokenKeyName,
pki.ServiceAccountTokenKeyName,
"",
c.Certificates[pki.ServiceAccountTokenKeyName].Certificate,
privateKey.(*rsa.PrivateKey))
}
}
return nil
}

View File

@@ -67,6 +67,10 @@ const (
WorkerPlane = "workerPlan"
EtcdPlane = "etcd"
KubeAppLabel = "k8s-app"
AppLabel = "app"
NameLabel = "name"
WorkerThreads = util.WorkerThreads
)
@@ -458,3 +462,47 @@ func ConfigureCluster(
}
return nil
}
func RestartClusterPods(ctx context.Context, kubeCluster *Cluster) error {
log.Infof(ctx, "Restarting network, ingress, and metrics pods")
// this will remove the pods created by RKE and let the controller creates them again
kubeClient, err := k8s.NewClient(kubeCluster.LocalKubeConfigPath, kubeCluster.K8sWrapTransport)
if err != nil {
return fmt.Errorf("Failed to initialize new kubernetes client: %v", err)
}
labelsList := []string{
fmt.Sprintf("%s=%s", KubeAppLabel, CalicoNetworkPlugin),
fmt.Sprintf("%s=%s", KubeAppLabel, FlannelNetworkPlugin),
fmt.Sprintf("%s=%s", KubeAppLabel, CanalNetworkPlugin),
fmt.Sprintf("%s=%s", NameLabel, WeaveNetworkPlugin),
fmt.Sprintf("%s=%s", AppLabel, NginxIngressAddonAppName),
fmt.Sprintf("%s=%s", KubeAppLabel, DefaultMonitoringProvider),
fmt.Sprintf("%s=%s", KubeAppLabel, KubeDNSAddonAppName),
fmt.Sprintf("%s=%s", KubeAppLabel, KubeDNSAutoscalerAppName),
}
var errgrp errgroup.Group
labelQueue := util.GetObjectQueue(labelsList)
for w := 0; w < services.WorkerThreads; w++ {
errgrp.Go(func() error {
var errList []error
for label := range labelQueue {
runLabel := label.(string)
// list pods to be deleted
pods, err := k8s.ListPodsByLabel(kubeClient, runLabel)
if err != nil {
errList = append(errList, err)
}
// delete pods
err = k8s.DeletePods(kubeClient, pods)
if err != nil {
errList = append(errList, err)
}
}
return util.ErrList(errList)
})
}
if err := errgrp.Wait(); err != nil {
return err
}
return nil
}

View File

@@ -116,7 +116,7 @@ func (c *Cluster) InvertIndexHosts() error {
return nil
}
func (c *Cluster) SetUpHosts(ctx context.Context) error {
func (c *Cluster) SetUpHosts(ctx context.Context, rotateCerts bool) error {
if c.Authentication.Strategy == X509AuthenticationProvider {
log.Infof(ctx, "[certificates] Deploying kubernetes certificates to Cluster nodes")
hostList := hosts.GetUniqueHostList(c.EtcdHosts, c.ControlPlaneHosts, c.WorkerHosts)
@@ -127,7 +127,7 @@ func (c *Cluster) SetUpHosts(ctx context.Context) error {
errgrp.Go(func() error {
var errList []error
for host := range hostsQueue {
err := pki.DeployCertificatesOnPlaneHost(ctx, host.(*hosts.Host), c.RancherKubernetesEngineConfig, c.Certificates, c.SystemImages.CertDownloader, c.PrivateRegistriesMap)
err := pki.DeployCertificatesOnPlaneHost(ctx, host.(*hosts.Host), c.RancherKubernetesEngineConfig, c.Certificates, c.SystemImages.CertDownloader, c.PrivateRegistriesMap, rotateCerts)
if err != nil {
errList = append(errList, err)
}

View File

@@ -134,7 +134,7 @@ func (c *Cluster) BuildKubeAPIProcess(prefixPath string) v3.Process {
"tls-private-key-file": pki.GetKeyPath(pki.KubeAPICertName),
"kubelet-client-certificate": pki.GetCertPath(pki.KubeAPICertName),
"kubelet-client-key": pki.GetKeyPath(pki.KubeAPICertName),
"service-account-key-file": pki.GetKeyPath(pki.KubeAPICertName),
"service-account-key-file": pki.GetKeyPath(pki.ServiceAccountTokenKeyName),
"etcd-cafile": etcdCAClientCert,
"etcd-certfile": etcdClientCert,
"etcd-keyfile": etcdClientKey,
@@ -249,7 +249,7 @@ func (c *Cluster) BuildKubeControllerProcess(prefixPath string) v3.Process {
"allocate-node-cidrs": "true",
"cluster-cidr": c.ClusterCIDR,
"service-cluster-ip-range": c.Services.KubeController.ServiceClusterIPRange,
"service-account-private-key-file": pki.GetKeyPath(pki.KubeAPICertName),
"service-account-private-key-file": pki.GetKeyPath(pki.ServiceAccountTokenKeyName),
"root-ca-file": pki.GetCertPath(pki.CACertName),
}
if len(c.CloudProvider.Name) > 0 && c.CloudProvider.Name != aws.AWSCloudProviderName {

View File

@@ -47,6 +47,12 @@ func ReconcileCluster(ctx context.Context, kubeCluster, currentCluster *Cluster,
if err := reconcileControl(ctx, currentCluster, kubeCluster, kubeClient); err != nil {
return err
}
// Handle service account token key issue
kubeAPICert := currentCluster.Certificates[pki.KubeAPICertName]
if currentCluster.Certificates[pki.ServiceAccountTokenKeyName].Key == nil {
log.Infof(ctx, "[certificates] Creating service account token key")
currentCluster.Certificates[pki.ServiceAccountTokenKeyName] = pki.ToCertObject(pki.ServiceAccountTokenKeyName, pki.ServiceAccountTokenKeyName, "", kubeAPICert.Certificate, kubeAPICert.Key)
}
log.Infof(ctx, "[reconcile] Reconciled cluster state successfully")
return nil
}