mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 02:15:43 +03:00
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
84 lines
2.4 KiB
Go
84 lines
2.4 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package vaultcompat
|
|
|
|
import "fmt"
|
|
|
|
const (
|
|
// jwtPath is where the JWT auth method is mounted in Vault.
|
|
// Use a non-default value for a more realistic scenario.
|
|
jwtPath = "nomad_jwt"
|
|
)
|
|
|
|
// roleLegacy is the legacy recommendation for nomad cluster role.
|
|
var roleLegacy = map[string]interface{}{
|
|
"disallowed_policies": "nomad-server",
|
|
"explicit_max_ttl": 0, // use old name for vault compatibility
|
|
"name": "nomad-cluster",
|
|
"orphan": false,
|
|
"period": 259200, // use old name for vault compatibility
|
|
"renewable": true,
|
|
}
|
|
|
|
// authConfigJWT is the configuration for the JWT auth method used by Nomad.
|
|
func authConfigJWT(jwksURL string) map[string]any {
|
|
return map[string]any{
|
|
"jwks_url": jwksURL,
|
|
"jwt_supported_algs": []string{"RS256", "EdDSA"},
|
|
"default_role": "nomad-workloads",
|
|
}
|
|
}
|
|
|
|
// roleWID is the recommended role for Nomad workloads when using JWT and
|
|
// workload identity.
|
|
func roleWID(policies []string) map[string]any {
|
|
return map[string]any{
|
|
"role_type": "jwt",
|
|
"bound_audiences": "vault.io",
|
|
"user_claim": "/extra_claims/nomad_workload_id",
|
|
"user_claim_json_pointer": true,
|
|
"claim_mappings": map[string]any{
|
|
"nomad_namespace": "nomad_namespace",
|
|
"nomad_job_id": "nomad_job_id",
|
|
},
|
|
"token_type": "service",
|
|
"token_period": "30m",
|
|
"token_policies": policies,
|
|
}
|
|
}
|
|
|
|
// policyWID is a templated Vault policy that grants tasks access to secret
|
|
// paths prefixed by <namespace>/<job>.
|
|
func policyWID(mountAccessor string) string {
|
|
return fmt.Sprintf(`
|
|
path "secret/data/{{identity.entity.aliases.%[1]s.metadata.nomad_namespace}}/{{identity.entity.aliases.%[1]s.metadata.nomad_job_id}}/*" {
|
|
capabilities = ["read"]
|
|
}
|
|
|
|
path "secret/data/{{identity.entity.aliases.%[1]s.metadata.nomad_namespace}}/{{identity.entity.aliases.%[1]s.metadata.nomad_job_id}}" {
|
|
capabilities = ["read"]
|
|
}
|
|
|
|
path "secret/metadata/{{identity.entity.aliases.%[1]s.metadata.nomad_namespace}}/*" {
|
|
capabilities = ["list"]
|
|
}
|
|
|
|
path "secret/metadata/*" {
|
|
capabilities = ["list"]
|
|
}
|
|
`, mountAccessor)
|
|
}
|
|
|
|
// policyRestricted is Vault policy that only grants read access to a specific
|
|
// path.
|
|
const policyRestricted = `
|
|
path "secret/data/restricted" {
|
|
capabilities = ["read"]
|
|
}
|
|
|
|
path "secret/metadata/restricted" {
|
|
capabilities = ["list"]
|
|
}
|
|
`
|