Vault policies are the access rules that control who can read, write, or delete secrets in your Vault server. Without policies, every user could access every secret, which defeats the whole purpose of having a secrets vault. For the VA-003 exam, policy authoring is a core skill — roughly 15% of the exam questions test your ability to write, interpret, and organise policies correctly.
Jump to a section
A simple way to picture Policy Authoring and Best Practices
Your apartment building has 37 pages of rules. Rule 12 says 'No pets over 15 kilograms.' Rule 18 says 'The gym closes at 10 PM.' Rule 31 says 'Only residents with a blue key fob can enter the rooftop garden.' These rules are not suggestions — they are enforced by the building manager. If you break Rule 12 by bringing a 20-kilogram dog into the lift, the manager stops the lift and sends you back. If a courier tries the rooftop with a standard key fob, the door stays locked.
Now imagine the building manager did not have these rules written down. Instead, he just made decisions on the spot. One day he lets a cat into the gym. The next day he bans all visitors. Tenants would get confused and angry. Security would be unpredictable. The written rulebook solves this. It is consistent. It is auditable — the landlord can check whether the manager followed Rule 18 last Tuesday night.
In HashiCorp Vault, policies are exactly this rulebook. Vault holds your organisation's secrets — passwords, database credentials, API keys. A Vault policy is a written rule that says who can read which secret, at what time, and under what conditions. Without policies, everyone could read everything. With good policies, access follows the 'least privilege' principle — you give each person or machine exactly the access they need, and nothing more. The 37-page rulebook sounds tedious until a 20-kilogram dog rides the lift to the rooftop garden. Then you are glad the rules exist.
A Vault policy is a set of rules written in a language called HashiCorp Configuration Language (HCL). HCL looks similar to JSON but is designed to be human-readable. Each policy contains one or more 'path' statements. A path is the location of a secret or resource inside Vault, like a folder on a computer. For example, the path 'secret/data/engineering' points to all secrets stored under the 'engineering' folder in the 'secret' secrets engine.
Every path in a policy has one or more 'capabilities'. Capabilities are the actions you are allowed to take on that path. The four main capabilities you need to know for the exam are: 'create' (write a new secret), 'read' (view an existing secret), 'update' (modify an existing secret), and 'delete' (remove a secret). There is also 'list' (show all secret names in a folder) and 'sudo' (perform privileged operations).
A simple policy looks like this:
path "secret/data/engineering/*" { capabilities = ["read", "list"] }
This policy says: for any secret inside the 'engineering' folder, the user can read the secret value and list the secret names. The asterisk '*' is a wildcard — it matches any number of characters. So 'secret/data/engineering/*' matches 'secret/data/engineering/database-password' and 'secret/data/engineering/API-keys/production'.
Wildcards are powerful but dangerous. A path like 'secret/data/*' gives access to every secret under the 'secret' mount, which breaks the least privilege principle. Least privilege means you give someone exactly the access they need to do their job, and no more. The VA-003 exam will test your understanding of wildcards and least privilege repeatedly.
Policies are evaluated using 'most specific path wins' logic. If a user has two policies attached to them, Vault looks at both policies and applies the one with the most specific path. For example, Policy A says 'read on secret/data/engineering/*', and Policy B says 'deny on secret/data/engineering/payroll'. The user can read everything in engineering except the payroll folder, because the specific deny cancels the broader allow. Deny capabilities always override allow capabilities when they conflict at the same path specificity.
Policies are attached to users through 'tokens'. Every time a user or machine authenticates to Vault, they receive a token. That token has one or more policies attached. The token is the key that the user presents to Vault with every request. Vault checks the token's policies before deciding whether to grant access.
Best practices for policy authoring include:
Use the smallest possible scope. Instead of granting 'read' to 'secret/data/*', grant 'read' only to 'secret/data/team-name/*'.
Prefer explicit deny rules for sensitive paths that should never be accessed by a particular group.
Group policies by function, not by person. Create a 'developer' policy, not a 'john-smith' policy. This makes audits easier.
Use 'list-only' policies for directories so users can see what secrets exist without reading the values.
Never write a policy with 'sudo' unless absolutely necessary. Sudo capability allows bypassing certain access control restrictions.
Write policies using the principle of default deny — if there is no policy rule that explicitly allows an action, that action is denied.
Vault policies are not the same as file system permissions. In Linux, if you own a file you can usually override its permissions. In Vault, policy rules are absolute — if no policy grants you 'read' on a path, you cannot read it, even if you are root. This makes Vault policies extremely secure but also means you must plan carefully.
For the VA-003 exam, you must memorise the following capabilities and their exact meanings: create, read, update, delete, list, sudo, deny. You must also understand glob patterns (the asterisk and plus sign syntax). The most common exam mistake is confusing 'update' with 'create' — update only works on existing secrets; create only works on new secrets. If a user needs to both create and update, you must list both capabilities.
Define the path
Identify the exact location of the secrets you want to control. The path must start with the secrets engine mount point, usually 'secret/data/' for KV v2. For example, 'secret/data/engineering/production/database-password'. Write the path as a string inside double quotes. Use wildcards (asterisks) only when necessary to cover multiple subpaths.
Choose the capabilities
Decide which actions the user should be allowed to perform on that path. List exactly the capabilities needed: create for new secrets, update for existing secrets, read for viewing values, delete for removing secrets, list for enumerating secret names. Do not add capabilities 'just in case'. Follow least privilege — the fewer capabilities, the safer.
Write the policy block
Write the HCL block with the path and capabilities inside curly braces. Syntax: path "your-path" { capabilities = ["cap1", "cap2"] }. Each capability is a lowercase string inside double quotes. Separate multiple capabilities with commas. The block must be properly indented for readability.
Add deny rules for exceptions
If you have a broad allow rule (like 'read on secret/data/engineering/*') but need to block access to a specific subpath (like payroll), write a separate policy block with the deny capability on that specific subpath. Deny blocks should use the most specific path possible to avoid accidentally blocking more than intended.
Save and attach the policy
Save the policy as a file in Vault using the command 'vault policy write policy-name policy-file.hcl'. The policy name should reflect its purpose, like 'engineering-readonly' or 'db-admin'. Then create a token or role that uses this policy. Verify the policy works by logging in as that user and trying to access a secret.
Audit the policy regularly
Review the policy every quarter or whenever a team member changes roles. Use 'vault policy list' to see all policies and 'vault policy read policy-name' to inspect their contents. Look for overly broad wildcards, unused capabilities, or policies that are no longer needed. Remove obsolete policies to keep the environment tidy.
An IT professional at a mid-sized e-commerce company, let us call her Priya, is responsible for managing secrets with Vault. The company has three teams: Engineering, Marketing, and DevOps. Each team stores secrets in Vault under their own path. Engineering uses 'secret/data/engineering/', Marketing uses 'secret/data/marketing/', and DevOps uses 'secret/data/devops/'.
Priya's first task on Monday morning is to grant a new engineer, Raj, access to the engineering secrets. She does not give Raj the 'root' policy — that would give him access to everything. Instead, she creates a policy called 'engineering-standard' that grants 'read' and 'list' on 'secret/data/engineering/*' and 'read' on 'secret/data/devops/deployment-keys' because Raj needs to see the deployment keys for his project.
The policy file looks like this:
path "secret/data/engineering/*" { capabilities = ["read", "list"] }
path "secret/data/devops/deployment-keys" { capabilities = ["read"] }
Priya attaches this policy to Raj's token. Now Raj can read his team's secrets and the specific deployment key, but he cannot see Marketing's secrets or write any secrets.
Later that week, a senior engineer, Maria, needs to rotate the production database password. Rotating a password requires the 'update' capability — she needs to change the existing secret's value. Maria also needs to see the old password before changing it, so she needs 'read' too. Priya creates a policy called 'db-admin' with 'read' and 'update' on 'secret/data/engineering/production-database'. She does not give 'delete' because Maria should never delete the production database secret.
Next, the DevOps team asks for a policy that blocks all access to the 'secret/data/devops/deployment-keys' path except for two senior engineers. Priya writes a deny policy specifically for the junior DevOps members:
path "secret/data/devops/deployment-keys" { capabilities = ["deny"] }
She attaches this deny policy to the junior DevOps tokens. The deny overrides any broader allow from other policies, ensuring those junior members cannot read the deployment keys even if another policy might grant them access to the whole DevOps path.
Every quarter, Priya audits all policies. She checks if any policy uses a broad wildcard like 'secret/data/*'. She also checks if any token has more than four policies attached — too many policies can create confusing overlaps and accidental permissions. She uses the Vault command 'vault policy list' to see all policies, then 'vault policy read policy-name' to inspect each one.
Priya also documents every policy in a company wiki. Each policy entry explains what team it is for, what it allows, and who approved it. This documentation becomes critical during a security audit. The auditors ask to see the 'principle of least privilege' in action. Priya shows them the 'engineering-standard' policy and explains that it only grants read access, not write or delete. The auditors are satisfied.
In an emergency, such as a security breach, Priya can revoke all tokens that have a specific policy. She does this with the command 'vault token revoke -mode path secret/data/engineering/*'. This instantly blocks all access to that path for every token in the system, giving the team time to investigate without secrets being leaked.
The key point here is that Priya does not write policies once and forget them. Policy management is an ongoing process. Every new employee, every new project, and every new secret path requires a policy review. The exam tests whether you understand this lifecycle: create, attach, audit, revoke.
The VA-003 exam tests 'Policy Authoring and Best Practices' under objective 1.4, which accounts for roughly 15-20% of the total exam. Expect 5 to 8 questions on this topic. The questions fall into three categories: policy syntax interpretation, least privilege auditing, and capabilities matching.
For policy syntax interpretation, the exam gives you a small HCL policy snippet and asks which capabilities are granted on a specific path. The trap is the asterisk wildcard. For example, if the policy says 'path "secret/data/*" ' and a question asks what access the user has to 'secret/data/engineering/db-pass', many beginners think the asterisk only matches one level. In fact, a single asterisk matches everything to the right, so a path with one asterisk matches subpaths. You need to understand that 'path "secret/data/engineering/*" ' is more specific than 'path "secret/data/*" '. The exam will test whether you recognise that the more specific path wins.
For least privilege auditing, the exam describes a scenario with a user who has multiple policies. You must identify which access the user is actually granted. The standard pattern: if one policy grants 'read' on 'secret/data/foo/*' and another policy grants 'deny' on 'secret/data/foo/bar', then the user can read everything under 'foo' except 'foo/bar'. The 'deny' capability always wins when paths are equally specific. If a deny is on a more specific path than an allow, the deny overrides the allow on that specific path.
For capabilities matching, the exam lists a set of actions and asks which capability or combination of capabilities is required. For example, 'writing a new secret' requires the 'create' capability, not 'update'. 'Changing an existing secret' requires the 'update' capability, not 'create'. The exam will also ask about 'list' capability — list lets you see the names of secrets in a path, but not their values. If a user only has 'list' on a path, they can see that 'secret/data/engineering' contains 'db-pass' and 'api-key', but they cannot read the actual password or API key.
Key definitions to memorise exactly:
path: the location of a secret or resource in Vault, written as a string like "secret/data/team-name/*"
capability: an allowed action on a path, such as 'create', 'read', 'update', 'delete', 'list', 'sudo', 'deny'
HCL: HashiCorp Configuration Language, used to write policies
token: a credential that carries one or more policies
most specific path wins: when two policies conflict, the one with the most precise path is applied
deny: a capability that blocks all access to a path, even if another policy allows it
wildcard: the asterisk '*' character that matches any sequence of characters in a path
Exam traps to watch:
'Update' requires an existing secret to function. If the secret does not yet exist, 'update' fails, even if the user has 'update' on the path.
'Create' only works for new secrets. If you try to 'create' a secret that already exists, it fails. You need 'update' for existing secrets.
'Read' and 'list' are different. A user with 'list' can see secret names but not values.
Deny capabilities do not appear in the 'capabilities = []' block often. If a deny exists in any policy the user has, it applies.
A path with no matching policy means all actions are denied. There is no 'default allow' in Vault.
Root tokens bypass all policies. If you see a question about 'root token', the policies are irrelevant.
The path prefix 'secret/data/' is required for KV v2 secrets engines. The exam often uses KV v2, so remember the '/data/' part.
When writing policies for the exam, always think: what is the minimum set of capabilities needed? If a user needs to view and update an existing secret, the correct answer is ['read', 'update'], not ['read', 'create', 'update']. Add 'list' only if they need to enumerate secret names. Add 'deny' only when you need to block access on a specific subpath.
The exam may also present a 'best practice' question asking which approach is correct. The correct answer is almost always: use the least privilege principle, avoid broad wildcards, and use deny only for exceptions. Multiple-choice trap answers include: 'use a single broad policy for all users', 'give everyone the root token', or 'attach policies to individuals instead of roles'. None of those follow best practices.
A Vault policy with no matching path grants zero access — default deny is always in effect.
The asterisk wildcard in a policy path matches everything after it, including all subdirectories.
Deny capability always overrides allow when the deny path is equal to or more specific than the allow path.
Create creates new secrets only; update modifies existing secrets only — they are not interchangeable.
List shows secret names but not secret values; read shows secret values but not necessarily all names.
Attach policies to roles or teams, not to individuals, to simplify audits and reduce policy sprawl.
The most specific path wins when two policies conflict on the same capability.
Root tokens bypass all policies — if a user has a root token, policy rules do not apply to them.
These come up on the exam all the time. Here's how to tell them apart.
Create capability
Used to write a brand new secret that does not exist yet
Fails if the secret already exists at the specified path
Commonly used for onboarding new applications or services
Update capability
Used to modify an existing secret at a known path
Fails if the secret does not already exist
Commonly used for rotating passwords or regenerating API keys
List capability
Returns the names of secrets in a directory-like path
Does not reveal the actual secret values
Useful for discovery and inventory purposes
Read capability
Returns the full contents of a specific secret, including its value
Requires the exact path of the secret to be specified
Grants access to sensitive data like passwords and certificates
Allow rule
Explicitly permits certain capabilities on a path
Can be overridden by a more specific deny rule
Is the standard way to grant access to users
Deny rule
Explicitly blocks all capabilities on a path
Always wins when path specificity is equal or higher than the allow rule
Used sparingly for exceptions to broad allow rules
Role-based policies
Attached to a role that many users share
Easier to audit and maintain at scale
Follows best practice for large teams
Individual-user policies
Crafted specifically for one user's access needs
Harder to audit and track as the number of users grows
Leads to policy sprawl and inconsistency
Mistake
If you have any policy that grants access to a path, you can read all secrets under that path.
Correct
Policies are additive — you only get the capabilities explicitly listed on the paths you match. If a policy grants 'list' on a path, you can list secret names but not read their values. If the policy does not include 'read', you cannot read any secret content under that path.
Beginners assume 'access to a path' means full read/write access, like a folder in a file system. But Vault capabilities are granular — each action is a separate capability.
Mistake
Writing 'capabilities = ['create', 'update']' on a path means the user can both create new secrets and update existing ones, which is always correct.
Correct
This is correct syntactically, but best practice suggests you should only give the minimum capabilities needed. If a user only needs to update existing secrets, give only 'update'. Adding 'create' opens the door to creating new secrets that might not follow naming conventions or security rules.
Beginners think 'more is safer' but in security, more capabilities mean more risk. The principle of least privilege says give exactly what is needed, nothing more.
Mistake
If a deny policy and an allow policy both match the same path, Vault blocks everything because deny overrides everything.
Correct
Deny only overrides allow when the deny is on the same or a more specific path. If the allow is on a more specific path than the deny, the allow applies. For example, allow on 'secret/data/foo/bar' and deny on 'secret/data/foo/*' gives access to 'foo/bar' because the allow path is more specific.
The 'most specific path wins' rule confuses people. They think deny is absolute, but path specificity is checked first. Deny only wins when paths are equally specific or when the deny path is more specific.
Mistake
You can use the asterisk wildcard like a Linux shell glob, where 'secret/data/*' only matches one level deep.
Correct
In Vault policy paths, a single asterisk matches everything to the end of the path, including subdirectories. So 'secret/data/*' matches 'secret/data/engineering', 'secret/data/engineering/db', and 'secret/data/engineering/db/password'. To match one level only, you use the 'in-path' or '+ ' syntax, but the exam rarely tests that.
Most people come from a Linux background where 'ls /secret/data/*' only shows direct children. Vault's glob is more permissive, so beginners underestimate the scope of a single asterisk.
Mistake
The 'list' capability is just a nice extra — it does not affect security because you cannot read secret values with it.
Correct
List capability is a security risk because it reveals secret names. An attacker who can list paths learns what secrets exist and where they are stored. This information helps them target their attacks. Best practice is to give 'list' only to users who need to discover which secrets exist.
Beginners overlook that even knowing a secret exists is valuable information for an attacker. They focus only on preventing value reads, not on hiding the structure.
Mistake
You should write one policy per user to give them exactly what they need.
Correct
Best practice is to write policies per role or team, not per user. For example, write a 'developer' policy and attach it to all developers. This is easier to audit, reduces policy count, and ensures consistency. Individual exceptions can use deny policies.
New IT professionals treat policies like individual permissions, similar to setting up accounts on a website. But Vault is designed for many users, and per-user policies become unmanageable quickly.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
Create allows you to write a new secret that does not already exist at that path. Update allows you to modify an existing secret. If a secret already exists and you try to use 'create', it fails. If you try to 'update' a secret that does not exist, it also fails. You need both if the user must handle new and existing secrets.
No. If a user has no policies attached to their token, every action is denied by default. Vault uses a default-deny model — if no policy explicitly allows an operation, the operation is blocked. This is true even for users with valid tokens.
A single asterisk '*' matches any sequence of characters, including nested subpaths. For example, 'secret/data/*' matches 'secret/data/foo', 'secret/data/foo/bar', and 'secret/data/foo/bar/baz'. There is no way to limit an asterisk to only one directory level using standard HCL — you would need to write separate paths for each level.
Vault uses 'most specific path wins' logic. If both policies have the same path specificity, deny overrides allow. If one policy has a more specific path (e.g., 'secret/data/foo/bar' is more specific than 'secret/data/foo/*'), the more specific policy's capabilities are applied for that path.
Yes, use the 'list' capability. A policy with 'list' on a path allows the user to call the list operation, which returns secret names. Without the 'read' capability, they cannot view the actual values of those secrets.
No. Root tokens bypass all policies. A root token can perform any operation on any path, regardless of what policies say. This is why root tokens should be used only for initial setup and emergency break-glass scenarios.
The 'deny' capability explicitly blocks all access to a path, even if another policy grants access. Use deny for exceptions — for example, if a team policy grants broad access to a folder but you need to block one specific subfolder from that team. Do not use deny as your primary access control method.
You've finished Policy Authoring and Best Practices. Continue through the VA-003 study guide to build a complete picture of the exam.
Done with this chapter?