Skip to content

Commit 940817a

Browse files
authored
Merge pull request #8453 from hashicorp/oss-multi-vault-ns
oss compoments for multi-vault namespaces
2 parents f22b835 + 1981036 commit 940817a

30 files changed

+467
-83
lines changed

api/jobs.go

+4
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ type Job struct {
787787
Meta map[string]string
788788
ConsulToken *string `mapstructure:"consul_token"`
789789
VaultToken *string `mapstructure:"vault_token"`
790+
VaultNamespace *string `mapstructure:"vault_namespace"`
790791
NomadTokenID *string `mapstructure:"nomad_token_id"`
791792
Status *string
792793
StatusDescription *string
@@ -850,6 +851,9 @@ func (j *Job) Canonicalize() {
850851
if j.VaultToken == nil {
851852
j.VaultToken = stringToPtr("")
852853
}
854+
if j.VaultNamespace == nil {
855+
j.VaultNamespace = stringToPtr("")
856+
}
853857
if j.NomadTokenID == nil {
854858
j.NomadTokenID = stringToPtr("")
855859
}

api/jobs_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ func TestJobs_Canonicalize(t *testing.T) {
244244
AllAtOnce: boolToPtr(false),
245245
ConsulToken: stringToPtr(""),
246246
VaultToken: stringToPtr(""),
247+
VaultNamespace: stringToPtr(""),
247248
NomadTokenID: stringToPtr(""),
248249
Status: stringToPtr(""),
249250
StatusDescription: stringToPtr(""),
@@ -334,6 +335,7 @@ func TestJobs_Canonicalize(t *testing.T) {
334335
AllAtOnce: boolToPtr(false),
335336
ConsulToken: stringToPtr(""),
336337
VaultToken: stringToPtr(""),
338+
VaultNamespace: stringToPtr(""),
337339
NomadTokenID: stringToPtr(""),
338340
Status: stringToPtr(""),
339341
StatusDescription: stringToPtr(""),
@@ -407,6 +409,7 @@ func TestJobs_Canonicalize(t *testing.T) {
407409
AllAtOnce: boolToPtr(false),
408410
ConsulToken: stringToPtr(""),
409411
VaultToken: stringToPtr(""),
412+
VaultNamespace: stringToPtr(""),
410413
NomadTokenID: stringToPtr(""),
411414
Stop: boolToPtr(false),
412415
Stable: boolToPtr(false),
@@ -573,6 +576,7 @@ func TestJobs_Canonicalize(t *testing.T) {
573576
AllAtOnce: boolToPtr(false),
574577
ConsulToken: stringToPtr(""),
575578
VaultToken: stringToPtr(""),
579+
VaultNamespace: stringToPtr(""),
576580
NomadTokenID: stringToPtr(""),
577581
Stop: boolToPtr(false),
578582
Stable: boolToPtr(false),
@@ -731,6 +735,7 @@ func TestJobs_Canonicalize(t *testing.T) {
731735
AllAtOnce: boolToPtr(false),
732736
ConsulToken: stringToPtr(""),
733737
VaultToken: stringToPtr(""),
738+
VaultNamespace: stringToPtr(""),
734739
NomadTokenID: stringToPtr(""),
735740
Stop: boolToPtr(false),
736741
Stable: boolToPtr(false),
@@ -817,6 +822,7 @@ func TestJobs_Canonicalize(t *testing.T) {
817822
AllAtOnce: boolToPtr(false),
818823
ConsulToken: stringToPtr(""),
819824
VaultToken: stringToPtr(""),
825+
VaultNamespace: stringToPtr(""),
820826
NomadTokenID: stringToPtr(""),
821827
Stop: boolToPtr(false),
822828
Stable: boolToPtr(false),
@@ -982,6 +988,7 @@ func TestJobs_Canonicalize(t *testing.T) {
982988
AllAtOnce: boolToPtr(false),
983989
ConsulToken: stringToPtr(""),
984990
VaultToken: stringToPtr(""),
991+
VaultNamespace: stringToPtr(""),
985992
NomadTokenID: stringToPtr(""),
986993
Stop: boolToPtr(false),
987994
Stable: boolToPtr(false),
@@ -1145,6 +1152,7 @@ func TestJobs_Canonicalize(t *testing.T) {
11451152
AllAtOnce: boolToPtr(false),
11461153
ConsulToken: stringToPtr(""),
11471154
VaultToken: stringToPtr(""),
1155+
VaultNamespace: stringToPtr(""),
11481156
NomadTokenID: stringToPtr(""),
11491157
Stop: boolToPtr(false),
11501158
Stable: boolToPtr(false),

api/tasks.go

+4
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ func (tmpl *Template) Canonicalize() {
812812

813813
type Vault struct {
814814
Policies []string
815+
Namespace *string `mapstructure:"namespace"`
815816
Env *bool
816817
ChangeMode *string `mapstructure:"change_mode"`
817818
ChangeSignal *string `mapstructure:"change_signal"`
@@ -821,6 +822,9 @@ func (v *Vault) Canonicalize() {
821822
if v.Env == nil {
822823
v.Env = boolToPtr(true)
823824
}
825+
if v.Namespace == nil {
826+
v.Namespace = stringToPtr("")
827+
}
824828
if v.ChangeMode == nil {
825829
v.ChangeMode = stringToPtr("restart")
826830
}

client/allocrunner/taskrunner/task_runner_getters.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,13 @@ func (tr *TaskRunner) setVaultToken(token string) {
5757
tr.vaultToken = token
5858

5959
// Update the task's environment
60-
tr.envBuilder.SetVaultToken(token, tr.clientConfig.VaultConfig.Namespace, tr.task.Vault.Env)
60+
taskNamespace := tr.task.Vault.Namespace
61+
62+
ns := tr.clientConfig.VaultConfig.Namespace
63+
if taskNamespace != "" {
64+
ns = taskNamespace
65+
}
66+
tr.envBuilder.SetVaultToken(token, ns, tr.task.Vault.Env)
6167
}
6268

6369
// getDriverHandle returns a driver handle.

client/allocrunner/taskrunner/template/template.go

+9
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ type TaskTemplateManagerConfig struct {
8787
// VaultToken is the Vault token for the task.
8888
VaultToken string
8989

90+
// VaultNamespace is the Vault namespace for the task
91+
VaultNamespace string
92+
9093
// TaskDir is the task's directory
9194
TaskDir string
9295

@@ -655,9 +658,15 @@ func newRunnerConfig(config *TaskTemplateManagerConfig,
655658
if cc.VaultConfig != nil && cc.VaultConfig.IsEnabled() {
656659
conf.Vault.Address = &cc.VaultConfig.Addr
657660
conf.Vault.Token = &config.VaultToken
661+
662+
// Set the Vault Namespace. Passed in Task config has
663+
// highest precedence.
658664
if config.ClientConfig.VaultConfig.Namespace != "" {
659665
conf.Vault.Namespace = &config.ClientConfig.VaultConfig.Namespace
660666
}
667+
if config.VaultNamespace != "" {
668+
conf.Vault.Namespace = &config.VaultNamespace
669+
}
661670

662671
if strings.HasPrefix(cc.VaultConfig.Addr, "https") || cc.VaultConfig.TLSCertFile != "" {
663672
skipVerify := cc.VaultConfig.TLSSkipVerify != nil && *cc.VaultConfig.TLSSkipVerify

client/allocrunner/taskrunner/template/template_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,41 @@ func TestTaskTemplateManager_Config_VaultNamespace(t *testing.T) {
13771377
assert.Equal(testNS, *ctconf.Vault.Namespace, "Vault Namespace Value")
13781378
}
13791379

1380+
// TestTaskTemplateManager_Config_VaultNamespace asserts the Vault namespace setting is
1381+
// propagated to consul-template's configuration.
1382+
func TestTaskTemplateManager_Config_VaultNamespace_TaskOverride(t *testing.T) {
1383+
t.Parallel()
1384+
assert := assert.New(t)
1385+
1386+
testNS := "test-namespace"
1387+
c := config.DefaultConfig()
1388+
c.Node = mock.Node()
1389+
c.VaultConfig = &sconfig.VaultConfig{
1390+
Enabled: helper.BoolToPtr(true),
1391+
Addr: "https://localhost/",
1392+
TLSServerName: "notlocalhost",
1393+
Namespace: testNS,
1394+
}
1395+
1396+
alloc := mock.Alloc()
1397+
overriddenNS := "new-namespace"
1398+
1399+
// Set the template manager config vault namespace
1400+
config := &TaskTemplateManagerConfig{
1401+
ClientConfig: c,
1402+
VaultToken: "token",
1403+
VaultNamespace: overriddenNS,
1404+
EnvBuilder: taskenv.NewBuilder(c.Node, alloc, alloc.Job.TaskGroups[0].Tasks[0], c.Region),
1405+
}
1406+
1407+
ctmplMapping, err := parseTemplateConfigs(config)
1408+
assert.Nil(err, "Parsing Templates")
1409+
1410+
ctconf, err := newRunnerConfig(config, ctmplMapping)
1411+
assert.Nil(err, "Building Runner Config")
1412+
assert.Equal(overriddenNS, *ctconf.Vault.Namespace, "Vault Namespace Value")
1413+
}
1414+
13801415
func TestTaskTemplateManager_BlockedEvents(t *testing.T) {
13811416
// The tests sets a template that need keys 0, 1, 2, 3, 4,
13821417
// then subsequently sets 0, 1, 2 keys

client/allocrunner/taskrunner/template_hook.go

+10
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ type templateHook struct {
4747
// vaultToken is the current Vault token
4848
vaultToken string
4949

50+
// vaultNamespace is the current Vault namespace
51+
vaultNamespace string
52+
5053
// taskDir is the task directory
5154
taskDir string
5255
}
@@ -75,6 +78,12 @@ func (h *templateHook) Prestart(ctx context.Context, req *interfaces.TaskPrestar
7578
// Store the current Vault token and the task directory
7679
h.taskDir = req.TaskDir.Dir
7780
h.vaultToken = req.VaultToken
81+
82+
// Set vault namespace if specified
83+
if req.Task.Vault != nil {
84+
h.vaultNamespace = req.Task.Vault.Namespace
85+
}
86+
7887
unblockCh, err := h.newManager()
7988
if err != nil {
8089
return err
@@ -98,6 +107,7 @@ func (h *templateHook) newManager() (unblock chan struct{}, err error) {
98107
Templates: h.config.templates,
99108
ClientConfig: h.config.clientConfig,
100109
VaultToken: h.vaultToken,
110+
VaultNamespace: h.vaultNamespace,
101111
TaskDir: h.taskDir,
102112
EnvBuilder: h.config.envBuilder,
103113
MaxTemplateEventRate: template.DefaultMaxTemplateEventRate,

client/client.go

+1
Original file line numberDiff line numberDiff line change
@@ -2457,6 +2457,7 @@ func (c *Client) deriveToken(alloc *structs.Allocation, taskNames []string, vcli
24572457
}
24582458

24592459
// Derive the tokens
2460+
// namespace is handled via nomad/vault
24602461
var resp structs.DeriveVaultTokenResponse
24612462
if err := c.RPC("Node.DeriveVaultToken", &req, &resp); err != nil {
24622463
vlogger.Error("error making derive token RPC", "error", err)

command/agent/job_endpoint.go

+24-16
Original file line numberDiff line numberDiff line change
@@ -773,22 +773,23 @@ func ApiJobToStructJob(job *api.Job) *structs.Job {
773773
job.Canonicalize()
774774

775775
j := &structs.Job{
776-
Stop: *job.Stop,
777-
Region: *job.Region,
778-
Namespace: *job.Namespace,
779-
ID: *job.ID,
780-
ParentID: *job.ParentID,
781-
Name: *job.Name,
782-
Type: *job.Type,
783-
Priority: *job.Priority,
784-
AllAtOnce: *job.AllAtOnce,
785-
Datacenters: job.Datacenters,
786-
Payload: job.Payload,
787-
Meta: job.Meta,
788-
ConsulToken: *job.ConsulToken,
789-
VaultToken: *job.VaultToken,
790-
Constraints: ApiConstraintsToStructs(job.Constraints),
791-
Affinities: ApiAffinitiesToStructs(job.Affinities),
776+
Stop: *job.Stop,
777+
Region: *job.Region,
778+
Namespace: *job.Namespace,
779+
ID: *job.ID,
780+
ParentID: *job.ParentID,
781+
Name: *job.Name,
782+
Type: *job.Type,
783+
Priority: *job.Priority,
784+
AllAtOnce: *job.AllAtOnce,
785+
Datacenters: job.Datacenters,
786+
Payload: job.Payload,
787+
Meta: job.Meta,
788+
ConsulToken: *job.ConsulToken,
789+
VaultToken: *job.VaultToken,
790+
VaultNamespace: *job.VaultNamespace,
791+
Constraints: ApiConstraintsToStructs(job.Constraints),
792+
Affinities: ApiAffinitiesToStructs(job.Affinities),
792793
}
793794

794795
// Update has been pushed into the task groups. stagger and max_parallel are
@@ -976,6 +977,12 @@ func ApiTgToStructsTG(job *structs.Job, taskGroup *api.TaskGroup, tg *structs.Ta
976977
for l, task := range taskGroup.Tasks {
977978
t := &structs.Task{}
978979
ApiTaskToStructsTask(task, t)
980+
981+
// Set the tasks vault namespace from Job if it was not
982+
// specified by the task or group
983+
if t.Vault != nil && t.Vault.Namespace == "" && job.VaultNamespace != "" {
984+
t.Vault.Namespace = job.VaultNamespace
985+
}
979986
tg.Tasks[l] = t
980987
}
981988
}
@@ -1089,6 +1096,7 @@ func ApiTaskToStructsTask(apiTask *api.Task, structsTask *structs.Task) {
10891096
if apiTask.Vault != nil {
10901097
structsTask.Vault = &structs.Vault{
10911098
Policies: apiTask.Vault.Policies,
1099+
Namespace: *apiTask.Vault.Namespace,
10921100
Env: *apiTask.Vault.Env,
10931101
ChangeMode: *apiTask.Vault.ChangeMode,
10941102
ChangeSignal: *apiTask.Vault.ChangeSignal,

command/agent/job_endpoint_test.go

+14-10
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,7 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
21212121
},
21222122
},
21232123
Vault: &api.Vault{
2124+
Namespace: helper.StringToPtr("ns1"),
21242125
Policies: []string{"a", "b", "c"},
21252126
Env: helper.BoolToPtr(true),
21262127
ChangeMode: helper.StringToPtr("c"),
@@ -2149,6 +2150,7 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
21492150
},
21502151
ConsulToken: helper.StringToPtr("abc123"),
21512152
VaultToken: helper.StringToPtr("def456"),
2153+
VaultNamespace: helper.StringToPtr("ghi789"),
21522154
Status: helper.StringToPtr("status"),
21532155
StatusDescription: helper.StringToPtr("status_desc"),
21542156
Version: helper.Uint64ToPtr(10),
@@ -2158,16 +2160,17 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
21582160
}
21592161

21602162
expected := &structs.Job{
2161-
Stop: true,
2162-
Region: "global",
2163-
Namespace: "foo",
2164-
ID: "foo",
2165-
ParentID: "lol",
2166-
Name: "name",
2167-
Type: "service",
2168-
Priority: 50,
2169-
AllAtOnce: true,
2170-
Datacenters: []string{"dc1", "dc2"},
2163+
Stop: true,
2164+
Region: "global",
2165+
Namespace: "foo",
2166+
VaultNamespace: "ghi789",
2167+
ID: "foo",
2168+
ParentID: "lol",
2169+
Name: "name",
2170+
Type: "service",
2171+
Priority: 50,
2172+
AllAtOnce: true,
2173+
Datacenters: []string{"dc1", "dc2"},
21712174
Constraints: []*structs.Constraint{
21722175
{
21732176
LTarget: "a",
@@ -2488,6 +2491,7 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
24882491
},
24892492
},
24902493
Vault: &structs.Vault{
2494+
Namespace: "ns1",
24912495
Policies: []string{"a", "b", "c"},
24922496
Env: true,
24932497
ChangeMode: "c",

command/job_run.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ Run Options:
101101
the job file. This overrides the token found in $VAULT_TOKEN environment
102102
variable and that found in the job.
103103
104+
-vault-namespace
105+
If set, the passed Vault namespace is stored in the job before sending to the
106+
Nomad servers. This overrides the namespace found in $VAULT_NAMESPACE environment
107+
variable and that found in the job.
108+
104109
-verbose
105110
Display full information.
106111
`
@@ -119,6 +124,7 @@ func (c *JobRunCommand) AutocompleteFlags() complete.Flags {
119124
"-verbose": complete.PredictNothing,
120125
"-consul-token": complete.PredictNothing,
121126
"-vault-token": complete.PredictAnything,
127+
"-vault-namespace": complete.PredictAnything,
122128
"-output": complete.PredictNothing,
123129
"-policy-override": complete.PredictNothing,
124130
"-preserve-counts": complete.PredictNothing,
@@ -133,7 +139,7 @@ func (c *JobRunCommand) Name() string { return "job run" }
133139

134140
func (c *JobRunCommand) Run(args []string) int {
135141
var detach, verbose, output, override, preserveCounts bool
136-
var checkIndexStr, consulToken, vaultToken string
142+
var checkIndexStr, consulToken, vaultToken, vaultNamespace string
137143

138144
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
139145
flags.Usage = func() { c.Ui.Output(c.Help()) }
@@ -145,6 +151,7 @@ func (c *JobRunCommand) Run(args []string) int {
145151
flags.StringVar(&checkIndexStr, "check-index", "", "")
146152
flags.StringVar(&consulToken, "consul-token", "", "")
147153
flags.StringVar(&vaultToken, "vault-token", "", "")
154+
flags.StringVar(&vaultNamespace, "vault-namespace", "", "")
148155

149156
if err := flags.Parse(args); err != nil {
150157
return 1
@@ -213,6 +220,15 @@ func (c *JobRunCommand) Run(args []string) int {
213220
job.VaultToken = helper.StringToPtr(vaultToken)
214221
}
215222

223+
// Parse the Vault namespace
224+
if vaultNamespace == "" {
225+
vaultNamespace = os.Getenv("VAULT_NAMESPACE")
226+
}
227+
228+
if vaultNamespace != "" {
229+
job.VaultNamespace = helper.StringToPtr(vaultNamespace)
230+
}
231+
216232
if output {
217233
req := struct {
218234
Job *api.Job

0 commit comments

Comments
 (0)