From bc50eebebdd608135429bd2f8d1c1ab8ed5f0cdd Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Mon, 5 Aug 2024 15:01:54 -0400 Subject: [PATCH] workload identity: add support for extra claims config for Vault (#23675) Although we encourage users to use Vault roles, sometimes they're going to want to assign policies based on entity and pre-create entities and aliases based on claims. This allows them to use single default role (or at least small number of them) that has a templated policy, but have an escape hatch from that. When defining Vault entities the `user_claim` must be unique. When writing Vault binding rules for use with Nomad workload identities the binding rule won't be able to create a 1:1 mapping because the selector language allows accessing only a single field. The `nomad_job_id` claim isn't sufficient to uniquely identify a job because of namespaces. It's possible to create a JWT auth role with `bound_claims` to avoid this becoming a security problem, but this doesn't allow for correct accounting of user claims. Add support for an `extra_claims` block on the server's `default_identity` blocks for Vault. This allows a cluster administrator to add a custom claim on all allocations. The values for these claims are interpolatable with a limited subset of fields, similar to how we interpolate the task environment. Fixes: https://github.com/hashicorp/nomad/issues/23510 Ref: https://hashicorp.atlassian.net/browse/NET-10372 Ref: https://hashicorp.atlassian.net/browse/NET-10387 --- e2e/vaultcompat/cluster_setup_test.go | 2 +- e2e/vaultcompat/input/restricted_jwt.hcl | 38 +++++++++++++ e2e/vaultcompat/run_ce_test.go | 1 + e2e/vaultcompat/vaultcompat_test.go | 17 ++++++ nomad/alloc_endpoint.go | 20 +++++-- nomad/config.go | 16 ++++++ nomad/structs/config/workload_id.go | 16 ++++++ nomad/structs/workload_id.go | 58 +++++++++++++++++++- nomad/structs/workload_id_test.go | 32 ++++++++++- testutil/server.go | 9 +-- website/content/docs/configuration/vault.mdx | 27 +++++++++ 11 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 e2e/vaultcompat/input/restricted_jwt.hcl diff --git a/e2e/vaultcompat/cluster_setup_test.go b/e2e/vaultcompat/cluster_setup_test.go index 48a6d7818e8..67eefdd4812 100644 --- a/e2e/vaultcompat/cluster_setup_test.go +++ b/e2e/vaultcompat/cluster_setup_test.go @@ -36,7 +36,7 @@ func roleWID(policies []string) map[string]any { return map[string]any{ "role_type": "jwt", "bound_audiences": "vault.io", - "user_claim": "/nomad_job_id", + "user_claim": "/extra_claims/nomad_workload_id", "user_claim_json_pointer": true, "claim_mappings": map[string]any{ "nomad_namespace": "nomad_namespace", diff --git a/e2e/vaultcompat/input/restricted_jwt.hcl b/e2e/vaultcompat/input/restricted_jwt.hcl new file mode 100644 index 00000000000..3ad151cbe62 --- /dev/null +++ b/e2e/vaultcompat/input/restricted_jwt.hcl @@ -0,0 +1,38 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +job "restricted_jwt" { + type = "batch" + + // Tasks in this group are expected to succeed and run to completion. + group "success" { + vault {} + + count = 2 + + // Task default_identity uses the default workload identity injected by the + // server and the inherits the Vault configuration from the group. + task "authorized" { + driver = "raw_exec" + + config { + command = "cat" + args = ["${NOMAD_SECRETS_DIR}/secret.txt"] + } + + // Vault has an alias that maps this job's nomad_workload_id to an entity + // with a policy that allows access to these secrets + template { + data = < **Warning:** The token-based authentication flow is deprecated and will be @@ -316,3 +342,4 @@ can be accomplished by sending the process a `SIGHUP` signal. [vault_bound_aud]: /vault/api-docs/auth/jwt#bound_audiences [vault_auth_enable_path]: /vault/docs/commands/auth/enable#path [workload_id]: /nomad/docs/concepts/workload-identity +[vault-jwt-user-claim]: /vault/api-docs/auth/jwt#user_claim