Vault

Vault Templated Policies Practical Guide: Enforcing Least Privilege with Identity entity/group Data

2026-04-19
NicheeLab Editorial Team

Templated Policies let policies reference identity information as variables and resolve paths dynamically at request time. They let you express a least-privilege design that gives each user or team their own secret space using only a small number of policies.

This article covers how to use information tied to entities and groups in template expansion, the evaluation order and pitfalls, practical configuration steps, and the key points to keep in mind for the exam.

Templated Policies: Basics and Exam Points

Vault's Templated Policies let you write {{...}} placeholders inside ACL policies, which are substituted using the identity context (entity, its aliases, metadata, and so on) bound to the requesting token. Substitution happens server-side, and ordinary capability evaluation runs against the matched path.

In practice, embedding a user's own name or team into the path lets you safely apply a single policy to many people. From an exam perspective, the basics matter: which identity fields are available, what happens when a token has no entity, that deny always wins, and the difference between kv v2's data and metadata paths.

  • Common placeholders: identity.entity.name, identity.entity.id, identity.entity.metadata.<key>, identity.entity.aliases.<mount_accessor>.name
  • Expansion is based on the requesting token's entity (you do not directly use the group's own name to expand the path)
  • If the token has no entity, most templates become empty, so paths fail to match and the result is effectively a deny
  • deny always wins over allow. When a broad allow overlaps a narrow deny, the deny takes precedence
  • On kv v2, read/write operations use kv/data/ and list operations use kv/metadata/

Minimal example: allow only the user's own area (kv v2)

path "kv/data/users/{{identity.entity.name}}/*" {
  capabilities = ["create", "update", "read", "delete"]
}

# for list (kv v2 metadata path)
path "kv/metadata/users/{{identity.entity.name}}/*" {
  capabilities = ["list"]
}

Static ACL vs. Templated Policies vs. Policy Engines: When to Use Which

Even for the same least-privilege design, you can produce many simple static ACLs, consolidate with templates, or control access through an advanced external policy engine like Sentinel. Pick the approach based on operational scale, how dynamic things are, and your audit requirements.

For the Associate and Ops exams, understanding when to use plain ACLs vs. Templated Policies is enough. Sentinel details show up in the context of higher-level certifications and Enterprise features.

  • Small and mid-size deployments: Templated Policies are usually enough
  • Large-scale or advanced conditional logic: consider a policy engine like Sentinel
  • Absorb frequently changing attributes (team name, etc.) via entity.metadata and use them in template expansion
AspectStatic ACL policiesTemplated PoliciesExternal policy engine
Number of definitionsTends to grow per userOne policy covers many usersRules consolidate, but runtime evaluation grows
ExpressivenessFixed paths onlyIdentity-derived variable pathsComplex conditions across time, environment, and attributes
Operational costNaming and distribution get messyEasy to keep in sync by updating attributesRequires expertise in design, review, and operations
Exam frequencyHighHigh (template syntax, evaluation order)Medium to low (higher-level certifications)

Evaluation Flow: From Entity Resolution to Path Matching and Capability Decision

Templates are expanded each time using the entity context bound to the requesting token. Standard ACL matching is performed against the expanded path string, and the final capabilities are decided (with deny taking precedence).

Groups are the unit you use to control who a policy applies to. Rather than dropping the group name itself into the path, the standard approach is to resolve the template using each member entity's attributes (for example, entity.metadata.team).

  • Entity resolution depends on the entity and alias created at login (authentication) time
  • aliases.<mount_accessor>.name lets you reference the username on the auth method side
  • If metadata is not set, the path fails to match and the request is denied, so automate metadata configuration in your initialization and onboarding flows
  • On kv v2, list is evaluated against the metadata path and read/write against the data path

Conceptual diagram of template expansion and evaluation

logintoken w/ entityentity contextexpand {{...}}match pathcapabilitiesAuth Method(userpass, OIDC)Vault Identity(entity/alias)Requestpath=kv/...Templated Policy (ACL)path after expansionAllow if matched and not denied

