From e9f4394df7fa954ca815612da50c6f1822c70a2e Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 8 Apr 2022 09:08:13 +0200 Subject: [PATCH 01/70] Working MVP - Admin Provided Bootstrap Token Admin Provided Bootstrap Token --- api/acl.go | 29 ++++++++++++++++++++++++++++- command/acl_bootstrap.go | 16 +++++++++++++--- command/agent/acl_endpoint.go | 27 ++++++++++++++++++++++++++- nomad/acl_endpoint.go | 7 +++++++ nomad/structs/acl.go | 4 ++++ nomad/structs/structs.go | 1 + 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 nomad/structs/acl.go diff --git a/api/acl.go b/api/acl.go index 0652e409c527..efa5665df276 100644 --- a/api/acl.go +++ b/api/acl.go @@ -2,6 +2,7 @@ package api import ( "fmt" + "strings" "time" ) @@ -72,9 +73,35 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } +// CSISecrets contain optional additional credentials that may be needed by +// the Bootstrap Command. +// TODO +// These values will be redacted when reported in the +// API or in Nomad's logs +type ACLSecrets map[string]string +type BootstrapRequest struct { + Secrets ACLSecrets + WriteRequest +} + +func (q *WriteOptions) SetHeadersFromBootstrapSecrets(secrets ACLSecrets) { + pairs := []string{} + for k, v := range secrets { + pairs = append(pairs, fmt.Sprintf("%v=%v", k, v)) + } + if q.Headers == nil { + q.Headers = map[string]string{} + } + q.Headers["X-Nomad-BOOT-Secrets"] = strings.Join(pairs, ",") +} + // Bootstrap is used to get the initial bootstrap token -func (a *ACLTokens) Bootstrap(q *WriteOptions) (*ACLToken, *WriteMeta, error) { +func (a *ACLTokens) Bootstrap(req *BootstrapRequest, q *WriteOptions) (*ACLToken, *WriteMeta, error) { + if q == nil { + q = &WriteOptions{} + } var resp ACLToken + q.SetHeadersFromBootstrapSecrets(req.Secrets) wm, err := a.client.write("/v1/acl/bootstrap", nil, &resp, q) if err != nil { return nil, nil, err diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 85dbc69bffd5..505fd910474b 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -37,8 +37,9 @@ Bootstrap Options: func (c *ACLBootstrapCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ - "-json": complete.PredictNothing, - "-t": complete.PredictAnything, + "-json": complete.PredictNothing, + "-t": complete.PredictAnything, + "-token": complete.PredictAnything, }) } @@ -57,12 +58,14 @@ func (c *ACLBootstrapCommand) Run(args []string) int { var ( json bool tmpl string + tkn string ) flags := c.Meta.FlagSet(c.Name(), FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&json, "json", false, "") flags.StringVar(&tmpl, "t", "", "") + flags.StringVar(&tkn, "tkn", "", "") if err := flags.Parse(args); err != nil { return 1 } @@ -82,8 +85,15 @@ func (c *ACLBootstrapCommand) Run(args []string) int { return 1 } + // LANCES HACK!!!!! BEWARE + var BootStrapSecret map[string]string + BootStrapSecret = make(map[string]string) + BootStrapSecret["bootstraptoken"] = tkn + btkn := api.BootstrapRequest{} + btkn.Secrets = BootStrapSecret + // Get the bootstrap token - token, _, err := client.ACLTokens().Bootstrap(nil) + token, _, err := client.ACLTokens().Bootstrap(&btkn, nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error bootstrapping: %s", err)) return 1 diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index c89e6fe2a25f..d86fd9a8394d 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -138,8 +138,11 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque return nil, CodedError(405, ErrInvalidMethod) } + secrets := parseACLSecrets(req) // Format the request - args := structs.ACLTokenBootstrapRequest{} + args := structs.ACLTokenBootstrapRequest{ + Secrets: secrets, + } s.parseWriteRequest(req, &args.WriteRequest) var out structs.ACLTokenUpsertResponse @@ -316,3 +319,25 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } + +// parseACLSecrets extracts a map of k/v pairs from the ACL secrets +// header. Silently ignores invalid secrets +func parseACLSecrets(req *http.Request) structs.ACLSecrets { + secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + if secretsHeader == "" { + return nil + } + + secrets := map[string]string{} + secretkvs := strings.Split(secretsHeader, ",") + for _, secretkv := range secretkvs { + kv := strings.Split(secretkv, "=") + if len(kv) == 2 { + secrets[kv[0]] = kv[1] + } + } + if len(secrets) == 0 { + return nil + } + return structs.ACLSecrets(secrets) +} diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index c5df70e29c0f..4ba537394688 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -353,6 +353,7 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A return aclDisabled } args.Region = a.srv.config.AuthoritativeRegion + providedTokenID := args.Secrets["bootstraptoken"] if done, err := a.srv.forward("ACL.Bootstrap", args, args, reply); done { return err @@ -396,6 +397,12 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A Global: true, CreateTime: time.Now().UTC(), } + + //if a token has been passed in from the comand line overwrite the created one. + if providedTokenID != "" { + args.Token.SecretID = providedTokenID + } + args.Token.SetHash() // Update via Raft diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go new file mode 100644 index 000000000000..932742d8d0d9 --- /dev/null +++ b/nomad/structs/acl.go @@ -0,0 +1,4 @@ +package structs + +// ACLSecrets contain optional additional configuration that can be used. +type ACLSecrets map[string]string diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 29dfdc25bed8..d46cf2cf7f28 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -11914,6 +11914,7 @@ type ACLTokenDeleteRequest struct { type ACLTokenBootstrapRequest struct { Token *ACLToken // Not client specifiable ResetIndex uint64 // Reset index is used to clear the bootstrap token + Secrets ACLSecrets WriteRequest } From cd6272687dd107a7094caf92f364e6c9d644349c Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 8 Apr 2022 13:45:35 +0200 Subject: [PATCH 02/70] Update acl.go Check for acl token in request --- api/acl.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/acl.go b/api/acl.go index efa5665df276..537a05d77c10 100644 --- a/api/acl.go +++ b/api/acl.go @@ -101,7 +101,11 @@ func (a *ACLTokens) Bootstrap(req *BootstrapRequest, q *WriteOptions) (*ACLToken q = &WriteOptions{} } var resp ACLToken - q.SetHeadersFromBootstrapSecrets(req.Secrets) + // Test if token is in the request. + if req != nil { + // TODO ADD Validation for UUID here. + q.SetHeadersFromBootstrapSecrets(req.Secrets) + } wm, err := a.client.write("/v1/acl/bootstrap", nil, &resp, q) if err != nil { return nil, nil, err From 0722f7222d2cb4a5bc729b09a8d2cccfc262f765 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 8 Apr 2022 18:20:15 +0200 Subject: [PATCH 03/70] Update acl_bootstrap.go Update the Information for the Autocomplete flags --- command/acl_bootstrap.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 505fd910474b..1c4d0febc915 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -30,6 +30,9 @@ Bootstrap Options: -t Format and display the bootstrap response using a Go template. + -tkn + Provide an operator generated management token. + ` return strings.TrimSpace(helpText) } @@ -37,9 +40,9 @@ Bootstrap Options: func (c *ACLBootstrapCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ - "-json": complete.PredictNothing, - "-t": complete.PredictAnything, - "-token": complete.PredictAnything, + "-json": complete.PredictNothing, + "-t": complete.PredictAnything, + "-tkn": complete.PredictAnything, }) } From cc0b3a4403fce94b4cbfcc962bb46780247511ad Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sun, 10 Apr 2022 11:02:42 +0200 Subject: [PATCH 04/70] Update acl_bootstrap.go Apply Suggested changes by S1021: should merge variable declaration with assignment on next line (gosimple) --- command/acl_bootstrap.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 1c4d0febc915..b95f4923213e 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -89,8 +89,7 @@ func (c *ACLBootstrapCommand) Run(args []string) int { } // LANCES HACK!!!!! BEWARE - var BootStrapSecret map[string]string - BootStrapSecret = make(map[string]string) + BootStrapSecret := make(map[string]string) BootStrapSecret["bootstraptoken"] = tkn btkn := api.BootstrapRequest{} btkn.Secrets = BootStrapSecret From eb0699a5e28afef0890a8c2da2366da2f73bd493 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 20:28:19 +0200 Subject: [PATCH 05/70] Update the flag name and some comments --- api/acl.go | 7 ++++--- command/acl_bootstrap.go | 20 ++++++++++---------- nomad/acl_endpoint.go | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/api/acl.go b/api/acl.go index 537a05d77c10..a02f8b5c53c9 100644 --- a/api/acl.go +++ b/api/acl.go @@ -73,12 +73,13 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } -// CSISecrets contain optional additional credentials that may be needed by +// ACLSecrets contain optional additional credentials that may be needed by // the Bootstrap Command. // TODO // These values will be redacted when reported in the // API or in Nomad's logs type ACLSecrets map[string]string + type BootstrapRequest struct { Secrets ACLSecrets WriteRequest @@ -92,10 +93,10 @@ func (q *WriteOptions) SetHeadersFromBootstrapSecrets(secrets ACLSecrets) { if q.Headers == nil { q.Headers = map[string]string{} } - q.Headers["X-Nomad-BOOT-Secrets"] = strings.Join(pairs, ",") + q.Headers["X-Nomad-Boostrap-Token"] = strings.Join(pairs, ",") } -// Bootstrap is used to get the initial bootstrap token +// Bootstrap is used to get the initial bootstrap token or pass in the one that was provided in the API func (a *ACLTokens) Bootstrap(req *BootstrapRequest, q *WriteOptions) (*ACLToken, *WriteMeta, error) { if q == nil { q = &WriteOptions{} diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index b95f4923213e..2847dda6a12e 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -30,7 +30,7 @@ Bootstrap Options: -t Format and display the bootstrap response using a Go template. - -tkn + -bootstrap-token Provide an operator generated management token. ` @@ -40,9 +40,9 @@ Bootstrap Options: func (c *ACLBootstrapCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ - "-json": complete.PredictNothing, - "-t": complete.PredictAnything, - "-tkn": complete.PredictAnything, + "-json": complete.PredictNothing, + "-t": complete.PredictAnything, + "-bootstrap-token": complete.PredictAnything, }) } @@ -59,16 +59,16 @@ func (c *ACLBootstrapCommand) Name() string { return "acl bootstrap" } func (c *ACLBootstrapCommand) Run(args []string) int { var ( - json bool - tmpl string - tkn string + json bool + tmpl string + bootstraptoken string ) flags := c.Meta.FlagSet(c.Name(), FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&json, "json", false, "") flags.StringVar(&tmpl, "t", "", "") - flags.StringVar(&tkn, "tkn", "", "") + flags.StringVar(&bootstraptoken, "bootstrap-token", "", "") if err := flags.Parse(args); err != nil { return 1 } @@ -88,9 +88,9 @@ func (c *ACLBootstrapCommand) Run(args []string) int { return 1 } - // LANCES HACK!!!!! BEWARE + // Take the provided token and prepare it for the query. BootStrapSecret := make(map[string]string) - BootStrapSecret["bootstraptoken"] = tkn + BootStrapSecret["bootstraptoken"] = bootstraptoken btkn := api.BootstrapRequest{} btkn.Secrets = BootStrapSecret diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index 4ba537394688..20bc9a5bdb49 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -398,7 +398,7 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A CreateTime: time.Now().UTC(), } - //if a token has been passed in from the comand line overwrite the created one. + // if a token has been passed in from the API overwrite the generated one. if providedTokenID != "" { args.Token.SecretID = providedTokenID } From 67ca953f0e50d0d5b8d345bd580c62984e38bc35 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:47:11 +0200 Subject: [PATCH 06/70] Updated the header name in the agent --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index d86fd9a8394d..54993af8cc91 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") if secretsHeader == "" { return nil } From e4a69241196b8c1d10f206e0e3afc30ecf874629 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:49:35 +0200 Subject: [PATCH 07/70] Update Header Name Typo Copy Paste Error --- api/acl.go | 2 +- command/agent/acl_endpoint.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/acl.go b/api/acl.go index a02f8b5c53c9..55808f98f247 100644 --- a/api/acl.go +++ b/api/acl.go @@ -93,7 +93,7 @@ func (q *WriteOptions) SetHeadersFromBootstrapSecrets(secrets ACLSecrets) { if q.Headers == nil { q.Headers = map[string]string{} } - q.Headers["X-Nomad-Boostrap-Token"] = strings.Join(pairs, ",") + q.Headers["X-Nomad-Bootstrap-Token"] = strings.Join(pairs, ",") } // Bootstrap is used to get the initial bootstrap token or pass in the one that was provided in the API diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 54993af8cc91..dedddb873e21 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") + secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") if secretsHeader == "" { return nil } From 8b046dec9d31664720a6628b8f23fa63337be96f Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 20:28:55 +0200 Subject: [PATCH 08/70] Validate ProvidedToken is a UUID --- nomad/acl_endpoint.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index 20bc9a5bdb49..8b9e1c4ff33b 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -6,6 +6,7 @@ import ( "net/http" "os" "path/filepath" + "regexp" "strings" "time" @@ -400,7 +401,13 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A // if a token has been passed in from the API overwrite the generated one. if providedTokenID != "" { - args.Token.SecretID = providedTokenID + matched, err := regexp.MatchString( + "[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}", providedTokenID) + if matched { + args.Token.SecretID = providedTokenID + } else { + return structs.NewErrRPCCodedf(400, "invalid acl token: %v", err) + } } args.Token.SetHash() From c435389f7df208b8aae417554626fad9b695e6ce Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 20:54:49 +0200 Subject: [PATCH 09/70] Update acl_endpoint.go Use the built in helper function to test for a valid UUID --- nomad/acl_endpoint.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index 8b9e1c4ff33b..f7e991f27dcb 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -6,7 +6,6 @@ import ( "net/http" "os" "path/filepath" - "regexp" "strings" "time" @@ -14,6 +13,7 @@ import ( log "github.com/hashicorp/go-hclog" memdb "github.com/hashicorp/go-memdb" policy "github.com/hashicorp/nomad/acl" + "github.com/hashicorp/nomad/helper" "github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/nomad/state" "github.com/hashicorp/nomad/nomad/state/paginator" @@ -401,9 +401,7 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A // if a token has been passed in from the API overwrite the generated one. if providedTokenID != "" { - matched, err := regexp.MatchString( - "[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}", providedTokenID) - if matched { + if helper.IsUUID(providedTokenID) { args.Token.SecretID = providedTokenID } else { return structs.NewErrRPCCodedf(400, "invalid acl token: %v", err) From 7143fa29fe6c2982706e6570bedcf952fb2c5ebd Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 22:48:00 +0200 Subject: [PATCH 10/70] Refactor the ACL Bootstrap token code Removed unnecessary structs. Refactored the SetHeaders code to use just one secret. Removed parseACLSectrets function as redundant Removed the ACLSecrets Struct --- api/acl.go | 17 +++++------------ command/acl_bootstrap.go | 6 ++---- command/agent/acl_endpoint.go | 26 ++------------------------ nomad/acl_endpoint.go | 2 +- nomad/structs/acl.go | 4 ---- nomad/structs/structs.go | 2 +- 6 files changed, 11 insertions(+), 46 deletions(-) delete mode 100644 nomad/structs/acl.go diff --git a/api/acl.go b/api/acl.go index 55808f98f247..9e7a380214bd 100644 --- a/api/acl.go +++ b/api/acl.go @@ -2,7 +2,6 @@ package api import ( "fmt" - "strings" "time" ) @@ -78,22 +77,17 @@ func (c *Client) ACLTokens() *ACLTokens { // TODO // These values will be redacted when reported in the // API or in Nomad's logs -type ACLSecrets map[string]string +// type ACLSecrets map[string]string type BootstrapRequest struct { - Secrets ACLSecrets - WriteRequest + Secret string } -func (q *WriteOptions) SetHeadersFromBootstrapSecrets(secrets ACLSecrets) { - pairs := []string{} - for k, v := range secrets { - pairs = append(pairs, fmt.Sprintf("%v=%v", k, v)) - } +func (q *WriteOptions) SetHeadersFromBootstrapSecret(bootstraptoken string) { if q.Headers == nil { q.Headers = map[string]string{} } - q.Headers["X-Nomad-Bootstrap-Token"] = strings.Join(pairs, ",") + q.Headers["X-Nomad-Bootstrap-Token"] = bootstraptoken } // Bootstrap is used to get the initial bootstrap token or pass in the one that was provided in the API @@ -104,8 +98,7 @@ func (a *ACLTokens) Bootstrap(req *BootstrapRequest, q *WriteOptions) (*ACLToken var resp ACLToken // Test if token is in the request. if req != nil { - // TODO ADD Validation for UUID here. - q.SetHeadersFromBootstrapSecrets(req.Secrets) + q.SetHeadersFromBootstrapSecret(req.Secret) } wm, err := a.client.write("/v1/acl/bootstrap", nil, &resp, q) if err != nil { diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 2847dda6a12e..f2fa14c42e64 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -88,11 +88,9 @@ func (c *ACLBootstrapCommand) Run(args []string) int { return 1 } - // Take the provided token and prepare it for the query. - BootStrapSecret := make(map[string]string) - BootStrapSecret["bootstraptoken"] = bootstraptoken + // Take the provided ACL token and prepare it for the query. btkn := api.BootstrapRequest{} - btkn.Secrets = BootStrapSecret + btkn.Secret = bootstraptoken // Get the bootstrap token token, _, err := client.ACLTokens().Bootstrap(&btkn, nil) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index dedddb873e21..6e2248502ff8 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -138,10 +138,10 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque return nil, CodedError(405, ErrInvalidMethod) } - secrets := parseACLSecrets(req) + secret := req.Header.Get("X-Nomad-Bootstrap-Token") // Format the request args := structs.ACLTokenBootstrapRequest{ - Secrets: secrets, + Secret: secret, } s.parseWriteRequest(req, &args.WriteRequest) @@ -319,25 +319,3 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } - -// parseACLSecrets extracts a map of k/v pairs from the ACL secrets -// header. Silently ignores invalid secrets -func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") - if secretsHeader == "" { - return nil - } - - secrets := map[string]string{} - secretkvs := strings.Split(secretsHeader, ",") - for _, secretkv := range secretkvs { - kv := strings.Split(secretkv, "=") - if len(kv) == 2 { - secrets[kv[0]] = kv[1] - } - } - if len(secrets) == 0 { - return nil - } - return structs.ACLSecrets(secrets) -} diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index f7e991f27dcb..5e98c61d8919 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -354,7 +354,7 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A return aclDisabled } args.Region = a.srv.config.AuthoritativeRegion - providedTokenID := args.Secrets["bootstraptoken"] + providedTokenID := args.Secret if done, err := a.srv.forward("ACL.Bootstrap", args, args, reply); done { return err diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go deleted file mode 100644 index 932742d8d0d9..000000000000 --- a/nomad/structs/acl.go +++ /dev/null @@ -1,4 +0,0 @@ -package structs - -// ACLSecrets contain optional additional configuration that can be used. -type ACLSecrets map[string]string diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index d46cf2cf7f28..5c70dd7cb5f6 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -11914,7 +11914,7 @@ type ACLTokenDeleteRequest struct { type ACLTokenBootstrapRequest struct { Token *ACLToken // Not client specifiable ResetIndex uint64 // Reset index is used to clear the bootstrap token - Secrets ACLSecrets + Secret string WriteRequest } From 2198fdfd659dc262740f6af3e4164b6b6f13fe6d Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 23:45:11 +0200 Subject: [PATCH 11/70] Add Additional field to allow current test to pass --- api/api_test.go | 2 +- internal/testing/apitests/api_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/api_test.go b/api/api_test.go index 7b5d35346e53..37c161083e92 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -40,7 +40,7 @@ func makeACLClient(t *testing.T, cb1 configCallback, }) // Get the root token - root, _, err := client.ACLTokens().Bootstrap(nil) + root, _, err := client.ACLTokens().Bootstrap(nil, nil) if err != nil { t.Fatalf("failed to bootstrap ACLs: %v", err) } diff --git a/internal/testing/apitests/api_test.go b/internal/testing/apitests/api_test.go index dcac8a63f990..98029ec26619 100644 --- a/internal/testing/apitests/api_test.go +++ b/internal/testing/apitests/api_test.go @@ -26,7 +26,7 @@ func makeACLClient(t *testing.T, cb1 configCallback, }) // Get the root token - root, _, err := client.ACLTokens().Bootstrap(nil) + root, _, err := client.ACLTokens().Bootstrap(nil, nil) if err != nil { t.Fatalf("failed to bootstrap ACLs: %v", err) } From 57ea2fe2adef12aca8ee21a7617395eca82cf27f Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 8 Apr 2022 09:08:13 +0200 Subject: [PATCH 12/70] Working MVP - Admin Provided Bootstrap Token Admin Provided Bootstrap Token --- api/acl.go | 3 --- command/agent/acl_endpoint.go | 22 ++++++++++++++++++++++ nomad/structs/acl.go | 4 ++++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 nomad/structs/acl.go diff --git a/api/acl.go b/api/acl.go index 9e7a380214bd..0804c7a93c92 100644 --- a/api/acl.go +++ b/api/acl.go @@ -72,12 +72,9 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } -// ACLSecrets contain optional additional credentials that may be needed by -// the Bootstrap Command. // TODO // These values will be redacted when reported in the // API or in Nomad's logs -// type ACLSecrets map[string]string type BootstrapRequest struct { Secret string diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 6e2248502ff8..4a7955b56964 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -319,3 +319,25 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } + +// parseACLSecrets extracts a map of k/v pairs from the ACL secrets +// header. Silently ignores invalid secrets +func parseACLSecrets(req *http.Request) structs.ACLSecrets { + secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + if secretsHeader == "" { + return nil + } + + secrets := map[string]string{} + secretkvs := strings.Split(secretsHeader, ",") + for _, secretkv := range secretkvs { + kv := strings.Split(secretkv, "=") + if len(kv) == 2 { + secrets[kv[0]] = kv[1] + } + } + if len(secrets) == 0 { + return nil + } + return structs.ACLSecrets(secrets) +} diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go new file mode 100644 index 000000000000..932742d8d0d9 --- /dev/null +++ b/nomad/structs/acl.go @@ -0,0 +1,4 @@ +package structs + +// ACLSecrets contain optional additional configuration that can be used. +type ACLSecrets map[string]string From e85c10443da48dc37e63a3c7f270a892daf4a92d Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 20:28:19 +0200 Subject: [PATCH 13/70] Update the flag name and some comments --- api/acl.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/acl.go b/api/acl.go index 0804c7a93c92..47f7781b9df7 100644 --- a/api/acl.go +++ b/api/acl.go @@ -72,9 +72,18 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } +<<<<<<< HEAD // TODO // These values will be redacted when reported in the // API or in Nomad's logs +======= +// ACLSecrets contain optional additional credentials that may be needed by +// the Bootstrap Command. +// TODO +// These values will be redacted when reported in the +// API or in Nomad's logs +type ACLSecrets map[string]string +>>>>>>> 1dc597bbb (Update the flag name and some comments) type BootstrapRequest struct { Secret string From 7a350379e8c3b1b2ab13b9c3ce0f482ab4ca37fd Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:47:11 +0200 Subject: [PATCH 14/70] Updated the header name in the agent --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 4a7955b56964..9aa8814faf70 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") if secretsHeader == "" { return nil } From e4242ae6bd7d7e5abc3f3f55ee497d4e755cdc41 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:49:35 +0200 Subject: [PATCH 15/70] Update Header Name Typo Copy Paste Error --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 9aa8814faf70..6c9e94fdb136 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") + secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") if secretsHeader == "" { return nil } From 111181dc21dc978fe8945f0288efe32436566ab5 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 20:28:55 +0200 Subject: [PATCH 16/70] Validate ProvidedToken is a UUID --- api/acl.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/api/acl.go b/api/acl.go index 47f7781b9df7..0804c7a93c92 100644 --- a/api/acl.go +++ b/api/acl.go @@ -72,18 +72,9 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } -<<<<<<< HEAD // TODO // These values will be redacted when reported in the // API or in Nomad's logs -======= -// ACLSecrets contain optional additional credentials that may be needed by -// the Bootstrap Command. -// TODO -// These values will be redacted when reported in the -// API or in Nomad's logs -type ACLSecrets map[string]string ->>>>>>> 1dc597bbb (Update the flag name and some comments) type BootstrapRequest struct { Secret string From ec6115d02a9e5a3c9ab49009262d6a894366aec0 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 22:48:00 +0200 Subject: [PATCH 17/70] Refactor the ACL Bootstrap token code Removed unnecessary structs. Refactored the SetHeaders code to use just one secret. Removed parseACLSectrets function as redundant Removed the ACLSecrets Struct --- command/agent/acl_endpoint.go | 22 ---------------------- nomad/structs/acl.go | 4 ---- 2 files changed, 26 deletions(-) delete mode 100644 nomad/structs/acl.go diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 6c9e94fdb136..6e2248502ff8 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -319,25 +319,3 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } - -// parseACLSecrets extracts a map of k/v pairs from the ACL secrets -// header. Silently ignores invalid secrets -func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") - if secretsHeader == "" { - return nil - } - - secrets := map[string]string{} - secretkvs := strings.Split(secretsHeader, ",") - for _, secretkv := range secretkvs { - kv := strings.Split(secretkv, "=") - if len(kv) == 2 { - secrets[kv[0]] = kv[1] - } - } - if len(secrets) == 0 { - return nil - } - return structs.ACLSecrets(secrets) -} diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go deleted file mode 100644 index 932742d8d0d9..000000000000 --- a/nomad/structs/acl.go +++ /dev/null @@ -1,4 +0,0 @@ -package structs - -// ACLSecrets contain optional additional configuration that can be used. -type ACLSecrets map[string]string From 908544b8e72dfab0223cca004d482c10d0f6c445 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sun, 15 May 2022 14:39:44 +0200 Subject: [PATCH 18/70] Update acl_bootstrap_test.go Add command Tests for Valid and Invalid operator supplied bootstrap tokens --- command/acl_bootstrap_test.go | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/command/acl_bootstrap_test.go b/command/acl_bootstrap_test.go index c972f4488b68..f115c31506e7 100644 --- a/command/acl_bootstrap_test.go +++ b/command/acl_bootstrap_test.go @@ -1,10 +1,12 @@ package command import ( + "strings" "testing" "github.com/hashicorp/nomad/ci" "github.com/hashicorp/nomad/command/agent" + "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" "github.com/stretchr/testify/assert" ) @@ -76,3 +78,67 @@ func TestACLBootstrapCommand_NonACLServer(t *testing.T) { out := ui.OutputWriter.String() assert.NotContains(out, "Secret ID") } + +// Attempting to bootstrap the server with an operator provided token should +// return the same token in the result. +func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { + ci.Parallel(t) + assert := assert.New(t) + + // create a acl-enabled server without bootstrapping the token + config := func(c *agent.Config) { + c.ACL.Enabled = true + c.ACL.PolicyTTL = 0 + } + + // create a valid token + mockToken := mock.ACLToken() + + srv, _, url := testServer(t, true, config) + defer srv.Shutdown() + + assert.Nil(srv.RootToken) + + ui := cli.NewMockUi() + cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + code := cmd.Run([]string{"-address=" + url, "-bootstrap-token=" + mockToken.SecretID}) + assert.Equal(0, code) + + out := ui.OutputWriter.String() + if !strings.Contains(out, mockToken.SecretID) { + t.Fatalf("expected "+mockToken.SecretID+" output, got: %s", out) + } +} + +// Attempting to bootstrap the server with an invalid operator provided token should +// fail. +func TestACLBootstrapCommand_WithBadOperatorBootstrapToken(t *testing.T) { + ci.Parallel(t) + assert := assert.New(t) + + // create a acl-enabled server without bootstrapping the token + config := func(c *agent.Config) { + c.ACL.Enabled = true + c.ACL.PolicyTTL = 0 + } + + // create a valid token + invalidToken := "invalid-token" + + srv, _, url := testServer(t, true, config) + defer srv.Shutdown() + + assert.Nil(srv.RootToken) + + ui := cli.NewMockUi() + cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + code := cmd.Run([]string{"-address=" + url, "-bootstrap-token=" + invalidToken}) + assert.Equal(1, code) + + out := ui.OutputWriter.String() + if strings.Contains(out, invalidToken) { + t.Fatalf("expected error output, got: %s", out) + } +} From 85876039a937cf2359c3a3c8b665c1bc6b4d8a00 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sun, 15 May 2022 14:42:09 +0200 Subject: [PATCH 19/70] WIP: ACL Test for Operator token. --- api/acl_test.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/api/acl_test.go b/api/acl_test.go index 6e32df71c25d..5de4e72a853b 100644 --- a/api/acl_test.go +++ b/api/acl_test.go @@ -269,3 +269,37 @@ func TestACL_OneTimeToken(t *testing.T) { assert.NotNil(t, out3) assert.Equal(t, out3.AccessorID, out.AccessorID) } + +func TestACLTokens_BootstrapInvalidToken(t *testing.T) { + testutil.Parallel(t) + c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) { + c.ACL.Enabled = true + }) + defer s.Stop() + at := c.ACLTokens() + + bootkn := BootstrapRequest{} + bootkn.Secret = "badtoken" + // Bootstrap with invalid token + out, wm, err := at.Bootstrap(&bootkn, nil) + assert.NotNil(t, err) + assertWriteMeta(t, wm) + assert.NotNil(t, out) +} + +func TestACLTokens_BootstrapValidToken(t *testing.T) { + testutil.Parallel(t) + c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) { + c.ACL.Enabled = true + }) + defer s.Stop() + at := c.ACLTokens() + + bootkn := BootstrapRequest{} + bootkn.Secret = "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" + // Bootstrap with Valid token + out, wm, err := at.Bootstrap(&bootkn, nil) + assert.Nil(t, err) + assertWriteMeta(t, wm) + assert.Equal(t, bootkn.Secret, out.SecretID) +} From 865892b7f86278cc5f37fae2b59a3217acf7b04c Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 8 Apr 2022 09:08:13 +0200 Subject: [PATCH 20/70] Working MVP - Admin Provided Bootstrap Token Admin Provided Bootstrap Token --- command/agent/acl_endpoint.go | 22 ++++++++++++++++++++++ nomad/structs/acl.go | 4 ++++ 2 files changed, 26 insertions(+) create mode 100644 nomad/structs/acl.go diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 6e2248502ff8..4a7955b56964 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -319,3 +319,25 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } + +// parseACLSecrets extracts a map of k/v pairs from the ACL secrets +// header. Silently ignores invalid secrets +func parseACLSecrets(req *http.Request) structs.ACLSecrets { + secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + if secretsHeader == "" { + return nil + } + + secrets := map[string]string{} + secretkvs := strings.Split(secretsHeader, ",") + for _, secretkv := range secretkvs { + kv := strings.Split(secretkv, "=") + if len(kv) == 2 { + secrets[kv[0]] = kv[1] + } + } + if len(secrets) == 0 { + return nil + } + return structs.ACLSecrets(secrets) +} diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go new file mode 100644 index 000000000000..932742d8d0d9 --- /dev/null +++ b/nomad/structs/acl.go @@ -0,0 +1,4 @@ +package structs + +// ACLSecrets contain optional additional configuration that can be used. +type ACLSecrets map[string]string From 7f5737b4a34c8c925b4206ed09b3cfbf960475bc Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 8 Apr 2022 18:20:15 +0200 Subject: [PATCH 21/70] Update acl_bootstrap.go Update the Information for the Autocomplete flags --- command/acl_bootstrap.go | 1 - 1 file changed, 1 deletion(-) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index f2fa14c42e64..4bf3d37f80f3 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -29,7 +29,6 @@ Bootstrap Options: -t Format and display the bootstrap response using a Go template. - -bootstrap-token Provide an operator generated management token. From 4af3111ccb08166367536f39c493abe11f966e92 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 20:28:19 +0200 Subject: [PATCH 22/70] Update the flag name and some comments --- command/acl_bootstrap.go | 1 + 1 file changed, 1 insertion(+) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 4bf3d37f80f3..6fb9135cb5f6 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -29,6 +29,7 @@ Bootstrap Options: -t Format and display the bootstrap response using a Go template. + -bootstrap-token Provide an operator generated management token. From 7fec7f869ca436d51dd21a3895bd640d84e0b982 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:47:11 +0200 Subject: [PATCH 23/70] Updated the header name in the agent --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 4a7955b56964..9aa8814faf70 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") if secretsHeader == "" { return nil } From 17cabf21b4b85161c0c9c81bb0dd1d6cef4371e8 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:49:35 +0200 Subject: [PATCH 24/70] Update Header Name Typo Copy Paste Error --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 9aa8814faf70..6c9e94fdb136 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") + secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") if secretsHeader == "" { return nil } From bade1e9a99561f2a0638aa18c580075d68429621 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 22:48:00 +0200 Subject: [PATCH 25/70] Refactor the ACL Bootstrap token code Removed unnecessary structs. Refactored the SetHeaders code to use just one secret. Removed parseACLSectrets function as redundant Removed the ACLSecrets Struct --- command/agent/acl_endpoint.go | 22 ---------------------- nomad/structs/acl.go | 4 ---- 2 files changed, 26 deletions(-) delete mode 100644 nomad/structs/acl.go diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 6c9e94fdb136..6e2248502ff8 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -319,25 +319,3 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } - -// parseACLSecrets extracts a map of k/v pairs from the ACL secrets -// header. Silently ignores invalid secrets -func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") - if secretsHeader == "" { - return nil - } - - secrets := map[string]string{} - secretkvs := strings.Split(secretsHeader, ",") - for _, secretkv := range secretkvs { - kv := strings.Split(secretkv, "=") - if len(kv) == 2 { - secrets[kv[0]] = kv[1] - } - } - if len(secrets) == 0 { - return nil - } - return structs.ACLSecrets(secrets) -} diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go deleted file mode 100644 index 932742d8d0d9..000000000000 --- a/nomad/structs/acl.go +++ /dev/null @@ -1,4 +0,0 @@ -package structs - -// ACLSecrets contain optional additional configuration that can be used. -type ACLSecrets map[string]string From cb2ae1ff28513249695d4be1318408d6f0ae692b Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 8 Apr 2022 09:08:13 +0200 Subject: [PATCH 26/70] Working MVP - Admin Provided Bootstrap Token Admin Provided Bootstrap Token --- command/acl_bootstrap.go | 2 +- command/agent/acl_endpoint.go | 22 ++++++++++++++++++++++ nomad/structs/acl.go | 4 ++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 nomad/structs/acl.go diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 6fb9135cb5f6..f2fa14c42e64 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -29,7 +29,7 @@ Bootstrap Options: -t Format and display the bootstrap response using a Go template. - + -bootstrap-token Provide an operator generated management token. diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 6e2248502ff8..4a7955b56964 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -319,3 +319,25 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } + +// parseACLSecrets extracts a map of k/v pairs from the ACL secrets +// header. Silently ignores invalid secrets +func parseACLSecrets(req *http.Request) structs.ACLSecrets { + secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + if secretsHeader == "" { + return nil + } + + secrets := map[string]string{} + secretkvs := strings.Split(secretsHeader, ",") + for _, secretkv := range secretkvs { + kv := strings.Split(secretkv, "=") + if len(kv) == 2 { + secrets[kv[0]] = kv[1] + } + } + if len(secrets) == 0 { + return nil + } + return structs.ACLSecrets(secrets) +} diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go new file mode 100644 index 000000000000..932742d8d0d9 --- /dev/null +++ b/nomad/structs/acl.go @@ -0,0 +1,4 @@ +package structs + +// ACLSecrets contain optional additional configuration that can be used. +type ACLSecrets map[string]string From d25cee178e6d892c704473d444cb1982a2c9d0d1 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:47:11 +0200 Subject: [PATCH 27/70] Updated the header name in the agent --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 4a7955b56964..9aa8814faf70 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-BOOT-Secrets") + secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") if secretsHeader == "" { return nil } From 3c7a0dce34fa0a29bcad59c9deb59a241cb82af7 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 11 Apr 2022 21:49:35 +0200 Subject: [PATCH 28/70] Update Header Name Typo Copy Paste Error --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 9aa8814faf70..6c9e94fdb136 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -323,7 +323,7 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re // parseACLSecrets extracts a map of k/v pairs from the ACL secrets // header. Silently ignores invalid secrets func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Boostrap-Token") + secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") if secretsHeader == "" { return nil } From 24117d357685c178ca554be1f97f89e6dcfdda8a Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Fri, 13 May 2022 22:48:00 +0200 Subject: [PATCH 29/70] Refactor the ACL Bootstrap token code Removed unnecessary structs. Refactored the SetHeaders code to use just one secret. Removed parseACLSectrets function as redundant Removed the ACLSecrets Struct --- command/agent/acl_endpoint.go | 22 ---------------------- nomad/structs/acl.go | 4 ---- 2 files changed, 26 deletions(-) delete mode 100644 nomad/structs/acl.go diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 6c9e94fdb136..6e2248502ff8 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -319,25 +319,3 @@ func (s *HTTPServer) ExchangeOneTimeToken(resp http.ResponseWriter, req *http.Re setIndex(resp, out.Index) return out, nil } - -// parseACLSecrets extracts a map of k/v pairs from the ACL secrets -// header. Silently ignores invalid secrets -func parseACLSecrets(req *http.Request) structs.ACLSecrets { - secretsHeader := req.Header.Get("X-Nomad-Bootstrap-Token") - if secretsHeader == "" { - return nil - } - - secrets := map[string]string{} - secretkvs := strings.Split(secretsHeader, ",") - for _, secretkv := range secretkvs { - kv := strings.Split(secretkv, "=") - if len(kv) == 2 { - secrets[kv[0]] = kv[1] - } - } - if len(secrets) == 0 { - return nil - } - return structs.ACLSecrets(secrets) -} diff --git a/nomad/structs/acl.go b/nomad/structs/acl.go deleted file mode 100644 index 932742d8d0d9..000000000000 --- a/nomad/structs/acl.go +++ /dev/null @@ -1,4 +0,0 @@ -package structs - -// ACLSecrets contain optional additional configuration that can be used. -type ACLSecrets map[string]string From 46b515e19503a522b115825bc1fa3aabb3d4b93f Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 16 May 2022 18:36:04 +0200 Subject: [PATCH 30/70] Update acl_test.go Fix Invalid Token Test --- api/acl_test.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/api/acl_test.go b/api/acl_test.go index 5de4e72a853b..811a5b9fc48c 100644 --- a/api/acl_test.go +++ b/api/acl_test.go @@ -278,13 +278,11 @@ func TestACLTokens_BootstrapInvalidToken(t *testing.T) { defer s.Stop() at := c.ACLTokens() - bootkn := BootstrapRequest{} + bootkn := &BootstrapRequest{} bootkn.Secret = "badtoken" // Bootstrap with invalid token - out, wm, err := at.Bootstrap(&bootkn, nil) - assert.NotNil(t, err) - assertWriteMeta(t, wm) - assert.NotNil(t, out) + _, _, err := at.Bootstrap(bootkn, nil) + assert.EqualError(t, err, "Unexpected response code: 400 (invalid acl token: )") } func TestACLTokens_BootstrapValidToken(t *testing.T) { @@ -295,10 +293,10 @@ func TestACLTokens_BootstrapValidToken(t *testing.T) { defer s.Stop() at := c.ACLTokens() - bootkn := BootstrapRequest{} + bootkn := &BootstrapRequest{} bootkn.Secret = "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" // Bootstrap with Valid token - out, wm, err := at.Bootstrap(&bootkn, nil) + out, wm, err := at.Bootstrap(bootkn, nil) assert.Nil(t, err) assertWriteMeta(t, wm) assert.Equal(t, bootkn.Secret, out.SecretID) From 363eabb650c51f477c4294237b39ab3b8d49fb60 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Mon, 16 May 2022 19:12:51 +0200 Subject: [PATCH 31/70] Update bootstrap.mdx Add some documentation on how to use the -bootstrap-token argument. --- .../content/docs/commands/acl/bootstrap.mdx | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/website/content/docs/commands/acl/bootstrap.mdx b/website/content/docs/commands/acl/bootstrap.mdx index cdc04845a50f..e377404277dd 100644 --- a/website/content/docs/commands/acl/bootstrap.mdx +++ b/website/content/docs/commands/acl/bootstrap.mdx @@ -15,7 +15,10 @@ The `acl bootstrap` command is used to bootstrap the initial ACL token. nomad acl bootstrap [options] ``` -The `acl bootstrap` command requires no arguments. +The `acl bootstrap` command can be used in two ways: +- If you provide no arguments it will return a system generated bootstrap token. +- If you use `-bootstrap-token [token]` where `[token]` is an operator generated token it will assign that token to manage ACLs. +Please make sure you secure this token in an apropriate manner as it could be written to your terminal history. ## General Options @@ -25,10 +28,11 @@ The `acl bootstrap` command requires no arguments. - `-json` : Output the bootstrap response in JSON format. - `-t` : Format and display the deployments using a Go template. +- `-bootstrap-token` : Provide an operator generated management token. ## Examples -Bootstrap the initial token: +Bootstrap the initial token without arguments: ```shell-session $ nomad acl bootstrap @@ -42,3 +46,18 @@ Create Time = 2017-09-11 17:38:10.999089612 +0000 UTC Create Index = 7 Modify Index = 7 ``` + +Bootstrap the initial token with provided token: + +```shell-session +$ nomad acl bootstrap -bootstrap-token 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a +Accessor ID = 5b7fd453-d3f7-6814-81dc-fcfe6daedea5 +Secret ID = 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a +Name = Bootstrap Token +Type = management +Global = true +Policies = n/a +Create Time = 2017-09-11 17:38:10.999089612 +0000 UTC +Create Index = 7 +Modify Index = 7 +``` \ No newline at end of file From 59c425bff9bfaf13256a78570634098ba2cf60dc Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 10:25:10 +0200 Subject: [PATCH 32/70] Update api/acl_test.go Add Improvement Tim Suggested Co-authored-by: Tim Gross --- api/acl_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/acl_test.go b/api/acl_test.go index 811a5b9fc48c..ae395641ec56 100644 --- a/api/acl_test.go +++ b/api/acl_test.go @@ -297,7 +297,7 @@ func TestACLTokens_BootstrapValidToken(t *testing.T) { bootkn.Secret = "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" // Bootstrap with Valid token out, wm, err := at.Bootstrap(bootkn, nil) - assert.Nil(t, err) + assert.NoError(t, err) assertWriteMeta(t, wm) assert.Equal(t, bootkn.Secret, out.SecretID) } From 8bdbb527dc7183b55836c2a3fe7fb2f274d3eba9 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 11:05:33 +0200 Subject: [PATCH 33/70] Update command/acl_bootstrap.go Add Suggestion by Tim Co-authored-by: Tim Gross --- command/acl_bootstrap.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index f2fa14c42e64..4dee12661c8b 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -88,9 +88,7 @@ func (c *ACLBootstrapCommand) Run(args []string) int { return 1 } - // Take the provided ACL token and prepare it for the query. - btkn := api.BootstrapRequest{} - btkn.Secret = bootstraptoken + btkn := &api.BootstrapRequest{Secret: bootstraptoken} // Get the bootstrap token token, _, err := client.ACLTokens().Bootstrap(&btkn, nil) From 358a8a82c7dbbe087470905658982b38ba1e2c75 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 11:06:03 +0200 Subject: [PATCH 34/70] Update nomad/acl_endpoint.go Apply suggestion by Tim Co-authored-by: Tim Gross --- nomad/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index 5e98c61d8919..5107f88f3984 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -404,7 +404,7 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A if helper.IsUUID(providedTokenID) { args.Token.SecretID = providedTokenID } else { - return structs.NewErrRPCCodedf(400, "invalid acl token: %v", err) + return structs.NewErrRPCCodedf(400, "invalid acl token") } } From 408940ffa49c9a37ab8fe3940dcce21cfc35726f Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 11:08:39 +0200 Subject: [PATCH 35/70] Update api/acl.go Remove TODO as per suggestion by Tim Co-authored-by: Tim Gross --- api/acl.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/acl.go b/api/acl.go index 0804c7a93c92..bf57eded14ae 100644 --- a/api/acl.go +++ b/api/acl.go @@ -72,9 +72,6 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } -// TODO -// These values will be redacted when reported in the -// API or in Nomad's logs type BootstrapRequest struct { Secret string From 7af15b4181621880e1abe7b3e3aabbfcb5cbaf5a Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 11:12:49 +0200 Subject: [PATCH 36/70] Update command/acl_bootstrap_test.go Apply changes as suggested by Tim Co-authored-by: Tim Gross --- command/acl_bootstrap_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/command/acl_bootstrap_test.go b/command/acl_bootstrap_test.go index f115c31506e7..0d201838f246 100644 --- a/command/acl_bootstrap_test.go +++ b/command/acl_bootstrap_test.go @@ -106,9 +106,7 @@ func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { assert.Equal(0, code) out := ui.OutputWriter.String() - if !strings.Contains(out, mockToken.SecretID) { - t.Fatalf("expected "+mockToken.SecretID+" output, got: %s", out) - } + assert.Contains(t, out, mockToken.SecretID) { } // Attempting to bootstrap the server with an invalid operator provided token should From 15f03e9db2a6c55a494417438d25e3178dec713f Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 11:13:30 +0200 Subject: [PATCH 37/70] Update command/acl_bootstrap_test.go Co-authored-by: Tim Gross --- command/acl_bootstrap_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/acl_bootstrap_test.go b/command/acl_bootstrap_test.go index 0d201838f246..24cbc58be5da 100644 --- a/command/acl_bootstrap_test.go +++ b/command/acl_bootstrap_test.go @@ -97,7 +97,7 @@ func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { srv, _, url := testServer(t, true, config) defer srv.Shutdown() - assert.Nil(srv.RootToken) + require.Nil(t, srv.RootToken) ui := cli.NewMockUi() cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}} From e46f431ff28d4eec79b1a0f895218de5a73958b1 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 12:30:56 +0200 Subject: [PATCH 38/70] Update acl_bootstrap_test.go Apply changes suggested by Tim --- command/acl_bootstrap_test.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/command/acl_bootstrap_test.go b/command/acl_bootstrap_test.go index 24cbc58be5da..2e0f85d3bf6e 100644 --- a/command/acl_bootstrap_test.go +++ b/command/acl_bootstrap_test.go @@ -1,7 +1,6 @@ package command import ( - "strings" "testing" "github.com/hashicorp/nomad/ci" @@ -9,6 +8,7 @@ import ( "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestACLBootstrapCommand(t *testing.T) { @@ -83,8 +83,7 @@ func TestACLBootstrapCommand_NonACLServer(t *testing.T) { // return the same token in the result. func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { ci.Parallel(t) - assert := assert.New(t) - + // assert := assert.New(t) // create a acl-enabled server without bootstrapping the token config := func(c *agent.Config) { c.ACL.Enabled = true @@ -103,17 +102,16 @@ func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}} code := cmd.Run([]string{"-address=" + url, "-bootstrap-token=" + mockToken.SecretID}) - assert.Equal(0, code) + assert.Equal(t, 0, code) out := ui.OutputWriter.String() - assert.Contains(t, out, mockToken.SecretID) { + assert.Contains(t, out, mockToken.SecretID) } // Attempting to bootstrap the server with an invalid operator provided token should // fail. func TestACLBootstrapCommand_WithBadOperatorBootstrapToken(t *testing.T) { ci.Parallel(t) - assert := assert.New(t) // create a acl-enabled server without bootstrapping the token config := func(c *agent.Config) { @@ -127,16 +125,14 @@ func TestACLBootstrapCommand_WithBadOperatorBootstrapToken(t *testing.T) { srv, _, url := testServer(t, true, config) defer srv.Shutdown() - assert.Nil(srv.RootToken) + assert.Nil(t, srv.RootToken) ui := cli.NewMockUi() cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}} code := cmd.Run([]string{"-address=" + url, "-bootstrap-token=" + invalidToken}) - assert.Equal(1, code) + assert.Equal(t, 1, code) out := ui.OutputWriter.String() - if strings.Contains(out, invalidToken) { - t.Fatalf("expected error output, got: %s", out) - } + assert.NotContains(t, out, invalidToken) } From b3fbae9b02e8b49327a96b9bc68c071980ce170d Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 12:31:47 +0200 Subject: [PATCH 39/70] Separate out the new Bootstrap code into a separate method --- api/acl.go | 15 +++++++++++++-- api/acl_test.go | 4 ++-- api/api_test.go | 2 +- command/acl_bootstrap.go | 2 +- internal/testing/apitests/api_test.go | 2 +- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/api/acl.go b/api/acl.go index bf57eded14ae..8272add92344 100644 --- a/api/acl.go +++ b/api/acl.go @@ -72,11 +72,22 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } +// This Method is deprecated and will be removed in 1.5 +// Bootstrap is used to get the initial bootstrap token +func (a *ACLTokens) Bootstrap(q *WriteOptions) (*ACLToken, *WriteMeta, error) { + var resp ACLToken + wm, err := a.client.write("/v1/acl/bootstrap", nil, &resp, q) + if err != nil { + return nil, nil, err + } + return &resp, wm, nil +} type BootstrapRequest struct { Secret string } +// Sets the bootstrap token header from the recieved token func (q *WriteOptions) SetHeadersFromBootstrapSecret(bootstraptoken string) { if q.Headers == nil { q.Headers = map[string]string{} @@ -84,8 +95,8 @@ func (q *WriteOptions) SetHeadersFromBootstrapSecret(bootstraptoken string) { q.Headers["X-Nomad-Bootstrap-Token"] = bootstraptoken } -// Bootstrap is used to get the initial bootstrap token or pass in the one that was provided in the API -func (a *ACLTokens) Bootstrap(req *BootstrapRequest, q *WriteOptions) (*ACLToken, *WriteMeta, error) { +// BootstrapOpts is used to get the initial bootstrap token or pass in the one that was provided in the API +func (a *ACLTokens) BootstrapOpts(req *BootstrapRequest, q *WriteOptions) (*ACLToken, *WriteMeta, error) { if q == nil { q = &WriteOptions{} } diff --git a/api/acl_test.go b/api/acl_test.go index ae395641ec56..1e258911dafa 100644 --- a/api/acl_test.go +++ b/api/acl_test.go @@ -281,7 +281,7 @@ func TestACLTokens_BootstrapInvalidToken(t *testing.T) { bootkn := &BootstrapRequest{} bootkn.Secret = "badtoken" // Bootstrap with invalid token - _, _, err := at.Bootstrap(bootkn, nil) + _, _, err := at.BootstrapOpts(bootkn, nil) assert.EqualError(t, err, "Unexpected response code: 400 (invalid acl token: )") } @@ -296,7 +296,7 @@ func TestACLTokens_BootstrapValidToken(t *testing.T) { bootkn := &BootstrapRequest{} bootkn.Secret = "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" // Bootstrap with Valid token - out, wm, err := at.Bootstrap(bootkn, nil) + out, wm, err := at.BootstrapOpts(bootkn, nil) assert.NoError(t, err) assertWriteMeta(t, wm) assert.Equal(t, bootkn.Secret, out.SecretID) diff --git a/api/api_test.go b/api/api_test.go index 37c161083e92..7b5d35346e53 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -40,7 +40,7 @@ func makeACLClient(t *testing.T, cb1 configCallback, }) // Get the root token - root, _, err := client.ACLTokens().Bootstrap(nil, nil) + root, _, err := client.ACLTokens().Bootstrap(nil) if err != nil { t.Fatalf("failed to bootstrap ACLs: %v", err) } diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 4dee12661c8b..93f1ed8be918 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -91,7 +91,7 @@ func (c *ACLBootstrapCommand) Run(args []string) int { btkn := &api.BootstrapRequest{Secret: bootstraptoken} // Get the bootstrap token - token, _, err := client.ACLTokens().Bootstrap(&btkn, nil) + token, _, err := client.ACLTokens().BootstrapOpts(btkn, nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error bootstrapping: %s", err)) return 1 diff --git a/internal/testing/apitests/api_test.go b/internal/testing/apitests/api_test.go index 98029ec26619..dcac8a63f990 100644 --- a/internal/testing/apitests/api_test.go +++ b/internal/testing/apitests/api_test.go @@ -26,7 +26,7 @@ func makeACLClient(t *testing.T, cb1 configCallback, }) // Get the root token - root, _, err := client.ACLTokens().Bootstrap(nil, nil) + root, _, err := client.ACLTokens().Bootstrap(nil) if err != nil { t.Fatalf("failed to bootstrap ACLs: %v", err) } From 867984f1dc25f4b42f7af9399439dc8eb14da107 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 12:32:00 +0200 Subject: [PATCH 40/70] Create 12520.txt Add Changelog Entry --- .changelog/12520.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/12520.txt diff --git a/.changelog/12520.txt b/.changelog/12520.txt new file mode 100644 index 000000000000..7d0009cd4808 --- /dev/null +++ b/.changelog/12520.txt @@ -0,0 +1,3 @@ +```release-note:improvement +bootstrap: Added `-bootstrap-token` to `acl bootstrap` command to allow operator provided token +``` \ No newline at end of file From 160a81d901c3e0236adb85875280fedd4502aaab Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 13:33:45 +0200 Subject: [PATCH 41/70] Update acl-tokens.mdx Add additional comments and examples for providing an ACL token as part of the bootstrap request --- website/content/api-docs/acl-tokens.mdx | 27 ++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/website/content/api-docs/acl-tokens.mdx b/website/content/api-docs/acl-tokens.mdx index 4c08ade21ad2..b541275be7d1 100644 --- a/website/content/api-docs/acl-tokens.mdx +++ b/website/content/api-docs/acl-tokens.mdx @@ -11,7 +11,7 @@ For more details about ACLs, please see the [ACL Guide](https://learn.hashicorp. ## Bootstrap Token -This endpoint is used to bootstrap the ACL system and provide the initial management token. +This endpoint is used to bootstrap the ACL system and provide the initial management token. An operator created token can be provided in a header called `X-Nomad-Bootstrap-Token` to bootstrap the cluster if required. If no header is provided the cluster will return a generated management token. This request is always forwarded to the authoritative region. It can only be invoked once until a [bootstrap reset](https://learn.hashicorp.com/tutorials/nomad/access-control-bootstrap#re-bootstrap-acl-system) is performed. @@ -51,6 +51,31 @@ $ curl \ } ``` +### Sample Request With Header + +```shell-session +$ curl \ + --request POST \ + --header "X-Nomad-Bootstrap-Token: 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" + https://localhost:4646/v1/acl/bootstrap +``` + +### Sample Response With Header + +```json +{ + "AccessorID": "b780e702-98ce-521f-2e5f-c6b87de05b24", + "SecretID": "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a", + "Name": "Bootstrap Token", + "Type": "management", + "Policies": null, + "Global": true, + "CreateTime": "2017-08-23T22:47:14.695408057Z", + "CreateIndex": 7, + "ModifyIndex": 7 +} +``` + ## List Tokens This endpoint lists all ACL tokens. This lists the local tokens and the global From d48a70532975d4b9a4f2f53e77d93d8a3c98891c Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 20:23:43 +0200 Subject: [PATCH 42/70] Update website/content/api-docs/acl-tokens.mdx Co-authored-by: Tim Gross --- website/content/api-docs/acl-tokens.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/website/content/api-docs/acl-tokens.mdx b/website/content/api-docs/acl-tokens.mdx index b541275be7d1..a4ff01d7cd59 100644 --- a/website/content/api-docs/acl-tokens.mdx +++ b/website/content/api-docs/acl-tokens.mdx @@ -11,7 +11,10 @@ For more details about ACLs, please see the [ACL Guide](https://learn.hashicorp. ## Bootstrap Token -This endpoint is used to bootstrap the ACL system and provide the initial management token. An operator created token can be provided in a header called `X-Nomad-Bootstrap-Token` to bootstrap the cluster if required. If no header is provided the cluster will return a generated management token. +This endpoint is used to bootstrap the ACL system and provide the initial management token. +An operator created token can be provided in a header called `X-Nomad-Bootstrap-Token` +to bootstrap the cluster if required. If no header is provided the cluster will return a +generated management token. This request is always forwarded to the authoritative region. It can only be invoked once until a [bootstrap reset](https://learn.hashicorp.com/tutorials/nomad/access-control-bootstrap#re-bootstrap-acl-system) is performed. From 1b40dec17f204bff6ec08fcd180f51c7c6b473d5 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 20:28:37 +0200 Subject: [PATCH 43/70] Add the UUID requirement to the documentation Add that the token should be a UUID and fixed a typo in the curl command. --- website/content/api-docs/acl-tokens.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/content/api-docs/acl-tokens.mdx b/website/content/api-docs/acl-tokens.mdx index a4ff01d7cd59..32f8d637e5ca 100644 --- a/website/content/api-docs/acl-tokens.mdx +++ b/website/content/api-docs/acl-tokens.mdx @@ -14,7 +14,7 @@ For more details about ACLs, please see the [ACL Guide](https://learn.hashicorp. This endpoint is used to bootstrap the ACL system and provide the initial management token. An operator created token can be provided in a header called `X-Nomad-Bootstrap-Token` to bootstrap the cluster if required. If no header is provided the cluster will return a -generated management token. +generated management token. The provided token should be presented in a UUID format. This request is always forwarded to the authoritative region. It can only be invoked once until a [bootstrap reset](https://learn.hashicorp.com/tutorials/nomad/access-control-bootstrap#re-bootstrap-acl-system) is performed. @@ -59,7 +59,7 @@ $ curl \ ```shell-session $ curl \ --request POST \ - --header "X-Nomad-Bootstrap-Token: 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" + --header "X-Nomad-Bootstrap-Token: 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" \ https://localhost:4646/v1/acl/bootstrap ``` From 585ee2b9faa2228b092b3af53d77d9119f0e650a Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 17 May 2022 20:28:56 +0200 Subject: [PATCH 44/70] Update acl_bootstrap_test.go Removed commented out code. --- command/acl_bootstrap_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/command/acl_bootstrap_test.go b/command/acl_bootstrap_test.go index 2e0f85d3bf6e..33d8333a6f14 100644 --- a/command/acl_bootstrap_test.go +++ b/command/acl_bootstrap_test.go @@ -83,7 +83,6 @@ func TestACLBootstrapCommand_NonACLServer(t *testing.T) { // return the same token in the result. func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { ci.Parallel(t) - // assert := assert.New(t) // create a acl-enabled server without bootstrapping the token config := func(c *agent.Config) { c.ACL.Enabled = true From e294174851a0f7241f3ee00404ac233fb1d9c50c Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Wed, 18 May 2022 07:45:30 +0200 Subject: [PATCH 45/70] Change Struct Field Name to be more descriptive Change Struct Filed Name to be more descriptive. Fix broken test --- api/acl.go | 4 ++-- api/acl_test.go | 8 ++++---- command/acl_bootstrap.go | 2 +- command/agent/acl_endpoint.go | 2 +- nomad/acl_endpoint.go | 2 +- nomad/structs/structs.go | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/api/acl.go b/api/acl.go index 8272add92344..2fa6c77ab052 100644 --- a/api/acl.go +++ b/api/acl.go @@ -84,7 +84,7 @@ func (a *ACLTokens) Bootstrap(q *WriteOptions) (*ACLToken, *WriteMeta, error) { } type BootstrapRequest struct { - Secret string + BootstrapSecret string } // Sets the bootstrap token header from the recieved token @@ -103,7 +103,7 @@ func (a *ACLTokens) BootstrapOpts(req *BootstrapRequest, q *WriteOptions) (*ACLT var resp ACLToken // Test if token is in the request. if req != nil { - q.SetHeadersFromBootstrapSecret(req.Secret) + q.SetHeadersFromBootstrapSecret(req.BootstrapSecret) } wm, err := a.client.write("/v1/acl/bootstrap", nil, &resp, q) if err != nil { diff --git a/api/acl_test.go b/api/acl_test.go index 1e258911dafa..033fedb90798 100644 --- a/api/acl_test.go +++ b/api/acl_test.go @@ -279,10 +279,10 @@ func TestACLTokens_BootstrapInvalidToken(t *testing.T) { at := c.ACLTokens() bootkn := &BootstrapRequest{} - bootkn.Secret = "badtoken" + bootkn.BootstrapSecret = "badtoken" // Bootstrap with invalid token _, _, err := at.BootstrapOpts(bootkn, nil) - assert.EqualError(t, err, "Unexpected response code: 400 (invalid acl token: )") + assert.EqualError(t, err, "Unexpected response code: 400 (invalid acl token)") } func TestACLTokens_BootstrapValidToken(t *testing.T) { @@ -294,10 +294,10 @@ func TestACLTokens_BootstrapValidToken(t *testing.T) { at := c.ACLTokens() bootkn := &BootstrapRequest{} - bootkn.Secret = "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" + bootkn.BootstrapSecret = "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" // Bootstrap with Valid token out, wm, err := at.BootstrapOpts(bootkn, nil) assert.NoError(t, err) assertWriteMeta(t, wm) - assert.Equal(t, bootkn.Secret, out.SecretID) + assert.Equal(t, bootkn.BootstrapSecret, out.SecretID) } diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 93f1ed8be918..1e17106b7598 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -88,7 +88,7 @@ func (c *ACLBootstrapCommand) Run(args []string) int { return 1 } - btkn := &api.BootstrapRequest{Secret: bootstraptoken} + btkn := &api.BootstrapRequest{BootstrapSecret: bootstraptoken} // Get the bootstrap token token, _, err := client.ACLTokens().BootstrapOpts(btkn, nil) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 6e2248502ff8..b56039b717cb 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -141,7 +141,7 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque secret := req.Header.Get("X-Nomad-Bootstrap-Token") // Format the request args := structs.ACLTokenBootstrapRequest{ - Secret: secret, + BootstrapSecret: secret, } s.parseWriteRequest(req, &args.WriteRequest) diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index 5107f88f3984..23a9e9913af0 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -354,7 +354,7 @@ func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.A return aclDisabled } args.Region = a.srv.config.AuthoritativeRegion - providedTokenID := args.Secret + providedTokenID := args.BootstrapSecret if done, err := a.srv.forward("ACL.Bootstrap", args, args, reply); done { return err diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 5c70dd7cb5f6..2692f7cb8a12 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -11912,9 +11912,9 @@ type ACLTokenDeleteRequest struct { // ACLTokenBootstrapRequest is used to bootstrap ACLs type ACLTokenBootstrapRequest struct { - Token *ACLToken // Not client specifiable - ResetIndex uint64 // Reset index is used to clear the bootstrap token - Secret string + Token *ACLToken // Not client specifiable + ResetIndex uint64 // Reset index is used to clear the bootstrap token + BootstrapSecret string WriteRequest } From 8f360a52bc76d647e931ea202694dd4d41becfc6 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sun, 22 May 2022 11:38:34 +0200 Subject: [PATCH 46/70] Remove the need for a header --- .vscode/launch.json | 7 +++++++ api/acl.go | 29 +++++++++++------------------ api/acl_test.go | 8 +++----- command/acl_bootstrap.go | 4 +--- command/agent/acl_endpoint.go | 15 +++++++++++---- 5 files changed, 33 insertions(+), 30 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000000..5c7247b40ad5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/api/acl.go b/api/acl.go index 2fa6c77ab052..a9faca0993f1 100644 --- a/api/acl.go +++ b/api/acl.go @@ -83,29 +83,17 @@ func (a *ACLTokens) Bootstrap(q *WriteOptions) (*ACLToken, *WriteMeta, error) { return &resp, wm, nil } -type BootstrapRequest struct { - BootstrapSecret string -} - -// Sets the bootstrap token header from the recieved token -func (q *WriteOptions) SetHeadersFromBootstrapSecret(bootstraptoken string) { - if q.Headers == nil { - q.Headers = map[string]string{} - } - q.Headers["X-Nomad-Bootstrap-Token"] = bootstraptoken -} - // BootstrapOpts is used to get the initial bootstrap token or pass in the one that was provided in the API -func (a *ACLTokens) BootstrapOpts(req *BootstrapRequest, q *WriteOptions) (*ACLToken, *WriteMeta, error) { +func (a *ACLTokens) BootstrapOpts(btoken string, q *WriteOptions) (*ACLToken, *WriteMeta, error) { if q == nil { q = &WriteOptions{} } - var resp ACLToken - // Test if token is in the request. - if req != nil { - q.SetHeadersFromBootstrapSecret(req.BootstrapSecret) + req := &BootstrapRequest{ + BootstrapSecret: btoken, } - wm, err := a.client.write("/v1/acl/bootstrap", nil, &resp, q) + + var resp ACLToken + wm, err := a.client.write("/v1/acl/bootstrap", req, &resp, q) if err != nil { return nil, nil, err } @@ -274,3 +262,8 @@ type OneTimeTokenExchangeRequest struct { type OneTimeTokenExchangeResponse struct { Token *ACLToken } + +// Bootstraorequest is used to when operstors priovide an ACL Bootstrap Token +type BootstrapRequest struct { + BootstrapSecret string +} diff --git a/api/acl_test.go b/api/acl_test.go index 033fedb90798..0b7dbc02588b 100644 --- a/api/acl_test.go +++ b/api/acl_test.go @@ -278,8 +278,7 @@ func TestACLTokens_BootstrapInvalidToken(t *testing.T) { defer s.Stop() at := c.ACLTokens() - bootkn := &BootstrapRequest{} - bootkn.BootstrapSecret = "badtoken" + bootkn := "badtoken" // Bootstrap with invalid token _, _, err := at.BootstrapOpts(bootkn, nil) assert.EqualError(t, err, "Unexpected response code: 400 (invalid acl token)") @@ -293,11 +292,10 @@ func TestACLTokens_BootstrapValidToken(t *testing.T) { defer s.Stop() at := c.ACLTokens() - bootkn := &BootstrapRequest{} - bootkn.BootstrapSecret = "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" + bootkn := "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" // Bootstrap with Valid token out, wm, err := at.BootstrapOpts(bootkn, nil) assert.NoError(t, err) assertWriteMeta(t, wm) - assert.Equal(t, bootkn.BootstrapSecret, out.SecretID) + assert.Equal(t, bootkn, out.SecretID) } diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 1e17106b7598..2cc1dfbbdcc1 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -88,10 +88,8 @@ func (c *ACLBootstrapCommand) Run(args []string) int { return 1 } - btkn := &api.BootstrapRequest{BootstrapSecret: bootstraptoken} - // Get the bootstrap token - token, _, err := client.ACLTokens().BootstrapOpts(btkn, nil) + token, _, err := client.ACLTokens().BootstrapOpts(bootstraptoken, nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error bootstrapping: %s", err)) return 1 diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index b56039b717cb..0d9d4434aac7 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -138,11 +138,18 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque return nil, CodedError(405, ErrInvalidMethod) } - secret := req.Header.Get("X-Nomad-Bootstrap-Token") - // Format the request - args := structs.ACLTokenBootstrapRequest{ - BootstrapSecret: secret, + var args structs.ACLTokenBootstrapRequest + + if req.ContentLength == 0 { + args = structs.ACLTokenBootstrapRequest{ + BootstrapSecret: "", + } + } else { + if err := decodeBody(req, &args); err != nil { + return nil, CodedError(400, err.Error()) + } } + s.parseWriteRequest(req, &args.WriteRequest) var out structs.ACLTokenUpsertResponse From 9c798fa333e322a120921e04fb067a94332afb39 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 24 May 2022 14:29:48 +0200 Subject: [PATCH 47/70] Remove .vscode/launch.json Removed the launch.json file and added it to the .gitignore. --- .gitignore | 3 +++ .vscode/launch.json | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.gitignore b/.gitignore index 10964e7a3534..92d75d5a4e7d 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,6 @@ e2e/remotetasks/input/ecs.vars # local terraform overrides *.auto.tfvars + +# vscode config +.vscode/launch.json \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 5c7247b40ad5..000000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [] -} \ No newline at end of file From f790c36bb9af71ce149330eff6cf7543b4e72366 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 24 May 2022 14:31:04 +0200 Subject: [PATCH 48/70] Update api/acl.go Co-authored-by: Michael Schurter --- api/acl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/acl.go b/api/acl.go index a9faca0993f1..4bfd39fb0e5d 100644 --- a/api/acl.go +++ b/api/acl.go @@ -263,7 +263,7 @@ type OneTimeTokenExchangeResponse struct { Token *ACLToken } -// Bootstraorequest is used to when operstors priovide an ACL Bootstrap Token +// BootstrapRequest is used to when operators provide an ACL Bootstrap Token type BootstrapRequest struct { BootstrapSecret string } From fc207de1e2fe1f089451ca5c8c137cc2feff8387 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Tue, 24 May 2022 14:43:20 +0200 Subject: [PATCH 49/70] Moved as per request --- .gitignore | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 92d75d5a4e7d..b3cc20aefcee 100644 --- a/.gitignore +++ b/.gitignore @@ -76,8 +76,10 @@ GNUMakefile.local rkt-* +# Common editor config ./idea *.iml +.vscode/launch.json # UI rules @@ -127,6 +129,3 @@ e2e/remotetasks/input/ecs.vars # local terraform overrides *.auto.tfvars - -# vscode config -.vscode/launch.json \ No newline at end of file From d739fbbb6cd073638f16101812fb885db6de8d25 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Wed, 25 May 2022 08:35:02 +0200 Subject: [PATCH 50/70] Update acl_bootstrap.go Removed the flag -bootstrap-token and added options to pass in the token with stdin and from a file. --- command/acl_bootstrap.go | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 2cc1dfbbdcc1..66a7643f6d69 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -2,6 +2,8 @@ package command import ( "fmt" + "io/ioutil" + "os" "strings" "github.com/hashicorp/nomad/api" @@ -59,28 +61,48 @@ func (c *ACLBootstrapCommand) Name() string { return "acl bootstrap" } func (c *ACLBootstrapCommand) Run(args []string) int { var ( - json bool - tmpl string - bootstraptoken string + json bool + tmpl string + file string ) flags := c.Meta.FlagSet(c.Name(), FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&json, "json", false, "") flags.StringVar(&tmpl, "t", "", "") - flags.StringVar(&bootstraptoken, "bootstrap-token", "", "") if err := flags.Parse(args); err != nil { return 1 } // Check that we got no arguments args = flags.Args() - if l := len(args); l != 0 { - c.Ui.Error("This command takes no arguments") + if l := len(args); l < 0 || l > 1 { + c.Ui.Error("This command takes up to one argument") c.Ui.Error(commandErrorText(c)) return 1 } + var terminalToken []byte + var err error + + if len(args) == 1 { + switch args[0] { + case "": + terminalToken = []byte{} + case "-": + terminalToken, err = ioutil.ReadAll(os.Stdin) + default: + terminalToken, err = ioutil.ReadFile(file) + } + if err != nil { + c.Ui.Error(fmt.Sprintf("Error reading provided token: %v", err)) + return 1 + } + } + + // Remove newline from the token if it was passed by stdin + boottoken := strings.TrimSuffix(string(terminalToken), "\n") + // Get the HTTP client client, err := c.Meta.Client() if err != nil { @@ -89,7 +111,7 @@ func (c *ACLBootstrapCommand) Run(args []string) int { } // Get the bootstrap token - token, _, err := client.ACLTokens().BootstrapOpts(bootstraptoken, nil) + token, _, err := client.ACLTokens().BootstrapOpts(boottoken, nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error bootstrapping: %s", err)) return 1 From 2d16aaa44a46a8098257c0a45affcfb809de6350 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 02:57:45 +0200 Subject: [PATCH 51/70] Update .gitignore Add .vscode to gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b3cc20aefcee..3bee04ba43f5 100644 --- a/.gitignore +++ b/.gitignore @@ -79,7 +79,7 @@ rkt-* # Common editor config ./idea *.iml -.vscode/launch.json +.vscode # UI rules From e93fc3526c080f388346503d263093da0a2623e3 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 03:08:17 +0200 Subject: [PATCH 52/70] Update acl_bootstrap.go Fix default file behaviour --- command/acl_bootstrap.go | 1 + 1 file changed, 1 insertion(+) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index 66a7643f6d69..b36adf6f634b 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -92,6 +92,7 @@ func (c *ACLBootstrapCommand) Run(args []string) int { case "-": terminalToken, err = ioutil.ReadAll(os.Stdin) default: + file = args[0] terminalToken, err = ioutil.ReadFile(file) } if err != nil { From b7aa487c6a53cb2514361b3e9d5e8067c1474d59 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 03:09:55 +0200 Subject: [PATCH 53/70] Update acl_bootstrap_test.go Update Tests for using file based token --- command/acl_bootstrap_test.go | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/command/acl_bootstrap_test.go b/command/acl_bootstrap_test.go index 33d8333a6f14..83533a9c7aa6 100644 --- a/command/acl_bootstrap_test.go +++ b/command/acl_bootstrap_test.go @@ -1,6 +1,8 @@ package command import ( + "io/ioutil" + "os" "testing" "github.com/hashicorp/nomad/ci" @@ -79,9 +81,9 @@ func TestACLBootstrapCommand_NonACLServer(t *testing.T) { assert.NotContains(out, "Secret ID") } -// Attempting to bootstrap the server with an operator provided token should +// Attempting to bootstrap the server with an operator provided token in a file should // return the same token in the result. -func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { +func TestACLBootstrapCommand_WithOperatorFileBootstrapToken(t *testing.T) { ci.Parallel(t) // create a acl-enabled server without bootstrapping the token config := func(c *agent.Config) { @@ -92,6 +94,15 @@ func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { // create a valid token mockToken := mock.ACLToken() + // Create temp file + f, err := ioutil.TempFile("", "nomad-token.token") + assert.Nil(t, err) + defer os.Remove(f.Name()) + + // Write the token to the file + err = ioutil.WriteFile(f.Name(), []byte(mockToken.SecretID), 0700) + assert.Nil(t, err) + srv, _, url := testServer(t, true, config) defer srv.Shutdown() @@ -100,14 +111,14 @@ func TestACLBootstrapCommand_WithOperatorBootstrapToken(t *testing.T) { ui := cli.NewMockUi() cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}} - code := cmd.Run([]string{"-address=" + url, "-bootstrap-token=" + mockToken.SecretID}) + code := cmd.Run([]string{"-address=" + url, f.Name()}) assert.Equal(t, 0, code) out := ui.OutputWriter.String() assert.Contains(t, out, mockToken.SecretID) } -// Attempting to bootstrap the server with an invalid operator provided token should +// Attempting to bootstrap the server with an invalid operator provided token in a file should // fail. func TestACLBootstrapCommand_WithBadOperatorBootstrapToken(t *testing.T) { ci.Parallel(t) @@ -118,9 +129,18 @@ func TestACLBootstrapCommand_WithBadOperatorBootstrapToken(t *testing.T) { c.ACL.PolicyTTL = 0 } - // create a valid token + // create a invalid token invalidToken := "invalid-token" + // Create temp file + f, err := ioutil.TempFile("", "nomad-token.token") + assert.Nil(t, err) + defer os.Remove(f.Name()) + + // Write the token to the file + err = ioutil.WriteFile(f.Name(), []byte(invalidToken), 0700) + assert.Nil(t, err) + srv, _, url := testServer(t, true, config) defer srv.Shutdown() @@ -129,7 +149,7 @@ func TestACLBootstrapCommand_WithBadOperatorBootstrapToken(t *testing.T) { ui := cli.NewMockUi() cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}} - code := cmd.Run([]string{"-address=" + url, "-bootstrap-token=" + invalidToken}) + code := cmd.Run([]string{"-address=" + url, f.Name()}) assert.Equal(t, 1, code) out := ui.OutputWriter.String() From 7bacf6fb1ae99931254ec855e080da9c13b6c97d Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 03:13:16 +0200 Subject: [PATCH 54/70] Update acl_bootstrap_test.go Fix Test Name --- command/acl_bootstrap_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/acl_bootstrap_test.go b/command/acl_bootstrap_test.go index 83533a9c7aa6..c91588b23c11 100644 --- a/command/acl_bootstrap_test.go +++ b/command/acl_bootstrap_test.go @@ -120,7 +120,7 @@ func TestACLBootstrapCommand_WithOperatorFileBootstrapToken(t *testing.T) { // Attempting to bootstrap the server with an invalid operator provided token in a file should // fail. -func TestACLBootstrapCommand_WithBadOperatorBootstrapToken(t *testing.T) { +func TestACLBootstrapCommand_WithBadOperatorFileBootstrapToken(t *testing.T) { ci.Parallel(t) // create a acl-enabled server without bootstrapping the token From 317ec5e9befe8dcb53c406a362542e9145242f60 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 04:16:59 +0200 Subject: [PATCH 55/70] Update acl_endpoint_test.go Add Test for the ACL endpoint --- command/agent/acl_endpoint_test.go | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/command/agent/acl_endpoint_test.go b/command/agent/acl_endpoint_test.go index 64f37a3339fc..515c80c1c8d7 100644 --- a/command/agent/acl_endpoint_test.go +++ b/command/agent/acl_endpoint_test.go @@ -221,6 +221,44 @@ func TestHTTP_ACLTokenBootstrap(t *testing.T) { }) } +func TestHTTP_ACLTokenBootstrapOperator(t *testing.T) { + ci.Parallel(t) + conf := func(c *Config) { + c.ACL.Enabled = true + c.ACL.PolicyTTL = 0 // Special flag to disable auto-bootstrap + } + httpTest(t, conf, func(s *TestAgent) { + // Provide token + args := structs.ACLTokenBootstrapRequest{ + BootstrapSecret: "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a", + } + + buf := encodeReq(args) + + // Make the HTTP request + req, err := http.NewRequest("PUT", "/v1/acl/bootstrap", buf) + if err != nil { + t.Fatalf("err: %v", err) + } + respW := httptest.NewRecorder() + // Make the request + obj, err := s.Server.ACLTokenBootstrap(respW, req) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Check for the index + if respW.Result().Header.Get("X-Nomad-Index") == "" { + t.Fatalf("missing index") + } + + // Check the output + n := obj.(*structs.ACLToken) + assert.NotNil(t, n) + assert.Equal(t, args.BootstrapSecret, n.SecretID) + }) +} + func TestHTTP_ACLTokenList(t *testing.T) { ci.Parallel(t) httpACLTest(t, nil, func(s *TestAgent) { From 89b34ec021169bd06df3fa2f8f2e4dfa4605c1df Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 04:17:26 +0200 Subject: [PATCH 56/70] Update acl-tokens.mdx Update API Docs --- website/content/api-docs/acl-tokens.mdx | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/website/content/api-docs/acl-tokens.mdx b/website/content/api-docs/acl-tokens.mdx index 32f8d637e5ca..b833c9dd27d2 100644 --- a/website/content/api-docs/acl-tokens.mdx +++ b/website/content/api-docs/acl-tokens.mdx @@ -12,9 +12,9 @@ For more details about ACLs, please see the [ACL Guide](https://learn.hashicorp. ## Bootstrap Token This endpoint is used to bootstrap the ACL system and provide the initial management token. -An operator created token can be provided in a header called `X-Nomad-Bootstrap-Token` -to bootstrap the cluster if required. If no header is provided the cluster will return a -generated management token. The provided token should be presented in a UUID format. +An operator created token can be provided in the body of the request to bootstrap the cluster +if required. If no header is provided the cluster will return a generated management token. +The provided token should be presented in a UUID format. This request is always forwarded to the authoritative region. It can only be invoked once until a [bootstrap reset](https://learn.hashicorp.com/tutorials/nomad/access-control-bootstrap#re-bootstrap-acl-system) is performed. @@ -54,16 +54,24 @@ $ curl \ } ``` -### Sample Request With Header +### Sample Operator Payload + +```json +{ + "BootstrapSecret": "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" +} +``` + +### Sample Request With Operator Token ```shell-session $ curl \ --request POST \ - --header "X-Nomad-Bootstrap-Token: 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" \ + --data @root.token \ https://localhost:4646/v1/acl/bootstrap ``` -### Sample Response With Header +### Sample Response With Operator Token ```json { From ae2691cbbf35759928540d87476593fe2987e5dc Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 04:17:47 +0200 Subject: [PATCH 57/70] Update 12520.txt Update changelog Note --- .changelog/12520.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/12520.txt b/.changelog/12520.txt index 7d0009cd4808..80ce4c84d867 100644 --- a/.changelog/12520.txt +++ b/.changelog/12520.txt @@ -1,3 +1,3 @@ ```release-note:improvement -bootstrap: Added `-bootstrap-token` to `acl bootstrap` command to allow operator provided token +bootstrap: Added option to allow for an operator generated bootstrap token to be passed to the `acl bootstrap` command ``` \ No newline at end of file From 10289f19fdbfd28c6ba49015460f3116ab8f1eca Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 04:29:38 +0200 Subject: [PATCH 58/70] Update bootstrap.mdx Add documentation for usage with the CLI --- website/content/docs/commands/acl/bootstrap.mdx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/website/content/docs/commands/acl/bootstrap.mdx b/website/content/docs/commands/acl/bootstrap.mdx index e377404277dd..86cbdf2db48b 100644 --- a/website/content/docs/commands/acl/bootstrap.mdx +++ b/website/content/docs/commands/acl/bootstrap.mdx @@ -17,7 +17,8 @@ nomad acl bootstrap [options] The `acl bootstrap` command can be used in two ways: - If you provide no arguments it will return a system generated bootstrap token. -- If you use `-bootstrap-token [token]` where `[token]` is an operator generated token it will assign that token to manage ACLs. +- If you would like to provide an operator generated token it is possible to provide the token +using a file `acl bootstrap [path]`. The Token can be read from stdin by setting the path to "-". Please make sure you secure this token in an apropriate manner as it could be written to your terminal history. ## General Options @@ -28,7 +29,6 @@ Please make sure you secure this token in an apropriate manner as it could be wr - `-json` : Output the bootstrap response in JSON format. - `-t` : Format and display the deployments using a Go template. -- `-bootstrap-token` : Provide an operator generated management token. ## Examples @@ -49,8 +49,15 @@ Modify Index = 7 Bootstrap the initial token with provided token: +root.token file +```json +{ + "BootstrapSecret": "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" +} +``` + ```shell-session -$ nomad acl bootstrap -bootstrap-token 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a +$ nomad acl bootstrap root.token Accessor ID = 5b7fd453-d3f7-6814-81dc-fcfe6daedea5 Secret ID = 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a Name = Bootstrap Token From e99c9c016682d30df878cba32da490caf97663a1 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 04:44:29 +0200 Subject: [PATCH 59/70] Update hashistack.tf Revert Terraform Autocorrect --- terraform/gcp/modules/hashistack/hashistack.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/gcp/modules/hashistack/hashistack.tf b/terraform/gcp/modules/hashistack/hashistack.tf index 01f9d14a6581..b5d54e02c7c9 100644 --- a/terraform/gcp/modules/hashistack/hashistack.tf +++ b/terraform/gcp/modules/hashistack/hashistack.tf @@ -245,7 +245,7 @@ resource "google_compute_instance" "client" { scheduling { preemptible = var.enable_preemptible # scheduling must have automatic_restart be false when preemptible is true. - automatic_restart = !var.enable_preemptible + automatic_restart = ! var.enable_preemptible } service_account { From 2de8f4989d18407066288ac2b924652487ae0208 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 04:59:52 +0200 Subject: [PATCH 60/70] Update acl_endpoint_test.go Add Operator Token Test --- nomad/acl_endpoint_test.go | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/nomad/acl_endpoint_test.go b/nomad/acl_endpoint_test.go index 2e17d0204611..5a9785d404af 100644 --- a/nomad/acl_endpoint_test.go +++ b/nomad/acl_endpoint_test.go @@ -1349,6 +1349,46 @@ func TestACLEndpoint_Bootstrap(t *testing.T) { assert.Equal(t, created, out) } +func TestACLEndpoint_BootstrapOperator(t *testing.T) { + ci.Parallel(t) + s1, cleanupS1 := TestServer(t, func(c *Config) { + c.ACLEnabled = true + }) + defer cleanupS1() + codec := rpcClient(t, s1) + testutil.WaitForLeader(t, s1.RPC) + + // Lookup the tokens + req := &structs.ACLTokenBootstrapRequest{ + WriteRequest: structs.WriteRequest{Region: "global"}, + BootstrapSecret: "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a", + } + var resp structs.ACLTokenUpsertResponse + if err := msgpackrpc.CallWithCodec(codec, "ACL.Bootstrap", req, &resp); err != nil { + t.Fatalf("err: %v", err) + } + assert.NotEqual(t, uint64(0), resp.Index) + assert.NotNil(t, resp.Tokens[0]) + + // Get the token out from the response + created := resp.Tokens[0] + assert.NotEqual(t, "", created.AccessorID) + assert.NotEqual(t, "", created.SecretID) + assert.NotEqual(t, time.Time{}, created.CreateTime) + assert.Equal(t, structs.ACLManagementToken, created.Type) + assert.Equal(t, "Bootstrap Token", created.Name) + assert.Equal(t, true, created.Global) + + // Check we created the token + out, err := s1.fsm.State().ACLTokenByAccessorID(nil, created.AccessorID) + assert.Nil(t, err) + assert.Equal(t, created, out) + // Check we have the correct operator token + tokenout, err := s1.fsm.State().ACLTokenBySecretID(nil, created.SecretID) + assert.Nil(t, err) + assert.Equal(t, created, tokenout) +} + func TestACLEndpoint_Bootstrap_Reset(t *testing.T) { ci.Parallel(t) dir := t.TempDir() From b138bbd4b39ae608de2ef49e97725d7763db29af Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 05:10:30 +0200 Subject: [PATCH 61/70] Update acl_endpoint.go Remove Unneeded code. Go Struct initialised empty --- command/agent/acl_endpoint.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 0d9d4434aac7..df3f56851798 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -140,11 +140,7 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque var args structs.ACLTokenBootstrapRequest - if req.ContentLength == 0 { - args = structs.ACLTokenBootstrapRequest{ - BootstrapSecret: "", - } - } else { + if req.ContentLength != 0 { if err := decodeBody(req, &args); err != nil { return nil, CodedError(400, err.Error()) } From 633cf828e0bb1bb6293cc0ba79ba087c2b57bc32 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 16:10:47 +0200 Subject: [PATCH 62/70] Update acl_endpoint.go Detect if there is a body in the request before decoding. --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index df3f56851798..9256bfef4441 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -140,7 +140,7 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque var args structs.ACLTokenBootstrapRequest - if req.ContentLength != 0 { + if req.Body != nil { if err := decodeBody(req, &args); err != nil { return nil, CodedError(400, err.Error()) } From c973e2d89417b7c2e1acae11b21cad1d58bdb174 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 26 May 2022 16:14:18 +0200 Subject: [PATCH 63/70] Update bootstrap.mdx File containing management token should just contain the token Add examples for stdin usage --- .../content/docs/commands/acl/bootstrap.mdx | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/website/content/docs/commands/acl/bootstrap.mdx b/website/content/docs/commands/acl/bootstrap.mdx index 86cbdf2db48b..f797d33d2ef8 100644 --- a/website/content/docs/commands/acl/bootstrap.mdx +++ b/website/content/docs/commands/acl/bootstrap.mdx @@ -50,10 +50,8 @@ Modify Index = 7 Bootstrap the initial token with provided token: root.token file -```json -{ - "BootstrapSecret": "2b778dd9-f5f1-6f29-b4b4-9a5fa948757a" -} +```shell-session +2b778dd9-f5f1-6f29-b4b4-9a5fa948757a ``` ```shell-session @@ -67,4 +65,21 @@ Policies = n/a Create Time = 2017-09-11 17:38:10.999089612 +0000 UTC Create Index = 7 Modify Index = 7 -``` \ No newline at end of file +``` + +Bootstrap the initial token with provided token using stdin + +```shell-session +$ nomad acl bootstrap - +2b778dd9-f5f1-6f29-b4b4-9a5fa948757a +EOF +Accessor ID = 5b7fd453-d3f7-6814-81dc-fcfe6daedea5 +Secret ID = 2b778dd9-f5f1-6f29-b4b4-9a5fa948757a +Name = Bootstrap Token +Type = management +Global = true +Policies = n/a +Create Time = 2017-09-11 17:38:10.999089612 +0000 UTC +Create Index = 7 +Modify Index = 7 +``` From 8a0d393cb9699ef78b17ca53f359bd4f28c846d6 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sat, 28 May 2022 10:27:20 +0200 Subject: [PATCH 64/70] Update api/acl.go Co-authored-by: Michael Schurter --- api/acl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/acl.go b/api/acl.go index 4bfd39fb0e5d..055855743cef 100644 --- a/api/acl.go +++ b/api/acl.go @@ -263,7 +263,7 @@ type OneTimeTokenExchangeResponse struct { Token *ACLToken } -// BootstrapRequest is used to when operators provide an ACL Bootstrap Token +// BootstrapRequest is used for when operators provide an ACL Bootstrap Token type BootstrapRequest struct { BootstrapSecret string } From 731936c7d2c36b864995f59943e89a783693c123 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sat, 28 May 2022 10:31:11 +0200 Subject: [PATCH 65/70] Update acl_bootstrap.go Remove some old bootstrap-token code. --- command/acl_bootstrap.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/command/acl_bootstrap.go b/command/acl_bootstrap.go index b36adf6f634b..f8970f938499 100644 --- a/command/acl_bootstrap.go +++ b/command/acl_bootstrap.go @@ -32,9 +32,6 @@ Bootstrap Options: -t Format and display the bootstrap response using a Go template. - -bootstrap-token - Provide an operator generated management token. - ` return strings.TrimSpace(helpText) } @@ -42,9 +39,8 @@ Bootstrap Options: func (c *ACLBootstrapCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ - "-json": complete.PredictNothing, - "-t": complete.PredictAnything, - "-bootstrap-token": complete.PredictAnything, + "-json": complete.PredictNothing, + "-t": complete.PredictAnything, }) } From 16ec53b121856564330702fa10930bf09b114169 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sat, 28 May 2022 10:39:40 +0200 Subject: [PATCH 66/70] Update acl-tokens.mdx Make it more clear that the root token is based on the JSON above. --- website/content/api-docs/acl-tokens.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/content/api-docs/acl-tokens.mdx b/website/content/api-docs/acl-tokens.mdx index b833c9dd27d2..095fd66ca582 100644 --- a/website/content/api-docs/acl-tokens.mdx +++ b/website/content/api-docs/acl-tokens.mdx @@ -67,7 +67,7 @@ $ curl \ ```shell-session $ curl \ --request POST \ - --data @root.token \ + --data @root-token.json \ https://localhost:4646/v1/acl/bootstrap ``` From 2d7b3152b2603540254a85beca95e83aaa96d4fe Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Sat, 28 May 2022 10:44:09 +0200 Subject: [PATCH 67/70] Update api/acl.go Co-authored-by: Michael Schurter --- api/acl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/acl.go b/api/acl.go index 055855743cef..a964b01e0133 100644 --- a/api/acl.go +++ b/api/acl.go @@ -72,7 +72,7 @@ func (c *Client) ACLTokens() *ACLTokens { return &ACLTokens{client: c} } -// This Method is deprecated and will be removed in 1.5 +// DEPRECATED: will be removed in Nomad 1.5.0 // Bootstrap is used to get the initial bootstrap token func (a *ACLTokens) Bootstrap(q *WriteOptions) (*ACLToken, *WriteMeta, error) { var resp ACLToken From d716f3f093d20125187eff4cadda589399ad80c4 Mon Sep 17 00:00:00 2001 From: Lance Haig Date: Thu, 2 Jun 2022 17:00:31 +0200 Subject: [PATCH 68/70] Revert Back to the ContentLength check --- command/agent/acl_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/acl_endpoint.go b/command/agent/acl_endpoint.go index 9256bfef4441..df3f56851798 100644 --- a/command/agent/acl_endpoint.go +++ b/command/agent/acl_endpoint.go @@ -140,7 +140,7 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque var args structs.ACLTokenBootstrapRequest - if req.Body != nil { + if req.ContentLength != 0 { if err := decodeBody(req, &args); err != nil { return nil, CodedError(400, err.Error()) } From 9ca6c63a2be183d8c68dcbaa07ea8b43cf397b49 Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Thu, 2 Jun 2022 14:44:34 -0700 Subject: [PATCH 69/70] test: manually set contentlength in tests --- command/agent/acl_endpoint_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/command/agent/acl_endpoint_test.go b/command/agent/acl_endpoint_test.go index 515c80c1c8d7..0e52a08993cf 100644 --- a/command/agent/acl_endpoint_test.go +++ b/command/agent/acl_endpoint_test.go @@ -240,6 +240,11 @@ func TestHTTP_ACLTokenBootstrapOperator(t *testing.T) { if err != nil { t.Fatalf("err: %v", err) } + + // Since we're not actually writing this HTTP request, we have + // to manually set ContentLength + req.ContentLength = -1 + respW := httptest.NewRecorder() // Make the request obj, err := s.Server.ACLTokenBootstrap(respW, req) From 772d8ee90fc09101e0d5be6dc467f0f04c4a1e9a Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Thu, 2 Jun 2022 16:02:34 -0700 Subject: [PATCH 70/70] appease hclfmt --- terraform/gcp/modules/hashistack/hashistack.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/gcp/modules/hashistack/hashistack.tf b/terraform/gcp/modules/hashistack/hashistack.tf index b5d54e02c7c9..01f9d14a6581 100644 --- a/terraform/gcp/modules/hashistack/hashistack.tf +++ b/terraform/gcp/modules/hashistack/hashistack.tf @@ -245,7 +245,7 @@ resource "google_compute_instance" "client" { scheduling { preemptible = var.enable_preemptible # scheduling must have automatic_restart be false when preemptible is true. - automatic_restart = ! var.enable_preemptible + automatic_restart = !var.enable_preemptible } service_account {