What are Vault policies and how does path-based access control work?
Quick Answer
Vault policies are rules written in HCL or JSON that control what a token can do. Each rule maps a path to allowed actions (create, read, update, delete, list). Everything is denied by default unless a policy explicitly allows it.
Detailed Answer
Think of Vault policies like the badge system in a large office building. Your badge determines which floors you can visit, which doors you can open, and what you can do in each room. Some badges let you enter a room and read documents but not change them. Others give full access to certain floors while blocking others entirely. Just as a building security system keeps all doors locked by default, Vault denies all access unless a policy explicitly allows it.
Vault policies are written in HCL (HashiCorp Configuration Language) or JSON and define rules that map API paths to allowed actions. The five main actions are create, read, update, delete, and list. Two additional actions exist: sudo (for protected admin paths) and deny (an explicit override that blocks access no matter what). Policies follow a deny-by-default model, meaning a token with no policies can access nothing. Two built-in policies exist: the default policy grants basic self-management like token lookup and renewal, and the root policy grants unrestricted access to everything. Custom policies get attached to tokens during authentication, and a token's effective permissions are the combination of all its attached policies.
Under the hood, Vault evaluates policies using a longest-prefix-match approach. When a client makes a request to secret/data/payments-api/db, Vault looks at all policies on the token and finds the most specific matching path rule. Path patterns support wildcards: the asterisk matches any single path segment, and the plus sign matches one directory level. For example, secret/data/payments-api/* matches any key under payments-api but not nested paths, while secret/data/+ matches any direct child of data. Vault also supports templated policies using identity metadata, so you can write rules like secret/data/{{identity.entity.name}}/* to let each authenticated entity access only secrets under their own namespace. Policy changes take effect right away for new requests without needing to regenerate tokens.
In production, policy design follows least-privilege principles organized around your team structure. Teams typically create policies at three levels: infrastructure policies for platform teams (managing auth methods, secrets engines, and audit devices), application policies for service identities (reading specific secrets and generating dynamic credentials), and operator policies for human users (managing secrets within their team's area). Sentinel policies, available in Vault Enterprise, add a second enforcement layer with governance rules that can require MFA for certain paths or restrict secret creation to specific time windows. Many organizations use Terraform to manage Vault policies as code, which enables peer review and version control for access changes.
The most common mistake is overly broad wildcard policies that accidentally grant more access than intended. A policy like path "secret/*" { capabilities = ["read"] } looks reasonable but gives read access to every secret in the entire KV store, including other teams' secrets. Another frequent error is forgetting that the list action is separate from read. A service might be able to read a specific secret but cannot discover what secrets exist without list permission. Teams also trip over the difference between secret/data/ and secret/metadata/ paths in KV v2. The actual secret values live under data/ while version history and metadata live under metadata/, so you need separate policy rules for each.