Example: expanding via alias (the auth method's username)

# Assume the userpass accessor is held in an env var
# Example: ACCESSOR=auth_userpass_12345678

path "kv/data/users/{{identity.entity.aliases.${ACCESSOR}.name}}/*" {
  capabilities = ["create", "update", "read", "delete"]
}

path "kv/metadata/users/{{identity.entity.aliases.${ACCESSOR}.name}}/*" {
  capabilities = ["list"]
}

Use Cases: User Spaces, Team Spaces, and Alias-Name-Based Patterns

Carving out a personal space is the most common pattern. Because entity.name may be an auto-generated name, use aliases.<mount_accessor>.name when you want to stabilize on the auth method's username.

Team-level spaces branch on an attribute like entity.metadata.team. When someone changes teams, you only need to update metadata and permissions move automatically — no redeploying policies.

  • Personal space: kv/data/users/{{identity.entity.aliases.<accessor>.name}}/*
  • Team space: kv/data/teams/{{identity.entity.metadata.team}}/*
  • Don't forget the auxiliary stanzas for read-only or list-only access (on kv v2, list lives on the metadata path)

HCL example: express both personal and team spaces in a single policy

# Personal space (username)
path "kv/data/users/{{identity.entity.aliases.${ACCESSOR}.name}}/*" {
  capabilities = ["create", "update", "read", "delete"]
}
path "kv/metadata/users/{{identity.entity.aliases.${ACCESSOR}.name}}/*" {
  capabilities = ["list"]
}

# Team space (entity.metadata.team). If team is unset, paths fail to match → deny
path "kv/data/teams/{{identity.entity.metadata.team}}/*" {
  capabilities = ["read", "list"]
}
path "kv/metadata/teams/{{identity.entity.metadata.team}}/*" {
  capabilities = ["list"]
}

Step-by-Step: Implementing with kv v2 + userpass + group

Below is a minimal example that grants users a personal space named after their username after logging in with userpass. Because we use aliases.<mount_accessor>.name, we fetch the userpass mount accessor and bake it into the template.

For production, design alongside entity metadata initialization, group policy attachment, and automation for the user join/leave flow.

  • Get the accessor via auth list -detailed and embed it in the policy file either as a literal or via variable expansion
  • Attaching the policy to a group applies the same template logic to every member
  • Watch out: missing list capabilities easily break CLI listings

End-to-end CLI command example

# 1) Enable kv v2
vault secrets enable -path=kv kv-v2

# 2) Enable userpass and create a user
auth_path=userpass
vault auth enable ${auth_path}
vault write auth/${auth_path}/users/alice password="S3cret!"

# 3) Fetch the userpass mount accessor
ACCESSOR=$(vault auth list -format=json | jq -r '."'${auth_path}'/".accessor')
echo "ACCESSOR=${ACCESSOR}"

# 4) Create the templated policy
cat > user-scoped.hcl <<EOF
path "kv/data/users/{{identity.entity.aliases.${ACCESSOR}.name}}/*" {
  capabilities = ["create", "update", "read", "delete"]
}
path "kv/metadata/users/{{identity.entity.aliases.${ACCESSOR}.name}}/*" {
  capabilities = ["list"]
}
EOF
vault policy write user-scoped user-scoped.hcl

# 5) Create an identity group and attach the policy
gid=$(vault write -field=id identity/group name="ops" policies="user-scoped")
echo "GROUP_ID=${gid}"

# 6) Log in once as alice so the entity is auto-created
VAULT_TOKEN=$(vault login -method=${auth_path} -format=json username=alice password="S3cret!" | jq -r .auth.client_token)
ENTITY_ID=$(VAULT_TOKEN=$VAULT_TOKEN vault token lookup -format=json | jq -r .data.entity_id)
echo "ENTITY_ID=${ENTITY_ID}"

# 7) Add alice's entity to the group
vault write identity/group/id/${gid} member_entity_ids=${ENTITY_ID}

# 8) Create a secret (substitute with an admin token in real use)
vault kv put kv/users/alice/api key=abc123

# 9) Verify access with alice's token
VAULT_TOKEN=$VAULT_TOKEN vault kv get kv/users/alice/api   # succeeds
VAULT_TOKEN=$VAULT_TOKEN vault kv get kv/users/bob/api     # fails (path mismatch)

Operational Pitfalls and Associate / Ops Exam Highlights

Template expansion is convenient, but missing attributes or mixing up path types can lead to unintended denies. Keep a checklist that covers audit and maintenance perspectives to stay safe.

On the exam, expect frequent questions on deny precedence, which identity fields are usable in templates, why list requires kv/metadata, and what happens when no entity exists.

  • When metadata is unset, paths fail to match — an initialization flow is mandatory
  • On kv v2, list lives on metadata and read/write on data — mix them up and list fails
  • Disabling and recreating an auth method changes the accessor, so policies using aliases.<accessor>.name need updating
  • deny takes precedence — never create allows that are too broad
  • Use audit logs to inspect request.path and the final capabilities, indirectly verifying expansion results

Sample audit log entry (excerpt)

# Assumes the file audit device is enabled
# Confirm request.path matches the post-expansion real path
{
  "type": "request",
  "auth": {"entity_id": "...", "policies": ["user-scoped"]},
  "request": {"path": "kv/data/users/alice/api", "operation": "read"},
  "response": {"policy_results": {"allowed": true}}
}

Check Your Understanding

Associate / Ops

問題 1

You want to allow a user who logged in with userpass to access only the kv v2 path whose name matches their username. Which templated policy is written correctly (ignore list capability)?

  1. path "kv/data/users/{{identity.entity.aliases.auth_userpass_XXXXXXXX.name}}/*" { capabilities = ["read", "create", "update", "delete"] }
  2. path "kv/data/users/{{identity.groups.name}}/*" { capabilities = ["read"] }
  3. path "kv/data/users/{{entity.name}}/*" { capabilities = ["read"] }
  4. path "kv/metadata/users/{{identity.entity.name}}/*" { capabilities = ["read", "update"] }

正解: A

aliases.<accessor>.name using the userpass mount accessor is the stable way to expand to the auth method's username. Reads and writes on kv v2 go under kv/data/. B is an invalid placeholder, C uses the wrong namespace, and D uses the metadata path with read/update which is inappropriate (metadata is for list).

Frequently Asked Questions

How are templates evaluated when the token has no entity?

Without an identity context, most template values are treated as empty, so paths fail to match and the request is denied. If you rely on templated policies, make sure your auth method always creates an entity/alias on login.

Do I need to update the policy when a user changes their name?

If you use aliases.<accessor>.name, the policy follows the auth method's username changes. However, if the mount accessor changes (for example, after recreating the auth method), you need to update the <accessor> value inside the policy. If you rely on entity.metadata, simply updating that key's value will automatically change how the template expands.

Can group information be used directly in template expansion?

Groups are generally used as the unit for policy attachment, while template expansion relies on each member's entity attributes (for example, entity.metadata.team or aliases). In other words, the group decides who the policy applies to, and each member's entity information decides which paths it reaches.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Vault

Vault Core Concepts: Sealed/Unsealed, Auth, Secrets (2026)

Vault fundamentals — sealed/unsealed state, auth methods, se...

Vault

Vault Operations Professional (VOP-003): Complete Guide (2026)

Pass the Vault Operations Professional exam — enterprise pat...

Vault

Vault Path-Based Routing: API URL Structure (2026)

How Vault's path-based routing works — mount points, sub-pat...

Vault

Vault Tokens: Auth Token Mechanics (2026)

Token fundamentals — service vs. batch tokens, accessor, ren...

Vault

Vault Token Types: Service, Batch, Periodic (2026)

Service vs. batch tokens compared — performance, ACL behavio...

Browse all Vault articles (101)
© 2026 NicheeLab All rights reserved.