diff --git a/client/allocrunner/taskrunner/task_runner_getters.go b/client/allocrunner/taskrunner/task_runner_getters.go index c888b9a78..0afcee832 100644 --- a/client/allocrunner/taskrunner/task_runner_getters.go +++ b/client/allocrunner/taskrunner/task_runner_getters.go @@ -57,7 +57,7 @@ func (tr *TaskRunner) setVaultToken(token string) { tr.vaultToken = token // Update the task's environment - tr.envBuilder.SetVaultToken(token, tr.task.Vault.Env) + tr.envBuilder.SetVaultToken(token, tr.clientConfig.VaultConfig.Namespace, tr.task.Vault.Env) } // getDriverHandle returns a driver handle. diff --git a/client/taskenv/env.go b/client/taskenv/env.go index 6e41a03a3..78eecf4d5 100644 --- a/client/taskenv/env.go +++ b/client/taskenv/env.go @@ -85,6 +85,9 @@ const ( // VaultToken is the environment variable for passing the Vault token VaultToken = "VAULT_TOKEN" + + // VaultNamespace is the environment variable for passing the Vault namespace, if applicable + VaultNamespace = "VAULT_NAMESPACE" ) // The node values that can be interpreted. @@ -305,6 +308,7 @@ type Builder struct { allocName string groupName string vaultToken string + vaultNamespace string injectVaultToken bool jobName string @@ -423,6 +427,11 @@ func (b *Builder) Build() *TaskEnv { envMap[VaultToken] = b.vaultToken } + // Build the Vault Namespace + if b.injectVaultToken && b.vaultNamespace != "" { + envMap[VaultNamespace] = b.vaultNamespace + } + // Copy task meta for k, v := range b.taskMeta { envMap[k] = v @@ -753,9 +762,10 @@ func (b *Builder) SetTemplateEnv(m map[string]string) *Builder { return b } -func (b *Builder) SetVaultToken(token string, inject bool) *Builder { +func (b *Builder) SetVaultToken(token, namespace string, inject bool) *Builder { b.mu.Lock() b.vaultToken = token + b.vaultNamespace = namespace b.injectVaultToken = inject b.mu.Unlock() return b diff --git a/client/taskenv/env_test.go b/client/taskenv/env_test.go index 15f748be6..457befbf3 100644 --- a/client/taskenv/env_test.go +++ b/client/taskenv/env_test.go @@ -468,28 +468,59 @@ func TestEnvironment_VaultToken(t *testing.T) { n := mock.Node() a := mock.Alloc() env := NewBuilder(n, a, a.Job.TaskGroups[0].Tasks[0], "global") - env.SetVaultToken("123", false) + env.SetVaultToken("123", "vault-namespace", false) { act := env.Build().All() if act[VaultToken] != "" { t.Fatalf("Unexpected environment variables: %s=%q", VaultToken, act[VaultToken]) } + if act[VaultNamespace] != "" { + t.Fatalf("Unexpected environment variables: %s=%q", VaultNamespace, act[VaultNamespace]) + } } { - act := env.SetVaultToken("123", true).Build().List() + act := env.SetVaultToken("123", "", true).Build().List() exp := "VAULT_TOKEN=123" found := false + foundNs := false for _, entry := range act { if entry == exp { found = true - break + } + if strings.HasPrefix(entry, "VAULT_NAMESPACE=") { + foundNs = true } } if !found { t.Fatalf("did not find %q in:\n%s", exp, strings.Join(act, "\n")) } + if foundNs { + t.Fatalf("found unwanted VAULT_NAMESPACE in:\n%s", strings.Join(act, "\n")) + } + } + + { + act := env.SetVaultToken("123", "vault-namespace", true).Build().List() + exp := "VAULT_TOKEN=123" + expNs := "VAULT_NAMESPACE=vault-namespace" + found := false + foundNs := false + for _, entry := range act { + if entry == exp { + found = true + } + if entry == expNs { + foundNs = true + } + } + if !found { + t.Fatalf("did not find %q in:\n%s", exp, strings.Join(act, "\n")) + } + if !foundNs { + t.Fatalf("did not find %q in:\n%s", expNs, strings.Join(act, "\n")) + } } } diff --git a/website/source/docs/job-specification/vault.html.md b/website/source/docs/job-specification/vault.html.md index f99f1c7fa..a65f37b86 100644 --- a/website/source/docs/job-specification/vault.html.md +++ b/website/source/docs/job-specification/vault.html.md @@ -47,8 +47,10 @@ job "docs" { ``` The Nomad client will make the Vault token available to the task by writing it -to the secret directory at `secrets/vault_token` and by injecting a VAULT_TOKEN -environment variable. +to the secret directory at `secrets/vault_token` and by injecting a `VAULT_TOKEN` +environment variable. If the Nomad cluster is [configured](http://localhost:4567/docs/configuration/vault.html#namespace) +to use [Vault Namespaces](https://www.vaultproject.io/docs/enterprise/namespaces/index.html), +a `VAULT_NAMESPACE` environment variable will be injected whenever `VAULT_TOKEN` is. If Nomad is unable to renew the Vault token (perhaps due to a Vault outage or network error), the client will attempt to retrieve a new Vault token. If successful, the @@ -71,8 +73,8 @@ with Vault as well. string like `"SIGUSR1"` or `"SIGINT"`. This option is required if the `change_mode` is `signal`. -- `env` `(bool: true)` - Specifies if the `VAULT_TOKEN` environment variable - should be set when starting the task. +- `env` `(bool: true)` - Specifies if the `VAULT_TOKEN` and `VAULT_NAMESPACE` + environment variables should be set when starting the task. - `policies` `(array: [])` - Specifies the set of Vault policies that the task requires. The Nomad client will retrieve a Vault token that is