diff --git a/cluster/certificates.go b/cluster/certificates.go index 2067e87c..fb35a9c7 100644 --- a/cluster/certificates.go +++ b/cluster/certificates.go @@ -15,11 +15,6 @@ import ( "k8s.io/client-go/util/cert" ) -type RotateCertificatesFlags struct { - RotateCACerts bool - RotateComponents []string -} - func SetUpAuthentication(ctx context.Context, kubeCluster, currentCluster *Cluster, fullState *FullState) error { if kubeCluster.Authentication.Strategy == X509AuthenticationProvider { kubeCluster.Certificates = fullState.DesiredState.CertificatesBundle @@ -154,7 +149,7 @@ func regenerateAPIAggregationCerts(c *Cluster, certificates map[string]pki.Certi return certificates, nil } -func RotateRKECertificates(ctx context.Context, c *Cluster, flags ExternalFlags, rotateflags RotateCertificatesFlags, clusterState *FullState) error { +func RotateRKECertificates(ctx context.Context, c *Cluster, flags ExternalFlags, clusterState *FullState) error { var ( serviceAccountTokenKey string ) @@ -166,14 +161,15 @@ func RotateRKECertificates(ctx context.Context, c *Cluster, flags ExternalFlags, services.KubeletContainerName: pki.GenerateKubeNodeCertificate, services.EtcdContainerName: pki.GenerateEtcdCertificates, } - if rotateflags.RotateCACerts { + rotateFlags := c.RancherKubernetesEngineConfig.RotateCertificates + if rotateFlags.CACertificates { // rotate CA cert and RequestHeader CA cert if err := pki.GenerateRKECACerts(ctx, c.Certificates, flags.ClusterFilePath, flags.ConfigDir); err != nil { return err } - rotateflags.RotateComponents = nil + rotateFlags.Services = nil } - for _, k8sComponent := range rotateflags.RotateComponents { + for _, k8sComponent := range rotateFlags.Services { genFunc := componentsCertsFuncMap[k8sComponent] if genFunc != nil { if err := genFunc(ctx, c.Certificates, c.RancherKubernetesEngineConfig, flags.ClusterFilePath, flags.ConfigDir, true); err != nil { @@ -181,7 +177,7 @@ func RotateRKECertificates(ctx context.Context, c *Cluster, flags ExternalFlags, } } } - if len(rotateflags.RotateComponents) == 0 { + if len(rotateFlags.Services) == 0 { // do not rotate service account token if c.Certificates[pki.ServiceAccountTokenKeyName].Key != nil { serviceAccountTokenKey = string(cert.EncodePrivateKeyPEM(c.Certificates[pki.ServiceAccountTokenKeyName].Key)) @@ -206,10 +202,3 @@ func RotateRKECertificates(ctx context.Context, c *Cluster, flags ExternalFlags, clusterState.DesiredState.RancherKubernetesEngineConfig = &c.RancherKubernetesEngineConfig return nil } - -func GetRotateCertsFlags(rotateCACerts bool, components []string) RotateCertificatesFlags { - return RotateCertificatesFlags{ - RotateCACerts: rotateCACerts, - RotateComponents: components, - } -} diff --git a/cmd/cert.go b/cmd/cert.go index d4af1bd4..643236bc 100644 --- a/cmd/cert.go +++ b/cmd/cert.go @@ -11,6 +11,7 @@ import ( "github.com/rancher/rke/services" "github.com/rancher/types/apis/management.cattle.io/v3" "github.com/urfave/cli" + "k8s.io/client-go/util/cert" ) func CertificateCommand() cli.Command { @@ -51,8 +52,8 @@ func CertificateCommand() cli.Command { } func rotateRKECertificatesFromCli(ctx *cli.Context) error { - k8sComponent := ctx.StringSlice("service") - rotateCACert := ctx.Bool("rotate-ca") + k8sComponents := ctx.StringSlice("service") + rotateCACerts := ctx.Bool("rotate-ca") clusterFile, filePath, err := resolveClusterFile(ctx) if err != nil { return fmt.Errorf("Failed to resolve cluster file: %v", err) @@ -68,12 +69,16 @@ func rotateRKECertificatesFromCli(ctx *cli.Context) error { } // setting up the flags externalFlags := cluster.GetExternalFlags(false, false, false, "", filePath) - rotateFlags := cluster.GetRotateCertsFlags(rotateCACert, k8sComponent) - - if err := RotateRKECertificates(context.Background(), rkeConfig, hosts.DialersOptions{}, externalFlags, rotateFlags); err != nil { + // setting up rotate flags + rkeConfig.RotateCertificates = &v3.RotateCertificates{ + CACertificates: rotateCACerts, + Services: k8sComponents, + } + if err := ClusterInit(context.Background(), rkeConfig, hosts.DialersOptions{}, externalFlags); err != nil { return err } - return RebuildClusterWithRotatedCertificates(context.Background(), rkeConfig, hosts.DialersOptions{}, externalFlags, rotateFlags) + _, _, _, _, _, err = RebuildClusterWithRotatedCertificates(context.Background(), hosts.DialersOptions{}, externalFlags) + return err } func showRKECertificatesFromCli(ctx *cli.Context) error { @@ -81,104 +86,84 @@ func showRKECertificatesFromCli(ctx *cli.Context) error { } func RebuildClusterWithRotatedCertificates(ctx context.Context, - rkeConfig *v3.RancherKubernetesEngineConfig, dialersOptions hosts.DialersOptions, - flags cluster.ExternalFlags, - rotateFlags cluster.RotateCertificatesFlags) error { - + flags cluster.ExternalFlags) (string, string, string, string, map[string]pki.CertificatePKI, error) { + var APIURL, caCrt, clientCert, clientKey string log.Infof(ctx, "Rebuilding Kubernetes cluster with rotated certificates") clusterState, err := cluster.ReadStateFile(ctx, cluster.GetStateFilePath(flags.ClusterFilePath, flags.ConfigDir)) if err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } - kubeCluster, err := cluster.InitClusterObject(ctx, rkeConfig, flags) + kubeCluster, err := cluster.InitClusterObject(ctx, clusterState.DesiredState.RancherKubernetesEngineConfig.DeepCopy(), flags) if err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } if err := kubeCluster.SetupDialers(ctx, dialersOptions); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } if err := kubeCluster.TunnelHosts(ctx, flags); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } if err := cluster.SetUpAuthentication(ctx, kubeCluster, nil, clusterState); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } + APIURL = fmt.Sprintf("https://" + kubeCluster.ControlPlaneHosts[0].Address + ":6443") + clientCert = string(cert.EncodeCertPEM(kubeCluster.Certificates[pki.KubeAdminCertName].Certificate)) + clientKey = string(cert.EncodePrivateKeyPEM(kubeCluster.Certificates[pki.KubeAdminCertName].Key)) + caCrt = string(cert.EncodeCertPEM(kubeCluster.Certificates[pki.CACertName].Certificate)) if err := kubeCluster.SetUpHosts(ctx, true); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } // Save new State if err := kubeCluster.UpdateClusterCurrentState(ctx, clusterState); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } // Restarting Kubernetes components servicesMap := make(map[string]bool) - for _, component := range rotateFlags.RotateComponents { + for _, component := range kubeCluster.RotateCertificates.Services { servicesMap[component] = true } - if len(rotateFlags.RotateComponents) == 0 || rotateFlags.RotateCACerts || servicesMap[services.EtcdContainerName] { + if len(kubeCluster.RotateCertificates.Services) == 0 || kubeCluster.RotateCertificates.CACertificates || servicesMap[services.EtcdContainerName] { if err := services.RestartEtcdPlane(ctx, kubeCluster.EtcdHosts); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } } if err := services.RestartControlPlane(ctx, kubeCluster.ControlPlaneHosts); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } allHosts := hosts.GetUniqueHostList(kubeCluster.EtcdHosts, kubeCluster.ControlPlaneHosts, kubeCluster.WorkerHosts) if err := services.RestartWorkerPlane(ctx, allHosts); err != nil { - return err + return APIURL, caCrt, clientCert, clientKey, nil, err } - if rotateFlags.RotateCACerts { - return cluster.RestartClusterPods(ctx, kubeCluster) + if kubeCluster.RotateCertificates.CACertificates { + if err := cluster.RestartClusterPods(ctx, kubeCluster); err != nil { + return APIURL, caCrt, clientCert, clientKey, nil, err + } } - return nil + return APIURL, caCrt, clientCert, clientKey, kubeCluster.Certificates, nil } -func RotateRKECertificates(ctx context.Context, - rkeConfig *v3.RancherKubernetesEngineConfig, - dialersOptions hosts.DialersOptions, - flags cluster.ExternalFlags, - rotateFlags cluster.RotateCertificatesFlags) error { +func rotateRKECertificates(ctx context.Context, kubeCluster *cluster.Cluster, flags cluster.ExternalFlags, rkeFullState *cluster.FullState) (*cluster.FullState, error) { log.Infof(ctx, "Rotating Kubernetes cluster certificates") - stateFilePath := cluster.GetStateFilePath(flags.ClusterFilePath, flags.ConfigDir) - clusterState, _ := cluster.ReadStateFile(ctx, stateFilePath) - - kubeCluster, err := cluster.InitClusterObject(ctx, rkeConfig, flags) + currentCluster, err := kubeCluster.GetClusterState(ctx, rkeFullState) if err != nil { - return err - } - - if err := kubeCluster.SetupDialers(ctx, dialersOptions); err != nil { - return err - } - - err = doUpgradeLegacyCluster(ctx, kubeCluster, clusterState) - if err != nil { - log.Warnf(ctx, "[state] can't fetch legacy cluster state from Kubernetes") - } - - currentCluster, err := kubeCluster.GetClusterState(ctx, clusterState) - if err != nil { - return err + return nil, err } if currentCluster == nil { - return fmt.Errorf("Failed to rotate certificates: can't find old certificates") + return nil, fmt.Errorf("Failed to rotate certificates: can't find old certificates") } - if err := cluster.RotateRKECertificates(ctx, currentCluster, flags, rotateFlags, clusterState); err != nil { - return err + currentCluster.RotateCertificates = kubeCluster.RotateCertificates + if err := cluster.RotateRKECertificates(ctx, currentCluster, flags, rkeFullState); err != nil { + return nil, err } - rkeState := cluster.FullState{ - DesiredState: clusterState.DesiredState, - CurrentState: clusterState.CurrentState, - } - return rkeState.WriteStateFile(ctx, stateFilePath) + return rkeFullState, nil } diff --git a/cmd/common.go b/cmd/common.go index 7585db94..d9603186 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -1,13 +1,16 @@ package cmd import ( + "context" "fmt" + "github.com/rancher/rke/cluster" + "github.com/rancher/rke/hosts" + "github.com/rancher/rke/log" + "github.com/rancher/types/apis/management.cattle.io/v3" + "github.com/urfave/cli" "io/ioutil" "os" "path/filepath" - - "github.com/rancher/types/apis/management.cattle.io/v3" - "github.com/urfave/cli" ) var commonFlags = []cli.Flag{ @@ -52,3 +55,39 @@ func setOptionsFromCLI(c *cli.Context, rkeConfig *v3.RancherKubernetesEngineConf return rkeConfig, nil } + +func ClusterInit(ctx context.Context, rkeConfig *v3.RancherKubernetesEngineConfig, dialersOptions hosts.DialersOptions, flags cluster.ExternalFlags) error { + log.Infof(ctx, "Initiating Kubernetes cluster") + var fullState *cluster.FullState + stateFilePath := cluster.GetStateFilePath(flags.ClusterFilePath, flags.ConfigDir) + rkeFullState, _ := cluster.ReadStateFile(ctx, stateFilePath) + + kubeCluster, err := cluster.InitClusterObject(ctx, rkeConfig, flags) + if err != nil { + return err + } + + if err := kubeCluster.SetupDialers(ctx, dialersOptions); err != nil { + return err + } + + err = doUpgradeLegacyCluster(ctx, kubeCluster, rkeFullState) + if err != nil { + log.Warnf(ctx, "[state] can't fetch legacy cluster state from Kubernetes") + } + // check if certificate rotate or normal init + if kubeCluster.RancherKubernetesEngineConfig.RotateCertificates != nil { + fullState, err = rotateRKECertificates(ctx, kubeCluster, flags, rkeFullState) + } else { + fullState, err = cluster.RebuildState(ctx, &kubeCluster.RancherKubernetesEngineConfig, rkeFullState, flags) + } + if err != nil { + return err + } + + rkeState := cluster.FullState{ + DesiredState: fullState.DesiredState, + CurrentState: fullState.CurrentState, + } + return rkeState.WriteStateFile(ctx, stateFilePath) +} diff --git a/cmd/up.go b/cmd/up.go index 6a4546ad..d7596677 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -102,35 +102,6 @@ func doUpgradeLegacyCluster(ctx context.Context, kubeCluster *cluster.Cluster, f return nil } -func ClusterInit(ctx context.Context, rkeConfig *v3.RancherKubernetesEngineConfig, dialersOptions hosts.DialersOptions, flags cluster.ExternalFlags) error { - log.Infof(ctx, "Initiating Kubernetes cluster") - stateFilePath := cluster.GetStateFilePath(flags.ClusterFilePath, flags.ConfigDir) - rkeFullState, _ := cluster.ReadStateFile(ctx, stateFilePath) - kubeCluster, err := cluster.InitClusterObject(ctx, rkeConfig, flags) - if err != nil { - return err - } - if err := kubeCluster.SetupDialers(ctx, dialersOptions); err != nil { - return err - } - - err = doUpgradeLegacyCluster(ctx, kubeCluster, rkeFullState) - if err != nil { - log.Warnf(ctx, "[state] can't fetch legacy cluster state from Kubernetes") - } - - fullState, err := cluster.RebuildState(ctx, &kubeCluster.RancherKubernetesEngineConfig, rkeFullState, flags) - if err != nil { - return err - } - - rkeState := cluster.FullState{ - DesiredState: fullState.DesiredState, - CurrentState: fullState.CurrentState, - } - return rkeState.WriteStateFile(ctx, stateFilePath) -} - func ClusterUp(ctx context.Context, dialersOptions hosts.DialersOptions, flags cluster.ExternalFlags) (string, string, string, string, map[string]pki.CertificatePKI, error) { log.Infof(ctx, "Building Kubernetes cluster") var APIURL, caCrt, clientCert, clientKey string diff --git a/pki/services.go b/pki/services.go index ef003264..35556666 100644 --- a/pki/services.go +++ b/pki/services.go @@ -26,7 +26,7 @@ func GenerateKubeAPICertificate(ctx context.Context, certs map[string]Certificat kubeAPICert := certs[KubeAPICertName].Certificate if kubeAPICert != nil && reflect.DeepEqual(kubeAPIAltNames.DNSNames, kubeAPICert.DNSNames) && - deepEqualIPsAltNames(kubeAPIAltNames.IPs, kubeAPICert.IPAddresses) { + deepEqualIPsAltNames(kubeAPIAltNames.IPs, kubeAPICert.IPAddresses) && !rotate { return nil } log.Infof(ctx, "[certificates] Generating Kubernetes API server certificates")