# Vault Policy Writing Standards
## Rule
All Vault policies MUST follow least-privilege principles. Deny by default. Grant explicit capabilities per path. Never use wildcard (*) capabilities on secret paths. Name policies with environment and role prefixes.
## Policy Naming Convention
```
<environment>-<team>-<role>
Examples:
prod-platform-admin
staging-backend-readonly
dev-frontend-secrets
```
## Good Examples
```hcl
# prod-backend-app.hcl — application secrets access
path "secret/data/production/backend/*" {
capabilities = ["read"]
}
# Allow listing secret keys (not values)
path "secret/metadata/production/backend/*" {
capabilities = ["list"]
}
# Database dynamic credentials
path "database/creds/production-backend-readonly" {
capabilities = ["read"]
}
# Allow token self-renewal
path "auth/token/renew-self" {
capabilities = ["update"]
}
# Deny access to other environments
path "secret/data/staging/*" {
capabilities = ["deny"]
}
```
```hcl
# prod-platform-admin.hcl — admin policy
path "secret/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "sys/policies/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Even admins can't read root tokens
path "auth/token/create-orphan" {
capabilities = ["deny"]
}
```
## Bad Examples
```hcl
# BAD: Wildcard everything — defeats the purpose of Vault
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# BAD: Too broad secret access
path "secret/*" {
capabilities = ["read"]
}
# Grants access to ALL secrets across ALL environments
# BAD: No naming convention
path "secret/data/myapp" {
capabilities = ["read"]
}
# Policy file named "policy1.hcl" — meaningless
```
## Enforcement
- Vault Sentinel policies for policy-as-code enforcement
- Quarterly audit of policy assignments
- CI validates policy files with `vault policy fmt`
- Never assign the root policy to service accounts