From 9fe51e392be56b9543216222e154893e2bff3537 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Mon, 29 Oct 2018 11:14:12 -0700 Subject: [PATCH] Support etcd TLS certficates (#6719) This PR supports two models for etcd certs - Client-to-server transport security with HTTPS - Client-to-server authentication with HTTPS client certificates --- cmd/common-main.go | 17 +++++++++++++++++ cmd/gateway-main.go | 16 ++++++++-------- cmd/gateway/s3/gateway-s3.go | 3 +++ cmd/server-main.go | 12 ++++++------ docs/sts/etcd.md | 6 +++++- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/cmd/common-main.go b/cmd/common-main.go index c4e5e19aa..0eb677248 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -17,6 +17,7 @@ package cmd import ( + "crypto/tls" "errors" "net" "os" @@ -157,11 +158,27 @@ func handleCommonEnvVars() { etcdEndpointsEnv, ok := os.LookupEnv("MINIO_ETCD_ENDPOINTS") if ok { etcdEndpoints := strings.Split(etcdEndpointsEnv, ",") + + // This is only to support client side certificate authentication + // https://coreos.com/etcd/docs/latest/op-guide/security.html + etcdClientCertFile, ok1 := os.LookupEnv("MINIO_ETCD_CLIENT_CERT") + etcdClientCertKey, ok2 := os.LookupEnv("MINIO_ETCD_CLIENT_CERT_KEY") + var getClientCertificate func(*tls.CertificateRequestInfo) (*tls.Certificate, error) + if ok1 && ok2 { + getClientCertificate = func(unused *tls.CertificateRequestInfo) (*tls.Certificate, error) { + cert, err := tls.LoadX509KeyPair(etcdClientCertFile, etcdClientCertKey) + return &cert, err + } + } var err error globalEtcdClient, err = etcd.New(etcd.Config{ Endpoints: etcdEndpoints, DialTimeout: defaultDialTimeout, DialKeepAliveTime: defaultDialKeepAlive, + TLS: &tls.Config{ + RootCAs: globalRootCAs, + GetClientCertificate: getClientCertificate, + }, }) logger.FatalIf(err, "Unable to initialize etcd with %s", etcdEndpoints) } diff --git a/cmd/gateway-main.go b/cmd/gateway-main.go index bdcca38b7..075436443 100644 --- a/cmd/gateway-main.go +++ b/cmd/gateway-main.go @@ -134,9 +134,6 @@ func StartGateway(ctx *cli.Context, gw Gateway) { // Handle common command args. handleCommonCmdArgs(ctx) - // Handle common env vars. - handleCommonEnvVars() - // Get port to listen on from gateway address _, gatewayPort, pErr := net.SplitHostPort(gatewayAddr) if pErr != nil { @@ -149,11 +146,6 @@ func StartGateway(ctx *cli.Context, gw Gateway) { // To avoid this error situation we check for port availability. logger.FatalIf(checkPortAvailability(gatewayPort), "Unable to start the gateway") - // Validate if we have access, secret set through environment. - if !globalIsEnvCreds { - logger.Fatal(uiErrEnvCredentialsMissingGateway(nil), "Unable to start gateway") - } - // Create certs path. logger.FatalIf(createConfigDir(), "Unable to create configuration directories") @@ -166,6 +158,14 @@ func StartGateway(ctx *cli.Context, gw Gateway) { globalRootCAs, err = getRootCAs(getCADir()) logger.FatalIf(err, "Failed to read root CAs (%v)", err) + // Handle common env vars. + handleCommonEnvVars() + + // Validate if we have access, secret set through environment. + if !globalIsEnvCreds { + logger.Fatal(uiErrEnvCredentialsMissingGateway(nil), "Unable to start gateway") + } + // Set system resources to maximum. logger.LogIf(context.Background(), setMaxResources()) diff --git a/cmd/gateway/s3/gateway-s3.go b/cmd/gateway/s3/gateway-s3.go index 845a74655..78381f301 100644 --- a/cmd/gateway/s3/gateway-s3.go +++ b/cmd/gateway/s3/gateway-s3.go @@ -203,6 +203,9 @@ func newS3(url string) (*miniogo.Core, error) { return nil, err } + // Set custom transport + clnt.SetCustomTransport(minio.NewCustomHTTPTransport()) + probeBucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "probe-bucket-sign-") // Check if the provided keys are valid. if _, err = clnt.BucketExists(probeBucketName); err != nil { diff --git a/cmd/server-main.go b/cmd/server-main.go index bbdaa2315..757a0f672 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -218,12 +218,6 @@ func serverMain(ctx *cli.Context) { logger.EnableQuiet() } - // Handle all server command args. - serverHandleCmdArgs(ctx) - - // Handle all server environment vars. - serverHandleEnvVars() - // Create certs path. logger.FatalIf(createConfigDir(), "Unable to initialize configuration files") @@ -236,6 +230,12 @@ func serverMain(ctx *cli.Context) { globalRootCAs, err = getRootCAs(getCADir()) logger.FatalIf(err, "Failed to read root CAs (%v)", err) + // Handle all server command args. + serverHandleCmdArgs(ctx) + + // Handle all server environment vars. + serverHandleEnvVars() + // Is distributed setup, error out if no certificates are found for HTTPS endpoints. if globalIsDistXL { if globalEndpoints.IsHTTPS() && !globalIsSSL { diff --git a/docs/sts/etcd.md b/docs/sts/etcd.md index 4781cd7ce..aa52971ed 100644 --- a/docs/sts/etcd.md +++ b/docs/sts/etcd.md @@ -29,6 +29,8 @@ rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \ --initial-cluster-state new ``` +You may also setup etcd with TLS following this documentation [here](https://coreos.com/etcd/docs/latest/op-guide/security.html) + ### 3. Setup Minio with etcd Minio server expects environment variable for etcd as `MINIO_ETCD_ENDPOINTS`, this environment variable takes many comma separated entries. ``` @@ -36,7 +38,9 @@ export MINIO_ETCD_ENDPOINTS=localhost:2379 minio server /data ``` -### 5. Test with Minio STS API +NOTE: If `etcd` is configured with `Client-to-server authentication with HTTPS client certificates` then you need to use additional envs such as `MINIO_ETCD_CLIENT_CERT` pointing to path to `etcd-client.crt` and `MINIO_ETCD_CLIENT_CERT_KEY` path to `etcd-client.key` . + +### 4. Test with Minio STS API Assuming that you have configured Minio server to support STS API by following the doc [Minio STS Quickstart Guide](https://docs.minio.io/docs/minio-sts-quickstart-guide) and once you have obtained the JWT from WSO2 as mentioned in [WSO2 Quickstart Guide](https://github.com/minio/minio/blob/master/docs/sts/wso2.md). ``` go run full-example.go -cid PoEgXP6uVO45IsENRngDXj5Au5Ya -csec eKsw6z8CtOJVBtrOWvhRWL4TUCga