HashiCorp Vault — Policies Exercises
Practice writing and testing Vault policies.
Exercise 1 — Least Privilege Policy
Task: Write a policy for a web application that needs to:
- Read secrets under
secret/data/webapp/* - List secret keys under
secret/metadata/webapp/* - Encrypt/decrypt using the
webapp-keytransit key - NOT access any other path
Show Answer
# webapp-policy.hcl
path "secret/data/webapp/*" {
capabilities = ["read"]
}
path "secret/metadata/webapp/*" {
capabilities = ["list", "read"]
}
path "transit/encrypt/webapp-key" {
capabilities = ["update"]
}
path "transit/decrypt/webapp-key" {
capabilities = ["update"]
}
# Deploy and test
vault policy write webapp webapp-policy.hcl
TEST_TOKEN=$(vault token create -policy=webapp -ttl=5m -field=token)
# Should succeed
VAULT_TOKEN=$TEST_TOKEN vault kv get secret/webapp/config
# Should fail
VAULT_TOKEN=$TEST_TOKEN vault kv get secret/admin/config
# Error: permission denied
vault token revoke $TEST_TOKEN
Exercise 2 — Team Isolation
Task: Create policies for two teams: alpha and bravo. Each team should:
- Have full CRUD on their own path (
secret/data/teams/<team>/*) - Be able to read shared secrets (
secret/data/shared/*) - NOT be able to access the other team’s secrets
Show Answer
# team-alpha.hcl
path "secret/data/teams/alpha/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "secret/metadata/teams/alpha/*" {
capabilities = ["list", "read"]
}
path "secret/data/shared/*" {
capabilities = ["read"]
}
path "secret/metadata/shared/*" {
capabilities = ["list"]
}
path "secret/data/teams/bravo/*" {
capabilities = ["deny"]
}
# team-bravo.hcl
path "secret/data/teams/bravo/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "secret/metadata/teams/bravo/*" {
capabilities = ["list", "read"]
}
path "secret/data/shared/*" {
capabilities = ["read"]
}
path "secret/metadata/shared/*" {
capabilities = ["list"]
}
path "secret/data/teams/alpha/*" {
capabilities = ["deny"]
}
vault policy write team-alpha team-alpha.hcl
vault policy write team-bravo team-bravo.hcl
# Test isolation
ALPHA_TOKEN=$(vault token create -policy=team-alpha -ttl=5m -field=token)
VAULT_TOKEN=$ALPHA_TOKEN vault kv put secret/teams/alpha/db password=abc
# Success!
VAULT_TOKEN=$ALPHA_TOKEN vault kv get secret/teams/bravo/db
# Error: permission denied
Exercise 3 — Templated Policy
Task: Write a single templated policy that gives every user access to their own namespace under secret/data/users/<username>/*.
Show Answer
# user-workspace.hcl
path "secret/data/users/{{identity.entity.name}}/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "secret/metadata/users/{{identity.entity.name}}/*" {
capabilities = ["list", "read"]
}
vault policy write user-workspace user-workspace.hcl
# Create users with the policy
vault write auth/userpass/users/alice password="pass" policies="user-workspace"
vault write auth/userpass/users/bob password="pass" policies="user-workspace"
# Login as alice
vault login -method=userpass username=alice password="pass"
vault kv put secret/users/alice/mykey value=mysecret
# Success!
vault kv get secret/users/bob/mykey
# Error: permission denied
Exercise 4 — Sudo and Deny
Task: Write an admin policy that can:
- Manage all secrets
- Manage policies
- Enable/disable auth methods
- But CANNOT seal Vault or step down the leader
Show Answer
# admin-restricted.hcl
# Manage all secrets
path "secret/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Manage policies (requires sudo)
path "sys/policies/acl/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "sys/policies/acl" {
capabilities = ["list"]
}
# Manage auth methods (requires sudo)
path "sys/auth/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "sys/auth" {
capabilities = ["read"]
}
# Explicitly deny seal and step-down
path "sys/seal" {
capabilities = ["deny"]
}
path "sys/step-down" {
capabilities = ["deny"]
}
vault policy write admin-restricted admin-restricted.hcl
ADMIN_TOKEN=$(vault token create -policy=admin-restricted -ttl=1h -field=token)
# Can manage policies
VAULT_TOKEN=$ADMIN_TOKEN vault policy write test - <<EOF
path "secret/data/test/*" { capabilities = ["read"] }
EOF
# Success!
# Cannot seal vault
VAULT_TOKEN=$ADMIN_TOKEN vault operator seal
# Error: permission denied
Exercise 5 — Policy Debugging
Task: A user reports they can’t read secret/data/myapp/database. Debug the issue.
Given policy:
path "secret/data/myapp" {
capabilities = ["read", "list"]
}
Why can’t they read secret/data/myapp/database?
Show Answer
The policy grants access to secret/data/myapp (exact path) but NOT secret/data/myapp/database (a sub-path).
Fix — add a glob wildcard:
path "secret/data/myapp/*" {
capabilities = ["read", "list"]
}
Or to include both the path itself and sub-paths:
# The exact path
path "secret/data/myapp" {
capabilities = ["read", "list"]
}
# Everything below it
path "secret/data/myapp/*" {
capabilities = ["read", "list"]
}
Debug with:
vault token capabilities secret/data/myapp/database
# deny (no matching policy)
What’s Next?
With authentication and authorization covered, it’s time for the powerful feature that sets Vault apart — dynamic secrets.
Next Chapter: Dynamic Secrets