mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
When a Nomad client register or re-registers, the RPC handler will generate and return a node identity if required. When an identity is generated, the signing key ID will be stored within the node object, to ensure a root key is not deleted until it is not used. During normal client operation it will periodically heartbeat to the Nomad servers to indicate aliveness. The RPC handler that is used for this action has also been updated to conditionally perform identity generation. Performing it here means no extra RPC handlers are required and we inherit the jitter in identity generation from the heartbeat mechanism. The identity generation check methods are performed from the RPC request arguments, so they a scoped to the required behaviour and can handle the nuance of each RPC. Failure to generate an identity is considered terminal to the RPC call. The client will include behaviour to retry this error which is always caused by the encrypter not being ready unless the servers keyring has been corrupted.
156 lines
3.8 KiB
Go
156 lines
3.8 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package command
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/cli"
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/command/agent"
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
func TestACLBootstrapCommand(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
// create a acl-enabled server without bootstrapping the token
|
|
config := func(c *agent.Config) {
|
|
c.ACL.Enabled = true
|
|
c.ACL.PolicyTTL = 0
|
|
}
|
|
|
|
srv, _, url := testServer(t, false, config)
|
|
defer srv.Shutdown()
|
|
|
|
must.Nil(t, srv.RootToken)
|
|
|
|
ui := cli.NewMockUi()
|
|
cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
|
|
|
code := cmd.Run([]string{"-address=" + url})
|
|
must.Zero(t, code)
|
|
|
|
out := ui.OutputWriter.String()
|
|
must.StrContains(t, out, "Secret ID")
|
|
must.StrContains(t, out, "Expiry Time = <none>")
|
|
}
|
|
|
|
// If a bootstrap token has already been created, attempts to create more should
|
|
// fail.
|
|
func TestACLBootstrapCommand_ExistingBootstrapToken(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
config := func(c *agent.Config) {
|
|
c.ACL.Enabled = true
|
|
}
|
|
|
|
srv, _, url := testServer(t, true, config)
|
|
defer srv.Shutdown()
|
|
|
|
must.NotNil(t, srv.RootToken)
|
|
|
|
ui := cli.NewMockUi()
|
|
cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
|
|
|
code := cmd.Run([]string{"-address=" + url})
|
|
must.One(t, code)
|
|
|
|
out := ui.OutputWriter.String()
|
|
must.StrNotContains(t, out, "Secret ID")
|
|
}
|
|
|
|
// Attempting to bootstrap a token on a non-ACL enabled server should fail.
|
|
func TestACLBootstrapCommand_NonACLServer(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
srv, _, url := testServer(t, true, nil)
|
|
defer srv.Shutdown()
|
|
|
|
ui := cli.NewMockUi()
|
|
cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
|
|
|
code := cmd.Run([]string{"-address=" + url})
|
|
must.One(t, code)
|
|
|
|
out := ui.OutputWriter.String()
|
|
must.StrNotContains(t, out, "Secret ID")
|
|
}
|
|
|
|
// Attempting to bootstrap the server with an operator provided token in a file should
|
|
// return the same token in the result.
|
|
func TestACLBootstrapCommand_WithOperatorFileBootstrapToken(t *testing.T) {
|
|
ci.Parallel(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()
|
|
|
|
// Create temp file
|
|
file, rm := getTempFile(t, "nomad-token.token")
|
|
t.Cleanup(rm)
|
|
|
|
// Write the token to the file
|
|
err := os.WriteFile(file, []byte(mockToken.SecretID), 0700)
|
|
must.NoError(t, err)
|
|
|
|
srv, _, url := testServer(t, false, config)
|
|
defer srv.Shutdown()
|
|
|
|
must.Nil(t, srv.RootToken)
|
|
|
|
ui := cli.NewMockUi()
|
|
cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
|
|
|
code := cmd.Run([]string{"-address=" + url, file})
|
|
must.Zero(t, code)
|
|
|
|
out := ui.OutputWriter.String()
|
|
must.StrContains(t, out, mockToken.SecretID)
|
|
must.StrContains(t, out, "Expiry Time = <none>")
|
|
}
|
|
|
|
// Attempting to bootstrap the server with an invalid operator provided token in a file should
|
|
// fail.
|
|
func TestACLBootstrapCommand_WithBadOperatorFileBootstrapToken(t *testing.T) {
|
|
ci.Parallel(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 invalid token
|
|
invalidToken := "invalid-token"
|
|
|
|
// Create temp file
|
|
file, cleanup := getTempFile(t, "nomad-token.token")
|
|
t.Cleanup(cleanup)
|
|
|
|
// Write the token to the file
|
|
err := os.WriteFile(file, []byte(invalidToken), 0700)
|
|
must.NoError(t, err)
|
|
|
|
srv, _, url := testServer(t, false, config)
|
|
defer srv.Shutdown()
|
|
|
|
must.Nil(t, srv.RootToken)
|
|
|
|
ui := cli.NewMockUi()
|
|
cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}
|
|
|
|
code := cmd.Run([]string{"-address=" + url, file})
|
|
must.One(t, code)
|
|
|
|
out := ui.OutputWriter.String()
|
|
must.StrNotContains(t, out, invalidToken)
|
|
}
|