From 38c31b97664f5596ef9ceb5ca5b39568eb024096 Mon Sep 17 00:00:00 2001 From: moelsayed Date: Wed, 12 Jun 2019 00:31:01 +0200 Subject: [PATCH] Add option to pass custom CA certificate for S3 backend --- cluster/validation.go | 6 ++++++ cmd/common.go | 10 ++++++++++ cmd/etcd.go | 4 ++++ pki/util.go | 18 +++++++++++++++++- services/etcd.go | 10 +++++++++- 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/cluster/validation.go b/cluster/validation.go index d5188168..36658c7f 100644 --- a/cluster/validation.go +++ b/cluster/validation.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/rancher/rke/log" + "github.com/rancher/rke/pki" "github.com/rancher/rke/services" "github.com/rancher/rke/util" v3 "github.com/rancher/types/apis/management.cattle.io/v3" @@ -147,6 +148,11 @@ func validateEtcdBackupOptions(c *Cluster) error { if len(c.Services.Etcd.BackupConfig.S3BackupConfig.BucketName) == 0 { return fmt.Errorf("etcd s3 backup backend bucketName can't be empty") } + if len(c.Services.Etcd.BackupConfig.S3BackupConfig.EndpointCA) != 0 { + if isValid, err := pki.IsValidCertStr(c.Services.Etcd.BackupConfig.S3BackupConfig.EndpointCA); !isValid { + return fmt.Errorf("invalid S3 endpoint CA certificate: %v", err) + } + } } } return nil diff --git a/cmd/common.go b/cmd/common.go index 31c2cfc4..77f17518 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -11,6 +11,7 @@ import ( "github.com/rancher/rke/cluster" "github.com/rancher/rke/hosts" "github.com/rancher/rke/log" + "github.com/rancher/rke/pki" "github.com/rancher/rke/util" v3 "github.com/rancher/types/apis/management.cattle.io/v3" "github.com/sirupsen/logrus" @@ -114,6 +115,7 @@ func setS3OptionsFromCLI(c *cli.Context) *v3.S3BackupConfig { region := c.String("region") accessKey := c.String("access-key") secretKey := c.String("secret-key") + endpointCA := c.String("s3-endpoint-ca") var s3BackupBackend = &v3.S3BackupConfig{} if len(endpoint) != 0 { s3BackupBackend.Endpoint = endpoint @@ -130,6 +132,14 @@ func setS3OptionsFromCLI(c *cli.Context) *v3.S3BackupConfig { if len(secretKey) != 0 { s3BackupBackend.SecretKey = secretKey } + if len(endpointCA) != 0 { + caStr, err := pki.ReadCertToStr(endpointCA) + if err != nil { + logrus.Warnf("Failed to read s3-endpoint-ca [%s]: %v", endpointCA, err) + } else { + s3BackupBackend.EndpointCA = caStr + } + } return s3BackupBackend } diff --git a/cmd/etcd.go b/cmd/etcd.go index 7f99b2d6..409aa0b0 100644 --- a/cmd/etcd.go +++ b/cmd/etcd.go @@ -38,6 +38,10 @@ func EtcdCommand() cli.Command { Usage: "Specify s3 endpoint url", Value: s3Endpoint, }, + cli.StringFlag{ + Name: "s3-endpoint-ca", + Usage: "Specify a custom CA cert to connect to S3 endpoint", + }, cli.StringFlag{ Name: "access-key", Usage: "Specify s3 accessKey", diff --git a/pki/util.go b/pki/util.go index 00ea5934..3ab9c4da 100644 --- a/pki/util.go +++ b/pki/util.go @@ -20,7 +20,7 @@ import ( "time" "github.com/rancher/rke/hosts" - "github.com/rancher/types/apis/management.cattle.io/v3" + v3 "github.com/rancher/types/apis/management.cattle.io/v3" "github.com/sirupsen/logrus" "k8s.io/client-go/util/cert" ) @@ -744,3 +744,19 @@ func validateCAIssuer(rkeConfig *v3.RancherKubernetesEngineConfig, certBundle ma } return nil } + +func ReadCertToStr(file string) (string, error) { + certStr, err := ioutil.ReadFile(file) + if err != nil { + return "", fmt.Errorf("failed to read certificate [%s]: %v", file, err) + } + return string(certStr), nil +} + +func IsValidCertStr(c string) (bool, error) { + _, err := cert.ParseCertsPEM([]byte(c)) + if err != nil { + return false, err + } + return true, nil +} diff --git a/services/etcd.go b/services/etcd.go index b91e61ab..8d525d29 100644 --- a/services/etcd.go +++ b/services/etcd.go @@ -1,6 +1,7 @@ package services import ( + "encoding/base64" "fmt" "path" "path/filepath" @@ -366,7 +367,10 @@ func DownloadEtcdSnapshotFromS3(ctx context.Context, etcdHost *hosts.Host, prsMa }, Image: etcdSnapshotImage, } - + if s3Backend.EndpointCA != "" { + caStr := base64.StdEncoding.EncodeToString([]byte(s3Backend.EndpointCA)) + imageCfg.Cmd = append(imageCfg.Cmd, "--s3-endpoint-ca="+caStr) + } hostCfg := &container.HostConfig{ Binds: []string{ fmt.Sprintf("%s:/backup:z", EtcdSnapshotPath), @@ -552,6 +556,10 @@ func configS3BackupImgCmd(ctx context.Context, imageCfg *container.Config, bc *v "--s3-bucketName=" + bc.S3BackupConfig.BucketName, "--s3-region=" + bc.S3BackupConfig.Region, }...) + if bc.S3BackupConfig.EndpointCA != "" { + caStr := base64.StdEncoding.EncodeToString([]byte(bc.S3BackupConfig.EndpointCA)) + cmd = append(cmd, "--s3-endpoint-ca="+caStr) + } } imageCfg.Cmd = append(imageCfg.Cmd, cmd...) return imageCfg