diff --git a/tests/e2e/cluster_test.go b/tests/e2e/cluster_test.go index 133b3ee35..4b32db189 100644 --- a/tests/e2e/cluster_test.go +++ b/tests/e2e/cluster_test.go @@ -117,6 +117,8 @@ type etcdProcessClusterConfig struct { isClientAutoTLS bool isClientCRL bool + cipherSuites []string + forceNewCluster bool initialToken string quotaBackendBytes int64 @@ -307,6 +309,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/tests/e2e/v2_curl_test.go b/tests/e2e/v2_curl_test.go index f50520f0d..22ef3bdca 100644 --- a/tests/e2e/v2_curl_test.go +++ b/tests/e2e/v2_curl_test.go @@ -130,6 +130,8 @@ type cURLReq struct { header string metricsURLScheme string + + ciphers string } // cURLPrefixArgs builds the beginning of a curl command for a given key @@ -168,6 +170,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/tests/e2e/v3_curl_test.go b/tests/e2e/v3_curl_test.go index 250ea61aa..1515cfb31 100644 --- a/tests/e2e/v3_curl_test.go +++ b/tests/e2e/v3_curl_test.go @@ -26,6 +26,7 @@ import ( "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes" 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" ) @@ -349,6 +350,48 @@ func testV3CurlResignMissiongLeaderKey(cx ctlCtx) { } } +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) + } +} + // to manually decode; JSON marshals integer fields with // string types, so can't unmarshal with epb.CampaignResponse type campaignResponse struct {