Skip to content
7 min read·Lesson 4 of 8

Policies and Authorization

Write Vault policies in HCL — paths, capabilities, parameters, templating, and Sentinel for Enterprise governance.

Policies are how Vault grants and denies operations. They are written in HCL, attached to tokens, and evaluated on every request. Mastery of policies is the difference between a Vault deployment that's actually secure and one that's just on.

Policy Structure

# Allow reading the database static credentials
path "secret/data/database/*" {
  capabilities = ["read"]
}

# Allow generating dynamic credentials
path "database/creds/web-api" {
  capabilities = ["read"]
}

# Allow self-renew of the token
path "auth/token/renew-self" {
  capabilities = ["update"]
}

Capabilities

CapabilityWhat it allows
createPOST without existing data
readGET
updatePOST / PUT modifying existing data
deleteDELETE
listLIST operations
sudoRequired to call certain root-protected paths
denyExplicit deny — overrides all allows

You almost always want the minimum set. The most common mistake: granting create, read, update, delete, list when only read is needed.

Path Globbing

Two wildcard styles:

  • * at the end of a path — match anything after that point at the same level
  • + — match exactly one path segment
path "secret/data/team-a/*"  { capabilities = ["read"] }      # everything under team-a/
path "secret/data/+/shared"  { capabilities = ["read"] }      # any team's shared/ subdir

Effective Permissions

A token can carry multiple policies. The effective permission for a (path, capability) pair is:

  1. If any attached policy denies, the request is denied.
  2. Otherwise, if any attached policy allows, the request is allowed.
  3. Otherwise, denied (Vault is default-deny).

Parameter Constraints

Beyond capabilities, you can restrict which parameter values a request may include:

path "auth/token/create" {
  capabilities = ["update"]
  allowed_parameters = {
    "policies" = ["web-api", "web-api-readonly"]
    "ttl"      = []                       # any value allowed
  }
  denied_parameters = {
    "no_default_policy" = []
  }
}

Useful when you give a service the right to create tokens but only with a specific policy attached.

Policy Templating

You can reference identity attributes in path expressions:

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

This single policy gives every user access only to their own subtree. Perfect for self-service personal secrets.

Common Policy Idioms

Read-only across one engine

path "secret/data/*" {
  capabilities = ["read", "list"]
}
path "secret/metadata/*" {
  capabilities = ["read", "list"]
}

Allow token self-management

path "auth/token/lookup-self" { capabilities = ["read"] }
path "auth/token/renew-self"  { capabilities = ["update"] }
path "auth/token/revoke-self" { capabilities = ["update"] }

Almost every policy needs these — apps need to look up their own token to know when to renew.

Operations team

path "sys/policies/acl"           { capabilities = ["list"] }
path "sys/policies/acl/*"         { capabilities = ["read", "create", "update", "delete"] }
path "sys/audit"                  { capabilities = ["read", "sudo"] }
path "sys/audit/*"                { capabilities = ["create", "update", "delete", "sudo"] }
path "sys/auth"                   { capabilities = ["read", "list"] }
path "sys/mounts"                 { capabilities = ["read", "list"] }

Default and Root Policies

  • default: Auto-attached to every token; allows token lookup/renew and a few other harmless paths. Don't disable it; refine it instead.
  • root: Implicit unlimited access. Only the initial root token and the regenerated root tokens have it. Never attach it to anything else.

Attaching Policies

Policies are attached when the token is created:

# Via an auth role
vault write auth/approle/role/web-api token_policies="web-api,default"

# Via an explicit token creation
vault token create -policy=web-api -ttl=1h

# Via identity group (Enterprise)
vault write identity/group name=engineering policies="developer"

Testing Policies

vault token capabilities <token> secret/data/database/master
# returns: read

vault policy fmt my-policy.hcl
vault policy write my-policy my-policy.hcl

Test policies in dev before deploying to prod. A broken policy on production Vault locks out legitimate apps.

Sentinel and EGPs (Enterprise)

Vault Enterprise adds Sentinel — a policy-as-code language for cross-cutting policies that simple ACLs can't express:

  • Role-Governing Policies (RGPs): Constraints on what a specific identity can do
  • Endpoint-Governing Policies (EGPs): Constraints on a specific path regardless of identity

Example EGP: "No write to kv/data/critical/* outside business hours." This is impossible with HCL ACLs alone.

Least-Privilege Workflow

  1. Start with a policy that denies everything (no paths)
  2. Add paths one at a time as the app fails with 403s
  3. Review the final list — every line should map to a concrete need
  4. Tag policies with the application name in the path: app-policy/web-api
  5. Audit the policy in PR review like any other code

Policies are the contract between an application and its secrets. Treat them with the rigor of any other security control.

Key Takeaways

  • Policies are HCL files mapping paths to capabilities (create, read, update, delete, list, sudo, deny).
  • Effective permissions = union of all policies attached to the token, with deny taking precedence.
  • Paths support globs (*) and recursive globs (+) for fine-grained access.
  • Policy templating ({{identity.entity.name}}) personalises paths per entity.
  • Sentinel and EGPs (Enterprise) add role-governing policies beyond simple path ACLs.

Test your knowledge

Try exam-style practice questions to reinforce what you've learned.

Practice Questions →