2019-10-03 01:56:39 +00:00
package cmd
import (
"context"
"fmt"
"github.com/rancher/rke/cluster"
"github.com/rancher/rke/hosts"
"github.com/rancher/rke/log"
"github.com/rancher/rke/pki"
2020-12-14 18:51:46 +00:00
"github.com/rancher/rke/pki/cert"
2020-07-11 16:24:19 +00:00
v3 "github.com/rancher/rke/types"
2019-10-03 01:56:39 +00:00
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
func EncryptionCommand ( ) cli . Command {
encryptFlags := [ ] cli . Flag {
cli . StringFlag {
Name : "config" ,
Usage : "Specify an alternate cluster YAML file" ,
Value : pki . ClusterConfig ,
EnvVar : "RKE_CONFIG" ,
} ,
}
encryptFlags = append ( encryptFlags , commonFlags ... )
return cli . Command {
Name : "encrypt" ,
Usage : "Manage cluster encryption provider keys" ,
Subcommands : cli . Commands {
cli . Command {
Name : "rotate-key" ,
Usage : "Rotate cluster encryption provider key" ,
Action : rotateEncryptionKeyFromCli ,
Flags : encryptFlags ,
} ,
} ,
}
}
func rotateEncryptionKeyFromCli ( ctx * cli . Context ) error {
logrus . Infof ( "Running RKE version: %v" , ctx . App . Version )
clusterFile , filePath , err := resolveClusterFile ( ctx )
if err != nil {
return fmt . Errorf ( "Failed to resolve cluster file: %v" , err )
}
rkeConfig , err := cluster . ParseConfig ( clusterFile )
if err != nil {
return fmt . Errorf ( "Failed to parse cluster file: %v" , err )
}
rkeConfig , err = setOptionsFromCLI ( ctx , rkeConfig )
if err != nil {
return err
}
// setting up the flags
2020-08-03 13:35:38 +00:00
flags := cluster . GetExternalFlags ( false , false , false , false , "" , filePath )
2019-10-03 01:56:39 +00:00
2020-12-14 18:51:46 +00:00
_ , _ , _ , _ , _ , err = RotateEncryptionKey ( context . Background ( ) , rkeConfig , hosts . DialersOptions { } , flags )
return err
2019-10-03 01:56:39 +00:00
}
2020-12-14 18:51:46 +00:00
func RotateEncryptionKey (
ctx context . Context ,
rkeConfig * v3 . RancherKubernetesEngineConfig ,
dialersOptions hosts . DialersOptions ,
flags cluster . ExternalFlags ,
) ( string , string , string , string , map [ string ] pki . CertificatePKI , error ) {
log . Infof ( ctx , "Rotating cluster secrets encryption key" )
var APIURL , caCrt , clientCert , clientKey string
2019-10-03 01:56:39 +00:00
stateFilePath := cluster . GetStateFilePath ( flags . ClusterFilePath , flags . ConfigDir )
rkeFullState , _ := cluster . ReadStateFile ( ctx , stateFilePath )
2020-12-09 20:49:27 +00:00
2020-12-14 18:51:46 +00:00
// We generate the first encryption config in ClusterInit, to store it ASAP. It's written to the DesiredState
stateEncryptionConfig := rkeFullState . DesiredState . EncryptionConfig
2019-10-03 01:56:39 +00:00
// if CurrentState has EncryptionConfig, it means this is NOT the first time we enable encryption, we should use the _latest_ applied value from the current cluster
if rkeFullState . CurrentState . EncryptionConfig != "" {
stateEncryptionConfig = rkeFullState . CurrentState . EncryptionConfig
}
kubeCluster , err := cluster . InitClusterObject ( ctx , rkeConfig , flags , stateEncryptionConfig )
if err != nil {
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , nil , err
2019-10-03 01:56:39 +00:00
}
2020-12-14 18:51:46 +00:00
2019-10-03 01:56:39 +00:00
if kubeCluster . IsEncryptionCustomConfig ( ) {
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , nil , fmt . Errorf ( "can't rotate encryption keys: Key Rotation is not supported with custom configuration" )
2019-10-03 01:56:39 +00:00
}
if ! kubeCluster . IsEncryptionEnabled ( ) {
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , nil , fmt . Errorf ( "can't rotate encryption keys: Encryption Configuration is disabled" )
2019-10-03 01:56:39 +00:00
}
2020-12-14 18:51:46 +00:00
2019-10-03 01:56:39 +00:00
kubeCluster . Certificates = rkeFullState . DesiredState . CertificatesBundle
if err := kubeCluster . SetupDialers ( ctx , dialersOptions ) ; err != nil {
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , nil , err
2019-10-03 01:56:39 +00:00
}
if err := kubeCluster . TunnelHosts ( ctx , flags ) ; err != nil {
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , nil , err
}
if len ( kubeCluster . ControlPlaneHosts ) > 0 {
APIURL = fmt . Sprintf ( "https://%s:6443" , kubeCluster . ControlPlaneHosts [ 0 ] . Address )
2019-10-03 01:56:39 +00:00
}
2020-12-14 18:51:46 +00:00
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 ) )
2019-10-03 01:56:39 +00:00
err = kubeCluster . RotateEncryptionKey ( ctx , rkeFullState )
if err != nil {
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , nil , err
2019-10-03 01:56:39 +00:00
}
2020-12-14 18:51:46 +00:00
2019-10-03 01:56:39 +00:00
// make sure we have the latest state
rkeFullState , _ = cluster . ReadStateFile ( ctx , stateFilePath )
2020-12-14 18:51:46 +00:00
2019-10-03 01:56:39 +00:00
log . Infof ( ctx , "Reconciling cluster state" )
if err := kubeCluster . ReconcileDesiredStateEncryptionConfig ( ctx , rkeFullState ) ; err != nil {
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , nil , err
2019-10-03 01:56:39 +00:00
}
2020-12-14 18:51:46 +00:00
2019-10-03 01:56:39 +00:00
log . Infof ( ctx , "Cluster secrets encryption key rotated successfully" )
2020-12-14 18:51:46 +00:00
return APIURL , caCrt , clientCert , clientKey , kubeCluster . Certificates , nil
2019-10-03 01:56:39 +00:00
}