diff --git a/e2e/cluster_test.go b/e2e/cluster_test.go index 69896dd48..cfdb8c80a 100644 --- a/e2e/cluster_test.go +++ b/e2e/cluster_test.go @@ -112,6 +112,8 @@ type etcdProcessClusterConfig struct { isClientAutoTLS bool isClientCRL bool + cipherSuites []string + forceNewCluster bool initialToken string quotaBackendBytes int64 @@ -296,6 +298,10 @@ func (cfg *etcdProcessClusterConfig) tlsArgs() (args []string) { args = append(args, "--client-crl-file", crlPath, "--client-cert-auth") } + if len(cfg.cipherSuites) > 0 { + args = append(args, "--cipher-suites", strings.Join(cfg.cipherSuites, ",")) + } + return args } diff --git a/e2e/v2_curl_test.go b/e2e/v2_curl_test.go index 9f350a3e3..fa6a78c02 100644 --- a/e2e/v2_curl_test.go +++ b/e2e/v2_curl_test.go @@ -127,6 +127,8 @@ type cURLReq struct { header string metricsURLScheme string + + ciphers string } // cURLPrefixArgs builds the beginning of a curl command for a given key @@ -165,6 +167,10 @@ func cURLPrefixArgs(clus *etcdProcessCluster, method string, req cURLReq) []stri cmdArgs = append(cmdArgs, "-H", req.header) } + if req.ciphers != "" { + cmdArgs = append(cmdArgs, "--ciphers", req.ciphers) + } + switch method { case "POST", "PUT": dt := req.value diff --git a/e2e/v3_curl_test.go b/e2e/v3_curl_test.go index 778860955..2c8aec355 100644 --- a/e2e/v3_curl_test.go +++ b/e2e/v3_curl_test.go @@ -17,6 +17,7 @@ package e2e import ( "encoding/base64" "encoding/json" + "fmt" "path" "strconv" "testing" @@ -24,6 +25,7 @@ import ( epb "github.com/coreos/etcd/etcdserver/api/v3election/v3electionpb" pb "github.com/coreos/etcd/etcdserver/etcdserverpb" "github.com/coreos/etcd/pkg/testutil" + "github.com/coreos/etcd/version" "github.com/grpc-ecosystem/grpc-gateway/runtime" ) @@ -390,3 +392,45 @@ type campaignResponse struct { Lease string `json:"lease,omitempty"` } `json:"leader,omitempty"` } + +func TestV3CurlCipherSuitesValid(t *testing.T) { testV3CurlCipherSuites(t, true) } +func TestV3CurlCipherSuitesMismatch(t *testing.T) { testV3CurlCipherSuites(t, false) } +func testV3CurlCipherSuites(t *testing.T, valid bool) { + cc := configClientTLS + cc.clusterSize = 1 + cc.cipherSuites = []string{ + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + } + testFunc := cipherSuiteTestValid + if !valid { + testFunc = cipherSuiteTestMismatch + } + testCtl(t, testFunc, withCfg(cc)) +} + +func cipherSuiteTestValid(cx ctlCtx) { + if err := cURLGet(cx.epc, cURLReq{ + endpoint: "/metrics", + expected: fmt.Sprintf(`etcd_server_version{server_version="%s"} 1`, version.Version), + metricsURLScheme: cx.cfg.metricsURLScheme, + ciphers: "ECDHE-RSA-AES128-GCM-SHA256", // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + }); err != nil { + cx.t.Fatalf("failed get with curl (%v)", err) + } +} + +func cipherSuiteTestMismatch(cx ctlCtx) { + if err := cURLGet(cx.epc, cURLReq{ + endpoint: "/metrics", + expected: "alert handshake failure", + metricsURLScheme: cx.cfg.metricsURLScheme, + ciphers: "ECDHE-RSA-DES-CBC3-SHA", // TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + }); err != nil { + cx.t.Fatalf("failed get with curl (%v)", err) + } +}