cli: respect vault token in plan command
This PR fixes a regression where the 'job plan' command would not respect a Vault token if set via --vault-token or $VAULT_TOKEN. Basically the same bug/fix as for the validate command in https://github.com/hashicorp/nomad/issues/13062 Fixes https://github.com/hashicorp/nomad/issues/13939
This commit is contained in:
parent
1901cfaba8
commit
ba5c45ab93
|
@ -0,0 +1,3 @@
|
|||
```release-note:bug
|
||||
cli: Fixed a bug where vault token not respected in plan command
|
||||
```
|
|
@ -2,11 +2,13 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/hashicorp/nomad/helper/pointer"
|
||||
"github.com/hashicorp/nomad/scheduler"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
@ -62,6 +64,10 @@ Alias: nomad plan
|
|||
* 1: Allocations created or destroyed.
|
||||
* 255: Error determining plan results.
|
||||
|
||||
The plan command will set the vault_token of the job based on the following
|
||||
precedence, going from highest to lowest: the -vault-token flag, the
|
||||
$VAULT_TOKEN environment variable and finally the value in the job file.
|
||||
|
||||
When ACLs are enabled, this command requires a token with the 'submit-job'
|
||||
capability for the job's namespace.
|
||||
|
||||
|
@ -91,6 +97,22 @@ Plan Options:
|
|||
-policy-override
|
||||
Sets the flag to force override any soft mandatory Sentinel policies.
|
||||
|
||||
-vault-token
|
||||
Used to validate if the user submitting the job has permission to run the job
|
||||
according to its Vault policies. A Vault token must be supplied if the vault
|
||||
stanza allow_unauthenticated is disabled in the Nomad server configuration.
|
||||
If the -vault-token flag is set, the passed Vault token is added to the jobspec
|
||||
before sending to the Nomad servers. This allows passing the Vault token
|
||||
without storing it in the job file. This overrides the token found in the
|
||||
$VAULT_TOKEN environment variable and the vault_token field in the job file.
|
||||
This token is cleared from the job after validating and cannot be used within
|
||||
the job executing environment. Use the vault stanza when templating in a job
|
||||
with a Vault token.
|
||||
|
||||
-vault-namespace
|
||||
If set, the passed Vault namespace is stored in the job before sending to the
|
||||
Nomad servers.
|
||||
|
||||
-var 'key=value'
|
||||
Variable for template, can be used multiple times.
|
||||
|
||||
|
@ -116,6 +138,8 @@ func (c *JobPlanCommand) AutocompleteFlags() complete.Flags {
|
|||
"-json": complete.PredictNothing,
|
||||
"-hcl1": complete.PredictNothing,
|
||||
"-hcl2-strict": complete.PredictNothing,
|
||||
"-vault-token": complete.PredictAnything,
|
||||
"-vault-namespace": complete.PredictAnything,
|
||||
"-var": complete.PredictAnything,
|
||||
"-var-file": complete.PredictFiles("*.var"),
|
||||
})
|
||||
|
@ -132,6 +156,7 @@ func (c *JobPlanCommand) AutocompleteArgs() complete.Predictor {
|
|||
func (c *JobPlanCommand) Name() string { return "job plan" }
|
||||
func (c *JobPlanCommand) Run(args []string) int {
|
||||
var diff, policyOverride, verbose bool
|
||||
var vaultToken, vaultNamespace string
|
||||
|
||||
flagSet := c.Meta.FlagSet(c.Name(), FlagSetClient)
|
||||
flagSet.Usage = func() { c.Ui.Output(c.Help()) }
|
||||
|
@ -141,6 +166,8 @@ func (c *JobPlanCommand) Run(args []string) int {
|
|||
flagSet.BoolVar(&c.JobGetter.JSON, "json", false, "")
|
||||
flagSet.BoolVar(&c.JobGetter.HCL1, "hcl1", false, "")
|
||||
flagSet.BoolVar(&c.JobGetter.Strict, "hcl2-strict", true, "")
|
||||
flagSet.StringVar(&vaultToken, "vault-token", "", "")
|
||||
flagSet.StringVar(&vaultNamespace, "vault-namespace", "", "")
|
||||
flagSet.Var(&c.JobGetter.Vars, "var", "")
|
||||
flagSet.Var(&c.JobGetter.VarFiles, "var-file", "")
|
||||
|
||||
|
@ -186,6 +213,22 @@ func (c *JobPlanCommand) Run(args []string) int {
|
|||
client.SetNamespace(*n)
|
||||
}
|
||||
|
||||
// Parse the Vault token.
|
||||
if vaultToken == "" {
|
||||
// Check the environment variable
|
||||
vaultToken = os.Getenv("VAULT_TOKEN")
|
||||
}
|
||||
|
||||
// Set the vault token.
|
||||
if vaultToken != "" {
|
||||
job.VaultToken = pointer.Of(vaultToken)
|
||||
}
|
||||
|
||||
// Set the vault namespace.
|
||||
if vaultNamespace != "" {
|
||||
job.VaultNamespace = pointer.Of(vaultNamespace)
|
||||
}
|
||||
|
||||
// Setup the options
|
||||
opts := &api.PlanOptions{}
|
||||
if diff {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/hashicorp/nomad/ci"
|
||||
"github.com/hashicorp/nomad/testutil"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/shoenig/test/must"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -156,6 +157,60 @@ job "job1" {
|
|||
ui.ErrorWriter.Reset()
|
||||
}
|
||||
|
||||
func TestPlanCommand_From_Files(t *testing.T) {
|
||||
ci.Parallel(t)
|
||||
|
||||
// Create a Vault server
|
||||
v := testutil.NewTestVault(t)
|
||||
defer v.Stop()
|
||||
|
||||
// Create a Nomad server
|
||||
s := testutil.NewTestServer(t, func(c *testutil.TestServerConfig) {
|
||||
c.Vault.Address = v.HTTPAddr
|
||||
c.Vault.Enabled = true
|
||||
c.Vault.AllowUnauthenticated = false
|
||||
c.Vault.Token = v.RootToken
|
||||
})
|
||||
defer s.Stop()
|
||||
|
||||
t.Run("fail to place", func(t *testing.T) {
|
||||
ui := cli.NewMockUi()
|
||||
cmd := &JobPlanCommand{Meta: Meta{Ui: ui}}
|
||||
args := []string{"-address", "http://" + s.HTTPAddr, "testdata/example-basic.nomad"}
|
||||
code := cmd.Run(args)
|
||||
require.Equal(t, 1, code) // no client running, fail to place
|
||||
must.StrContains(t, ui.OutputWriter.String(), "WARNING: Failed to place all allocations.")
|
||||
})
|
||||
|
||||
t.Run("vault no token", func(t *testing.T) {
|
||||
ui := cli.NewMockUi()
|
||||
cmd := &JobPlanCommand{Meta: Meta{Ui: ui}}
|
||||
args := []string{"-address", "http://" + s.HTTPAddr, "testdata/example-vault.nomad"}
|
||||
code := cmd.Run(args)
|
||||
must.Eq(t, 255, code)
|
||||
must.StrContains(t, ui.ErrorWriter.String(), "* Vault used in the job but missing Vault token")
|
||||
})
|
||||
|
||||
t.Run("vault bad token via flag", func(t *testing.T) {
|
||||
ui := cli.NewMockUi()
|
||||
cmd := &JobPlanCommand{Meta: Meta{Ui: ui}}
|
||||
args := []string{"-address", "http://" + s.HTTPAddr, "-vault-token=abc123", "testdata/example-vault.nomad"}
|
||||
code := cmd.Run(args)
|
||||
must.Eq(t, 255, code)
|
||||
must.StrContains(t, ui.ErrorWriter.String(), "* bad token")
|
||||
})
|
||||
|
||||
t.Run("vault bad token via env", func(t *testing.T) {
|
||||
t.Setenv("VAULT_TOKEN", "abc123")
|
||||
ui := cli.NewMockUi()
|
||||
cmd := &JobPlanCommand{Meta: Meta{Ui: ui}}
|
||||
args := []string{"-address", "http://" + s.HTTPAddr, "testdata/example-vault.nomad"}
|
||||
code := cmd.Run(args)
|
||||
must.Eq(t, 255, code)
|
||||
must.StrContains(t, ui.ErrorWriter.String(), "* bad token")
|
||||
})
|
||||
}
|
||||
|
||||
func TestPlanCommand_From_URL(t *testing.T) {
|
||||
ci.Parallel(t)
|
||||
ui := cli.NewMockUi()
|
||||
|
|
|
@ -48,6 +48,10 @@ Plan will return one of the following exit codes:
|
|||
- 1: Allocations created or destroyed.
|
||||
- 255: Error determining plan results.
|
||||
|
||||
The plan command will set the `vault_token` of the job based on the following
|
||||
precedence, going from highest to lowest: the `-vault-token` flag, the
|
||||
`$VAULT_TOKEN` environment variable and finally the value in the job file.
|
||||
|
||||
When ACLs are enabled, this command requires a token with the `submit-job`
|
||||
capability for the job's namespace.
|
||||
|
||||
|
@ -73,6 +77,20 @@ capability for the job's namespace.
|
|||
a variable has been supplied which is not defined within the root variables.
|
||||
Defaults to true.
|
||||
|
||||
- `-vault-token`: Used to validate if the user submitting the job has
|
||||
permission to run the job according to its Vault policies. A Vault token must
|
||||
be supplied if the [`vault` stanza `allow_unauthenticated`] is disabled in
|
||||
the Nomad server configuration. If the `-vault-token` flag is set, the passed
|
||||
Vault token is added to the jobspec before sending to the Nomad servers. This
|
||||
allows passing the Vault token without storing it in the job file. This
|
||||
overrides the token found in the `$VAULT_TOKEN` environment variable and the
|
||||
[`vault_token`] field in the job file. This token is cleared from the job
|
||||
after planning and cannot be used within the job executing environment. Use
|
||||
the `vault` stanza when templating in a job with a Vault token.
|
||||
|
||||
- `-vault-namespace`: If set, the passed Vault namespace is stored in the job
|
||||
before sending to the Nomad servers.
|
||||
|
||||
- `-var=<key=value>`: Variable for template, can be used multiple times.
|
||||
|
||||
- `-var-file=<path>`: Path to HCL2 file containing user variables.
|
||||
|
@ -241,3 +259,5 @@ if a change is detected.
|
|||
[`go-getter`]: https://github.com/hashicorp/go-getter
|
||||
[`nomad job run -check-index`]: /docs/commands/job/run#check-index
|
||||
[`tee`]: https://man7.org/linux/man-pages/man1/tee.1.html
|
||||
[`vault` stanza `allow_unauthenticated`]: /docs/configuration/vault#allow_unauthenticated
|
||||
[`vault_token`]: /docs/job-specification/job#vault_token
|
||||
|
|
Loading…
Reference in New Issue