From 4d3b75d867dae508011c198c84318f54b4aa6684 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 29 Aug 2017 11:11:19 -0700 Subject: [PATCH 1/7] Fix TLSServerName for Node API Client This PR fixes the construction of the TLSServerName when connecting to a node that has TLS enabled and adds tests for all possible permutations. Fixes https://github.com/hashicorp/nomad/issues/3013 --- api/api.go | 23 ++++++++- api/api_test.go | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/api/api.go b/api/api.go index ce6d910fe170..09c000a4a9b7 100644 --- a/api/api.go +++ b/api/api.go @@ -125,7 +125,9 @@ func (c *Config) ClientConfig(region, address string, tlsEnabled bool) *Config { WaitTime: c.WaitTime, TLSConfig: c.TLSConfig.Copy(), } - config.TLSConfig.TLSServerName = fmt.Sprintf("client.%s.nomad", c.Region) + if tlsEnabled && config.TLSConfig != nil { + config.TLSConfig.TLSServerName = fmt.Sprintf("client.%s.nomad", region) + } return config } @@ -221,6 +223,9 @@ func DefaultConfig() *Config { // ConfigureTLS applies a set of TLS configurations to the the HTTP client. func (c *Config) ConfigureTLS() error { + if c.TLSConfig == nil { + return nil + } if c.HttpClient == nil { return fmt.Errorf("config HTTP Client must be set") } @@ -300,7 +305,17 @@ func (c *Client) SetRegion(region string) { // GetNodeClient returns a new Client that will dial the specified node. If the // QueryOptions is set, its region will be used. func (c *Client) GetNodeClient(nodeID string, q *QueryOptions) (*Client, error) { - node, _, err := c.Nodes().Info(nodeID, q) + return c.getNodeClientImpl(nodeID, q, c.Nodes().Info) +} + +// nodeLookup is used to lookup a node +type nodeLookup func(nodeID string, q *QueryOptions) (*Node, *QueryMeta, error) + +// getNodeClientImpl is the implementation of creating a API client for +// contacting a node. It is takes a function to lookup the node such that it can +// be mocked during tests. +func (c *Client) getNodeClientImpl(nodeID string, q *QueryOptions, lookup nodeLookup) (*Client, error) { + node, _, err := lookup(nodeID, q) if err != nil { return nil, err } @@ -316,6 +331,10 @@ func (c *Client) GetNodeClient(nodeID string, q *QueryOptions) (*Client, error) region = q.Region } + if region == "" { + region = "global" + } + // Get an API client for the node conf := c.config.ClientConfig(region, node.HTTPAddr, node.TLSEnabled) return NewClient(conf) diff --git a/api/api_test.go b/api/api_test.go index 06eba83b3c95..ae79fee4075b 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -2,6 +2,7 @@ package api import ( "encoding/json" + "fmt" "net/http" "net/http/httptest" "os" @@ -9,7 +10,9 @@ import ( "testing" "time" + "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/testutil" + "github.com/stretchr/testify/assert" ) type configCallback func(c *Config) @@ -243,3 +246,126 @@ func TestQueryString(t *testing.T) { t.Fatalf("bad uri: %q", uri) } } + +func TestClient_NodeClient(t *testing.T) { + http := "testdomain:4646" + tlsNode := func(string, *QueryOptions) (*Node, *QueryMeta, error) { + return &Node{ + ID: structs.GenerateUUID(), + Status: "ready", + HTTPAddr: http, + TLSEnabled: true, + }, nil, nil + } + noTlsNode := func(string, *QueryOptions) (*Node, *QueryMeta, error) { + return &Node{ + ID: structs.GenerateUUID(), + Status: "ready", + HTTPAddr: http, + TLSEnabled: false, + }, nil, nil + } + + optionNoRegion := &QueryOptions{} + optionRegion := &QueryOptions{ + Region: "foo", + } + + clientNoRegion, err := NewClient(DefaultConfig()) + assert.Nil(t, err) + + regionConfig := DefaultConfig() + regionConfig.Region = "bar" + clientRegion, err := NewClient(regionConfig) + assert.Nil(t, err) + + expectedTLSAddr := fmt.Sprintf("https://%s", http) + expectedNoTLSAddr := fmt.Sprintf("http://%s", http) + + cases := []struct { + Node nodeLookup + QueryOptions *QueryOptions + Client *Client + ExpectedAddr string + ExpectedRegion string + ExpectedTLSServerName string + }{ + { + Node: tlsNode, + QueryOptions: optionNoRegion, + Client: clientNoRegion, + ExpectedAddr: expectedTLSAddr, + ExpectedRegion: "global", + ExpectedTLSServerName: "client.global.nomad", + }, + { + Node: tlsNode, + QueryOptions: optionRegion, + Client: clientNoRegion, + ExpectedAddr: expectedTLSAddr, + ExpectedRegion: "foo", + ExpectedTLSServerName: "client.foo.nomad", + }, + { + Node: tlsNode, + QueryOptions: optionRegion, + Client: clientRegion, + ExpectedAddr: expectedTLSAddr, + ExpectedRegion: "foo", + ExpectedTLSServerName: "client.foo.nomad", + }, + { + Node: tlsNode, + QueryOptions: optionNoRegion, + Client: clientRegion, + ExpectedAddr: expectedTLSAddr, + ExpectedRegion: "bar", + ExpectedTLSServerName: "client.bar.nomad", + }, + { + Node: noTlsNode, + QueryOptions: optionNoRegion, + Client: clientNoRegion, + ExpectedAddr: expectedNoTLSAddr, + ExpectedRegion: "global", + ExpectedTLSServerName: "", + }, + { + Node: noTlsNode, + QueryOptions: optionRegion, + Client: clientNoRegion, + ExpectedAddr: expectedNoTLSAddr, + ExpectedRegion: "foo", + ExpectedTLSServerName: "", + }, + { + Node: noTlsNode, + QueryOptions: optionRegion, + Client: clientRegion, + ExpectedAddr: expectedNoTLSAddr, + ExpectedRegion: "foo", + ExpectedTLSServerName: "", + }, + { + Node: noTlsNode, + QueryOptions: optionNoRegion, + Client: clientRegion, + ExpectedAddr: expectedNoTLSAddr, + ExpectedRegion: "bar", + ExpectedTLSServerName: "", + }, + } + + for _, c := range cases { + name := fmt.Sprintf("%s__%s__%s", c.ExpectedAddr, c.ExpectedRegion, c.ExpectedTLSServerName) + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + nodeClient, err := c.Client.getNodeClientImpl("testID", c.QueryOptions, c.Node) + assert.Nil(err) + assert.Equal(c.ExpectedRegion, nodeClient.config.Region) + assert.Equal(c.ExpectedAddr, nodeClient.config.Address) + assert.NotNil(nodeClient.config.TLSConfig) + assert.Equal(c.ExpectedTLSServerName, nodeClient.config.TLSConfig.TLSServerName) + }) + } +} From f5fb62c7ccf73c2ee0028bbc23835f5ea3c43f6d Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 29 Aug 2017 14:22:11 -0700 Subject: [PATCH 2/7] Node Client doesn't share HTTP client --- api/api.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/api/api.go b/api/api.go index 09c000a4a9b7..e396612297b9 100644 --- a/api/api.go +++ b/api/api.go @@ -94,9 +94,8 @@ type Config struct { // Region to use. If not provided, the default agent region is used. Region string - // HttpClient is the client to use. Default will be - // used if not provided. - HttpClient *http.Client + // httpClient is the client to use. Default will be used if not provided. + httpClient *http.Client // HttpAuth is the auth info to use for http access. HttpAuth *HttpBasicAuth @@ -117,10 +116,11 @@ func (c *Config) ClientConfig(region, address string, tlsEnabled bool) *Config { if tlsEnabled { scheme = "https" } + defaultConfig := DefaultConfig() config := &Config{ Address: fmt.Sprintf("%s://%s", scheme, address), Region: region, - HttpClient: c.HttpClient, + httpClient: defaultConfig.httpClient, HttpAuth: c.HttpAuth, WaitTime: c.WaitTime, TLSConfig: c.TLSConfig.Copy(), @@ -171,10 +171,10 @@ func (t *TLSConfig) Copy() *TLSConfig { func DefaultConfig() *Config { config := &Config{ Address: "http://127.0.0.1:4646", - HttpClient: cleanhttp.DefaultClient(), + httpClient: cleanhttp.DefaultClient(), TLSConfig: &TLSConfig{}, } - transport := config.HttpClient.Transport.(*http.Transport) + transport := config.httpClient.Transport.(*http.Transport) transport.TLSHandshakeTimeout = 10 * time.Second transport.TLSClientConfig = &tls.Config{ MinVersion: tls.VersionTLS12, @@ -226,7 +226,7 @@ func (c *Config) ConfigureTLS() error { if c.TLSConfig == nil { return nil } - if c.HttpClient == nil { + if c.httpClient == nil { return fmt.Errorf("config HTTP Client must be set") } @@ -245,7 +245,7 @@ func (c *Config) ConfigureTLS() error { } } - clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig + clientTLSConfig := c.httpClient.Transport.(*http.Transport).TLSClientConfig rootConfig := &rootcerts.Config{ CAFile: c.TLSConfig.CACert, CAPath: c.TLSConfig.CAPath, @@ -282,8 +282,8 @@ func NewClient(config *Config) (*Client, error) { return nil, fmt.Errorf("invalid address '%s': %v", config.Address, err) } - if config.HttpClient == nil { - config.HttpClient = defConfig.HttpClient + if config.httpClient == nil { + config.httpClient = defConfig.httpClient } // Configure the TLS cofigurations @@ -490,7 +490,7 @@ func (c *Client) doRequest(r *request) (time.Duration, *http.Response, error) { return 0, nil, err } start := time.Now() - resp, err := c.config.HttpClient.Do(req) + resp, err := c.config.httpClient.Do(req) diff := time.Now().Sub(start) // If the response is compressed, we swap the body's reader. From 5d65af523d096e0b6878fbf95397cb6f53eb2d13 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 29 Aug 2017 14:29:32 -0700 Subject: [PATCH 3/7] Check for errors initializing client for autocomplete --- command/alloc_status.go | 6 +++++- command/deployment_fail.go | 6 +++++- command/deployment_pause.go | 6 +++++- command/deployment_promote.go | 6 +++++- command/deployment_resume.go | 6 +++++- command/deployment_status.go | 6 +++++- command/eval_status.go | 10 +++++++++- command/fs.go | 6 +++++- command/inspect.go | 6 +++++- command/job_deployments.go | 6 +++++- command/job_dispatch.go | 6 +++++- command/job_history.go | 6 +++++- command/job_promote.go | 6 +++++- command/job_revert.go | 6 +++++- command/job_status.go | 6 +++++- command/logs.go | 6 +++++- command/node_drain.go | 6 +++++- command/node_status.go | 6 +++++- command/status.go | 6 +++++- command/stop.go | 6 +++++- 20 files changed, 104 insertions(+), 20 deletions(-) diff --git a/command/alloc_status.go b/command/alloc_status.go index 20987b16df91..21b4c15bad5e 100644 --- a/command/alloc_status.go +++ b/command/alloc_status.go @@ -72,7 +72,11 @@ func (c *AllocStatusCommand) AutocompleteFlags() complete.Flags { func (c *AllocStatusCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Allocs, nil) if err != nil { return []string{} diff --git a/command/deployment_fail.go b/command/deployment_fail.go index f1e10b399f8e..54cd40bda4f1 100644 --- a/command/deployment_fail.go +++ b/command/deployment_fail.go @@ -52,7 +52,11 @@ func (c *DeploymentFailCommand) AutocompleteFlags() complete.Flags { func (c *DeploymentFailCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Deployments, nil) if err != nil { return []string{} diff --git a/command/deployment_pause.go b/command/deployment_pause.go index 81c210658c3d..4da31c5e92f8 100644 --- a/command/deployment_pause.go +++ b/command/deployment_pause.go @@ -44,7 +44,11 @@ func (c *DeploymentPauseCommand) AutocompleteFlags() complete.Flags { func (c *DeploymentPauseCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Deployments, nil) if err != nil { return []string{} diff --git a/command/deployment_promote.go b/command/deployment_promote.go index b8cd24821632..9d83b3aaae5d 100644 --- a/command/deployment_promote.go +++ b/command/deployment_promote.go @@ -62,7 +62,11 @@ func (c *DeploymentPromoteCommand) AutocompleteFlags() complete.Flags { func (c *DeploymentPromoteCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Deployments, nil) if err != nil { return []string{} diff --git a/command/deployment_resume.go b/command/deployment_resume.go index b50c179c1d0c..d2902ddeb5a3 100644 --- a/command/deployment_resume.go +++ b/command/deployment_resume.go @@ -50,7 +50,11 @@ func (c *DeploymentResumeCommand) AutocompleteFlags() complete.Flags { func (c *DeploymentResumeCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Deployments, nil) if err != nil { return []string{} diff --git a/command/deployment_status.go b/command/deployment_status.go index 6294360fe623..68c47316ee5b 100644 --- a/command/deployment_status.go +++ b/command/deployment_status.go @@ -53,7 +53,11 @@ func (c *DeploymentStatusCommand) AutocompleteFlags() complete.Flags { func (c *DeploymentStatusCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Deployments, nil) if err != nil { return []string{} diff --git a/command/eval_status.go b/command/eval_status.go index 33b3d2cddab0..c11a796c4893 100644 --- a/command/eval_status.go +++ b/command/eval_status.go @@ -60,7 +60,15 @@ func (c *EvalStatusCommand) AutocompleteFlags() complete.Flags { func (c *EvalStatusCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Evals, nil) if err != nil { return []string{} diff --git a/command/fs.go b/command/fs.go index e9c0df6a478d..11ac2d12f71e 100644 --- a/command/fs.go +++ b/command/fs.go @@ -95,7 +95,11 @@ func (c *FSCommand) AutocompleteFlags() complete.Flags { func (f *FSCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := f.Meta.Client() + client, err := f.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Allocs, nil) if err != nil { return []string{} diff --git a/command/inspect.go b/command/inspect.go index e97f3c14985a..b16527b59f27 100644 --- a/command/inspect.go +++ b/command/inspect.go @@ -52,7 +52,11 @@ func (c *InspectCommand) AutocompleteFlags() complete.Flags { func (c *InspectCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} diff --git a/command/job_deployments.go b/command/job_deployments.go index 62d423876952..807b48efcf90 100644 --- a/command/job_deployments.go +++ b/command/job_deployments.go @@ -55,7 +55,11 @@ func (c *JobDeploymentsCommand) AutocompleteFlags() complete.Flags { func (c *JobDeploymentsCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} diff --git a/command/job_dispatch.go b/command/job_dispatch.go index 087adffe82ec..8bfe2a22c9c1 100644 --- a/command/job_dispatch.go +++ b/command/job_dispatch.go @@ -67,7 +67,11 @@ func (c *JobDispatchCommand) AutocompleteFlags() complete.Flags { func (c *JobDispatchCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} diff --git a/command/job_history.go b/command/job_history.go index 660443d473da..8a23ccc1b751 100644 --- a/command/job_history.go +++ b/command/job_history.go @@ -67,7 +67,11 @@ func (c *JobHistoryCommand) Autocompleteflags() complete.Flags { func (c *JobHistoryCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} diff --git a/command/job_promote.go b/command/job_promote.go index 0b0cca14e11a..80db6efa4011 100644 --- a/command/job_promote.go +++ b/command/job_promote.go @@ -63,7 +63,11 @@ func (c *JobPromoteCommand) AutocompleteFlags() complete.Flags { func (c *JobPromoteCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} diff --git a/command/job_revert.go b/command/job_revert.go index 68c7291f357a..57e3f1c67994 100644 --- a/command/job_revert.go +++ b/command/job_revert.go @@ -50,7 +50,11 @@ func (c *JobRevertCommand) AutocompleteFlags() complete.Flags { func (c *JobRevertCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} diff --git a/command/job_status.go b/command/job_status.go index 91a018b15778..0adc69ef39ac 100644 --- a/command/job_status.go +++ b/command/job_status.go @@ -72,7 +72,11 @@ func (c *JobStatusCommand) AutocompleteFlags() complete.Flags { func (c *JobStatusCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} diff --git a/command/logs.go b/command/logs.go index 36b5c974077b..183a43569a98 100644 --- a/command/logs.go +++ b/command/logs.go @@ -76,7 +76,11 @@ func (c *LogsCommand) AutocompleteFlags() complete.Flags { func (l *LogsCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := l.Meta.Client() + client, err := l.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Allocs, nil) if err != nil { return []string{} diff --git a/command/node_drain.go b/command/node_drain.go index 6d1e7410b1f8..5fdd58efc5ed 100644 --- a/command/node_drain.go +++ b/command/node_drain.go @@ -57,7 +57,11 @@ func (c *NodeDrainCommand) AutocompleteFlags() complete.Flags { func (c *NodeDrainCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Nodes, nil) if err != nil { return []string{} diff --git a/command/node_status.go b/command/node_status.go index 34dd1dbec7f7..8891f16f86b0 100644 --- a/command/node_status.go +++ b/command/node_status.go @@ -100,7 +100,11 @@ func (c *NodeStatusCommand) AutocompleteFlags() complete.Flags { func (c *NodeStatusCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Nodes, nil) if err != nil { return []string{} diff --git a/command/status.go b/command/status.go index c9774f447ea0..e4b96f29ef95 100644 --- a/command/status.go +++ b/command/status.go @@ -38,7 +38,11 @@ func (c *StatusCommand) AutocompleteFlags() complete.Flags { func (c *StatusCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.All, nil) if err != nil { return []string{} diff --git a/command/stop.go b/command/stop.go index 27bb61c5200e..258679fec3a1 100644 --- a/command/stop.go +++ b/command/stop.go @@ -63,7 +63,11 @@ func (c *StopCommand) AutocompleteFlags() complete.Flags { func (c *StopCommand) AutocompleteArgs() complete.Predictor { return complete.PredictFunc(func(a complete.Args) []string { - client, _ := c.Meta.Client() + client, err := c.Meta.Client() + if err != nil { + return nil + } + resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil) if err != nil { return []string{} From 734a73ee4ed3dcc96e7f23c5289a59b976574d90 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 29 Aug 2017 14:33:19 -0700 Subject: [PATCH 4/7] tls cluster --- dev/tls_cluster/certs/cfssl.json | 13 ++++++++++ dev/tls_cluster/certs/cli-key.pem | 5 ++++ dev/tls_cluster/certs/cli.csr | 6 +++++ dev/tls_cluster/certs/cli.pem | 12 +++++++++ dev/tls_cluster/certs/client-key.pem | 5 ++++ dev/tls_cluster/certs/client.csr | 6 +++++ dev/tls_cluster/certs/client.pem | 13 ++++++++++ dev/tls_cluster/certs/nomad-ca-key.pem | 5 ++++ dev/tls_cluster/certs/nomad-ca.csr | 9 +++++++ dev/tls_cluster/certs/nomad-ca.pem | 13 ++++++++++ dev/tls_cluster/certs/server-key.pem | 5 ++++ dev/tls_cluster/certs/server.csr | 6 +++++ dev/tls_cluster/certs/server.pem | 13 ++++++++++ dev/tls_cluster/client1.hcl | 34 ++++++++++++++++++++++++++ dev/tls_cluster/client2.hcl | 34 ++++++++++++++++++++++++++ dev/tls_cluster/server.hcl | 27 ++++++++++++++++++++ 16 files changed, 206 insertions(+) create mode 100644 dev/tls_cluster/certs/cfssl.json create mode 100644 dev/tls_cluster/certs/cli-key.pem create mode 100644 dev/tls_cluster/certs/cli.csr create mode 100644 dev/tls_cluster/certs/cli.pem create mode 100644 dev/tls_cluster/certs/client-key.pem create mode 100644 dev/tls_cluster/certs/client.csr create mode 100644 dev/tls_cluster/certs/client.pem create mode 100644 dev/tls_cluster/certs/nomad-ca-key.pem create mode 100644 dev/tls_cluster/certs/nomad-ca.csr create mode 100644 dev/tls_cluster/certs/nomad-ca.pem create mode 100644 dev/tls_cluster/certs/server-key.pem create mode 100644 dev/tls_cluster/certs/server.csr create mode 100644 dev/tls_cluster/certs/server.pem create mode 100644 dev/tls_cluster/client1.hcl create mode 100644 dev/tls_cluster/client2.hcl create mode 100644 dev/tls_cluster/server.hcl diff --git a/dev/tls_cluster/certs/cfssl.json b/dev/tls_cluster/certs/cfssl.json new file mode 100644 index 000000000000..6e438c9b9d6f --- /dev/null +++ b/dev/tls_cluster/certs/cfssl.json @@ -0,0 +1,13 @@ +{ + "signing": { + "default": { + "expiry": "87600h", + "usages": [ + "signing", + "key encipherment", + "server auth", + "client auth" + ] + } + } +} diff --git a/dev/tls_cluster/certs/cli-key.pem b/dev/tls_cluster/certs/cli-key.pem new file mode 100644 index 000000000000..a33b90991ae2 --- /dev/null +++ b/dev/tls_cluster/certs/cli-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEILf7p/j1fRxbYKNMic2SDg8gtxKshjT9n53v79RL6YswoAoGCCqGSM49 +AwEHoUQDQgAEk5UATh31iXNMatpNooVoBqNJI7skvN7iXqhBP9v6ysACnhAbLphi +PaZja5dqVIGpdX48B/lqvdz7bcgEHD3BTw== +-----END EC PRIVATE KEY----- diff --git a/dev/tls_cluster/certs/cli.csr b/dev/tls_cluster/certs/cli.csr new file mode 100644 index 000000000000..6519162d2fe1 --- /dev/null +++ b/dev/tls_cluster/certs/cli.csr @@ -0,0 +1,6 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIG7MGICAQAwADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJOVAE4d9YlzTGra +TaKFaAajSSO7JLze4l6oQT/b+srAAp4QGy6YYj2mY2uXalSBqXV+PAf5ar3c+23I +BBw9wU+gADAKBggqhkjOPQQDAgNJADBGAiEAjxZKImvamyiwlM71T5afwYrkXSKm +Qgu2mOBVBMmLG1gCIQD74Uu+PlDuRFA+WLiRgpy/3WJWd6C2KAqTs7PLGx4cGw== +-----END CERTIFICATE REQUEST----- diff --git a/dev/tls_cluster/certs/cli.pem b/dev/tls_cluster/certs/cli.pem new file mode 100644 index 000000000000..911608a875c2 --- /dev/null +++ b/dev/tls_cluster/certs/cli.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIByDCCAW+gAwIBAgIUHLtX9ysumbw3LCkxkKEzEH219p4wCgYIKoZIzj0EAwIw +SDELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNVBAcT +AkNBMRQwEgYDVQQDEwtleGFtcGxlLm5ldDAeFw0xNzA4MjkxODU1MDBaFw0xODA4 +MjkxODU1MDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASTlQBOHfWJc0xq +2k2ihWgGo0kjuyS83uJeqEE/2/rKwAKeEBsumGI9pmNrl2pUgal1fjwH+Wq93Ptt +yAQcPcFPo38wfTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG +CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFJK+IEBba+s+v3rV/bFn +tZsnvduWMB8GA1UdIwQYMBaAFH66XbZ49lhFbnq7yQMJQgj5HAq3MAoGCCqGSM49 +BAMCA0cAMEQCIDe1yWG5ulggBbp0Qu+oZqARua9fK6lvcY8Ke0In7BcsAiB6QKi7 +ScbOUk5rusXY3PlFBu8IKm6b/cA/sftohFewLA== +-----END CERTIFICATE----- diff --git a/dev/tls_cluster/certs/client-key.pem b/dev/tls_cluster/certs/client-key.pem new file mode 100644 index 000000000000..245cd617de83 --- /dev/null +++ b/dev/tls_cluster/certs/client-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEILtFfW7tRp9eDQvQbZV9k8PwHyOh7RnnsKGuZs32VVNhoAoGCCqGSM49 +AwEHoUQDQgAEj/NNTMe1CfzurUFgnc1tNLUvfzcRJy4bE827jLbvct3DIXtYOv8S +HOG+qdFhOyK1yqzb6Jv67jQ0nia5C6J3pQ== +-----END EC PRIVATE KEY----- diff --git a/dev/tls_cluster/certs/client.csr b/dev/tls_cluster/certs/client.csr new file mode 100644 index 000000000000..0cb4ccfcdc91 --- /dev/null +++ b/dev/tls_cluster/certs/client.csr @@ -0,0 +1,6 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIG6MGICAQAwADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI/zTUzHtQn87q1B +YJ3NbTS1L383EScuGxPNu4y273LdwyF7WDr/EhzhvqnRYTsitcqs2+ib+u40NJ4m +uQuid6WgADAKBggqhkjOPQQDAgNIADBFAiEA7G6tB30lrg46m+xOx/3CWahUmzKg +tY0L8HH4I+URPvkCIHUHwmuQZAhkXyzSpUdaHBi/45c4MsUzt38JE1864Y1D +-----END CERTIFICATE REQUEST----- diff --git a/dev/tls_cluster/certs/client.pem b/dev/tls_cluster/certs/client.pem new file mode 100644 index 000000000000..cbe8d5854939 --- /dev/null +++ b/dev/tls_cluster/certs/client.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB+TCCAZ+gAwIBAgIUGKlylRp2EYUnnMoRzkDLE8e/y4cwCgYIKoZIzj0EAwIw +SDELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNVBAcT +AkNBMRQwEgYDVQQDEwtleGFtcGxlLm5ldDAeFw0xNzA4MjkxODU1MDBaFw0yNzA4 +MjcxODU1MDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASP801Mx7UJ/O6t +QWCdzW00tS9/NxEnLhsTzbuMtu9y3cMhe1g6/xIc4b6p0WE7IrXKrNvom/ruNDSe +JrkLonelo4GuMIGrMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUKwkGHIIODtdTmpOL +EKwqBao7jq8wHwYDVR0jBBgwFoAUfrpdtnj2WEVuervJAwlCCPkcCrcwLAYDVR0R +BCUwI4IQY2xpZW50LmZvby5ub21hZIIJbG9jYWxob3N0hwR/AAABMAoGCCqGSM49 +BAMCA0gAMEUCIQCCHEeAyi6CCeK2eDMo40wgSUwz7tVjaSmZ/jj/lq2FwwIgeNK3 +d9b/cOpGCX1vVyRD9qkIO6eM228YGBqwUQLlQoY= +-----END CERTIFICATE----- diff --git a/dev/tls_cluster/certs/nomad-ca-key.pem b/dev/tls_cluster/certs/nomad-ca-key.pem new file mode 100644 index 000000000000..a1e6e99e2476 --- /dev/null +++ b/dev/tls_cluster/certs/nomad-ca-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIL0op5QMrXeB876AhIx/djGCNWMNpTCea1IMW3qVrADioAoGCCqGSM49 +AwEHoUQDQgAEPTNOV30bIUeCR4xvPn2duP4nz8RZg5SSfBqJ788Zo2jWwgUJ6unh +KSeEsQaiVMIL8PcPn2OATMgTllqVSm7ALg== +-----END EC PRIVATE KEY----- diff --git a/dev/tls_cluster/certs/nomad-ca.csr b/dev/tls_cluster/certs/nomad-ca.csr new file mode 100644 index 000000000000..9324b444b7e5 --- /dev/null +++ b/dev/tls_cluster/certs/nomad-ca.csr @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBPDCB5AIBADBIMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNU2FuIEZyYW5jaXNj +bzELMAkGA1UEBxMCQ0ExFDASBgNVBAMTC2V4YW1wbGUubmV0MFkwEwYHKoZIzj0C +AQYIKoZIzj0DAQcDQgAEPTNOV30bIUeCR4xvPn2duP4nz8RZg5SSfBqJ788Zo2jW +wgUJ6unhKSeEsQaiVMIL8PcPn2OATMgTllqVSm7ALqA6MDgGCSqGSIb3DQEJDjEr +MCkwJwYDVR0RBCAwHoILZXhhbXBsZS5uZXSCD3d3dy5leGFtcGxlLm5ldDAKBggq +hkjOPQQDAgNHADBEAiAqo8um1UGdK2JIM2ZY5LUEvFfULqEP+IANGaBPR36rVwIg +fi6F99QQBNwk0vmFhOEP1T01vajoM+Uwx6EhjyXBS7A= +-----END CERTIFICATE REQUEST----- diff --git a/dev/tls_cluster/certs/nomad-ca.pem b/dev/tls_cluster/certs/nomad-ca.pem new file mode 100644 index 000000000000..413356481168 --- /dev/null +++ b/dev/tls_cluster/certs/nomad-ca.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB+DCCAZ6gAwIBAgIUbGbARr8sjISnz/MjmGEX/0VQWZswCgYIKoZIzj0EAwIw +SDELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNVBAcT +AkNBMRQwEgYDVQQDEwtleGFtcGxlLm5ldDAeFw0xNzA4MjkxODUzMDBaFw0yMjA4 +MjgxODUzMDBaMEgxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1TYW4gRnJhbmNpc2Nv +MQswCQYDVQQHEwJDQTEUMBIGA1UEAxMLZXhhbXBsZS5uZXQwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAAQ9M05XfRshR4JHjG8+fZ24/ifPxFmDlJJ8GonvzxmjaNbC +BQnq6eEpJ4SxBqJUwgvw9w+fY4BMyBOWWpVKbsAuo2YwZDAOBgNVHQ8BAf8EBAMC +AQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQUfrpdtnj2WEVuervJAwlC +CPkcCrcwHwYDVR0jBBgwFoAUfrpdtnj2WEVuervJAwlCCPkcCrcwCgYIKoZIzj0E +AwIDSAAwRQIhAKRui2n4gf/f2ooffiKkyJ2EmMJtD2zfusZPL84Vf59PAiAJtTNv +3hEDL/ov9L0n0YfmmprA6ef8qqcet3TqidYVLA== +-----END CERTIFICATE----- diff --git a/dev/tls_cluster/certs/server-key.pem b/dev/tls_cluster/certs/server-key.pem new file mode 100644 index 000000000000..38db8941c254 --- /dev/null +++ b/dev/tls_cluster/certs/server-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEINOEjpNrhLHbQRMavODvn0nDMxVihn4QfLKlPApUbkUeoAoGCCqGSM49 +AwEHoUQDQgAEkIyNAlIpNvgNCtbSk5OIkbr+mF+RrNAFlzUKAEyxfht2nq5ea+Nj +yP0wXQ5IWP+tHjiiQToBezSBJnlLxTzA1w== +-----END EC PRIVATE KEY----- diff --git a/dev/tls_cluster/certs/server.csr b/dev/tls_cluster/certs/server.csr new file mode 100644 index 000000000000..d24973eb835a --- /dev/null +++ b/dev/tls_cluster/certs/server.csr @@ -0,0 +1,6 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIG7MGICAQAwADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJCMjQJSKTb4DQrW +0pOTiJG6/phfkazQBZc1CgBMsX4bdp6uXmvjY8j9MF0OSFj/rR44okE6AXs0gSZ5 +S8U8wNegADAKBggqhkjOPQQDAgNJADBGAiEA3HRmZwW//PUp2wor97hIa5cAb0Yq +EBFyqiUm9LdFzCsCIQCj5t+f+thVEvO5fQGILXBqq969KTefk9dVVQbLrcgxog== +-----END CERTIFICATE REQUEST----- diff --git a/dev/tls_cluster/certs/server.pem b/dev/tls_cluster/certs/server.pem new file mode 100644 index 000000000000..01f757a023b1 --- /dev/null +++ b/dev/tls_cluster/certs/server.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB+jCCAZ+gAwIBAgIUBvib9g3e/m/c7mZjiBE59CJJo6swCgYIKoZIzj0EAwIw +SDELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDVNhbiBGcmFuY2lzY28xCzAJBgNVBAcT +AkNBMRQwEgYDVQQDEwtleGFtcGxlLm5ldDAeFw0xNzA4MjkxODU0MDBaFw0yNzA4 +MjcxODU0MDBaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASQjI0CUik2+A0K +1tKTk4iRuv6YX5Gs0AWXNQoATLF+G3aerl5r42PI/TBdDkhY/60eOKJBOgF7NIEm +eUvFPMDXo4GuMIGrMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUeoR3h6dgHF6LaHQ+ +xjO85N8fZ28wHwYDVR0jBBgwFoAUfrpdtnj2WEVuervJAwlCCPkcCrcwLAYDVR0R +BCUwI4IQc2VydmVyLmZvby5ub21hZIIJbG9jYWxob3N0hwR/AAABMAoGCCqGSM49 +BAMCA0kAMEYCIQCa/ljHAZh0RpV8aPu/GkJOJge8Jij5MsWRDYYIVoeN0QIhANHL +uibsL7bNniqtD+2pccgxyPIjvrz18NOC/31KJy8d +-----END CERTIFICATE----- diff --git a/dev/tls_cluster/client1.hcl b/dev/tls_cluster/client1.hcl new file mode 100644 index 000000000000..7641092519f8 --- /dev/null +++ b/dev/tls_cluster/client1.hcl @@ -0,0 +1,34 @@ +# Increase log verbosity +log_level = "DEBUG" + +region = "foo" + +# Setup data dir +data_dir = "/tmp/client1" + +# Enable the client +client { + enabled = true + + # For demo assume we are talking to server1. For production, + # this should be like "nomad.service.consul:4647" and a system + # like Consul used for service discovery. + servers = ["127.0.0.1:4647"] +} + +# Modify our port to avoid a collision with server1 +ports { + http = 5656 +} + +tls { + http = true + rpc = true + + ca_file = "certs/nomad-ca.pem" + cert_file = "certs/client.pem" + key_file = "certs/client-key.pem" + + verify_server_hostname = true + verify_https_client = true +} diff --git a/dev/tls_cluster/client2.hcl b/dev/tls_cluster/client2.hcl new file mode 100644 index 000000000000..77087674bec7 --- /dev/null +++ b/dev/tls_cluster/client2.hcl @@ -0,0 +1,34 @@ +# Increase log verbosity +log_level = "DEBUG" + +region = "foo" + +# Setup data dir +data_dir = "/tmp/client2" + +# Enable the client +client { + enabled = true + + # For demo assume we are talking to server1. For production, + # this should be like "nomad.service.consul:4647" and a system + # like Consul used for service discovery. + servers = ["127.0.0.1:4647"] +} + +# Modify our port to avoid a collision with server1 and client1 +ports { + http = 5657 +} + +tls { + http = true + rpc = true + + ca_file = "certs/nomad-ca.pem" + cert_file = "certs/client.pem" + key_file = "certs/client-key.pem" + + verify_server_hostname = true + verify_https_client = true +} diff --git a/dev/tls_cluster/server.hcl b/dev/tls_cluster/server.hcl new file mode 100644 index 000000000000..0b284779d73b --- /dev/null +++ b/dev/tls_cluster/server.hcl @@ -0,0 +1,27 @@ +# Increase log verbosity +log_level = "DEBUG" + +region = "foo" + +# Setup data dir +data_dir = "/tmp/server1" + +# Enable the server +server { + enabled = true + + # Self-elect, should be 3 or 5 for production + bootstrap_expect = 1 +} + +tls { + http = true + rpc = true + + ca_file = "certs/nomad-ca.pem" + cert_file = "certs/server.pem" + key_file = "certs/server-key.pem" + + verify_server_hostname = true + verify_https_client = true +} From 9e63e7b7cec7ac1467f7eba7d52527fe364dfc6b Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 29 Aug 2017 15:49:39 -0700 Subject: [PATCH 5/7] Add readmes --- dev/README.md | 3 +++ dev/tls_cluster/README.md | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 dev/tls_cluster/README.md diff --git a/dev/README.md b/dev/README.md index 9bb582119d3f..ea43cdc8a88f 100644 --- a/dev/README.md +++ b/dev/README.md @@ -10,5 +10,8 @@ files. At a high-level the use case for each package is as follows: spin up Nomad clients in Docker containers. This provides a simple mechanism to create a Nomad cluster locally. +* `tls_cluster`: This package provides Nomad client configs and certificates to + run a TLS enabled cluster. + * `vault`: This package provides basic Vault configuration files for use in configuring a Vault server when testing Nomad and Vault integrations. diff --git a/dev/tls_cluster/README.md b/dev/tls_cluster/README.md new file mode 100644 index 000000000000..13233b0fe603 --- /dev/null +++ b/dev/tls_cluster/README.md @@ -0,0 +1,2 @@ +Simply run the Nomad Server and Clients from this directory from this server and +the created cluster will be using TLS. From 0fa161be2244f09eb2aeb18960bba84dcc67b6fc Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 29 Aug 2017 15:50:52 -0700 Subject: [PATCH 6/7] Update README.md --- dev/tls_cluster/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tls_cluster/README.md b/dev/tls_cluster/README.md index 13233b0fe603..1b572939be6c 100644 --- a/dev/tls_cluster/README.md +++ b/dev/tls_cluster/README.md @@ -1,2 +1 @@ -Simply run the Nomad Server and Clients from this directory from this server and -the created cluster will be using TLS. +Simply run the Nomad Server and Clients from this directory and the created cluster will be using TLS. From d759dc8100e1107b288e87c5ee5c4ee1e691a295 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 29 Aug 2017 16:09:53 -0700 Subject: [PATCH 7/7] Address feedback --- api/api.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/api/api.go b/api/api.go index e396612297b9..2c957695cc42 100644 --- a/api/api.go +++ b/api/api.go @@ -308,12 +308,13 @@ func (c *Client) GetNodeClient(nodeID string, q *QueryOptions) (*Client, error) return c.getNodeClientImpl(nodeID, q, c.Nodes().Info) } -// nodeLookup is used to lookup a node +// nodeLookup is the definition of a function used to lookup a node. This is +// largely used to mock the lookup in tests. type nodeLookup func(nodeID string, q *QueryOptions) (*Node, *QueryMeta, error) // getNodeClientImpl is the implementation of creating a API client for -// contacting a node. It is takes a function to lookup the node such that it can -// be mocked during tests. +// contacting a node. It takes a function to lookup the node such that it can be +// mocked during tests. func (c *Client) getNodeClientImpl(nodeID string, q *QueryOptions, lookup nodeLookup) (*Client, error) { node, _, err := lookup(nodeID, q) if err != nil { @@ -326,12 +327,16 @@ func (c *Client) getNodeClientImpl(nodeID string, q *QueryOptions, lookup nodeLo return nil, fmt.Errorf("http addr of node %q (%s) is not advertised", node.Name, nodeID) } - region := c.config.Region - if q != nil && q.Region != "" { + var region string + switch { + case q != nil && q.Region != "": + // Prefer the region set in the query parameter region = q.Region - } - - if region == "" { + case c.config.Region != "": + // If the client is configured for a particular region use that + region = c.config.Region + default: + // No region information is given so use the default. region = "global" }