HashiCorp Vault — Capabilities Deep Dive
Each capability maps to an HTTP operation. Understanding them precisely is critical for writing least-privilege policies.
Capability to HTTP Mapping
| Capability | HTTP Method | Vault CLI Equivalent |
|---|---|---|
create |
POST (new resource) | vault write, vault kv put (new) |
read |
GET | vault read, vault kv get |
update |
POST/PUT (existing) | vault write, vault kv put (update) |
delete |
DELETE | vault delete, vault kv delete |
list |
LIST (GET with ?list=true) |
vault list, vault kv list |
sudo |
— | Access to sudo-protected endpoints |
deny |
— | Explicit deny (highest priority) |
create vs update
For most Vault endpoints, create and update both map to the POST method:
# Allow creating new secrets but NOT updating existing ones
# (Not enforceable for most endpoints — both use POST)
# In practice, grant both together:
path "secret/data/myapp/*" {
capabilities = ["create", "update"]
}
For KV v2 with Check-and-Set (CAS), you can enforce create-only:
# Create new secrets only (CAS = 0 means "create only if not exists")
path "secret/data/myapp/*" {
capabilities = ["create"]
required_parameters = ["options"]
}
The sudo Capability
Certain Vault paths are protected and require sudo:
# System paths that require sudo
path "sys/auth/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "sys/policies/acl/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Root token generation
path "sys/generate-root/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
Common sudo-protected paths:
| Path | Operation |
|---|---|
sys/auth/* |
Enable/disable auth methods |
sys/policies/acl/* |
Manage policies |
sys/mounts/* |
Enable/disable secrets engines |
sys/seal |
Seal Vault |
sys/step-down |
Force leader step-down |
auth/token/create-orphan |
Create orphan tokens |
The deny Capability
deny is the highest priority — it overrides any other policy:
# Allow reading all secrets
path "secret/data/*" {
capabilities = ["read", "list"]
}
# But explicitly deny the admin path
path "secret/data/admin/*" {
capabilities = ["deny"]
}
Use cases for deny:
- Block access to sensitive paths even if a broad policy grants it
- “All except” patterns
- Emergency lockout policies
The list Capability
list must be granted on separate paths for KV v2:
# List secret keys — requires metadata path
path "secret/metadata/*" {
capabilities = ["list"]
}
# Read secret values — requires data path
path "secret/data/*" {
capabilities = ["read"]
}
Without the list capability on metadata, users can read secrets they know the name of, but cannot browse or discover secret names.
Checking Capabilities
# Check what capabilities your token has on a path
vault token capabilities secret/data/myapp/config
# create, read, update
# Check another token's capabilities
vault token capabilities -accessor abc123 secret/data/myapp/config
# API equivalent
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"path": "secret/data/myapp/config"}' \
"$VAULT_ADDR/v1/sys/capabilities-self" | jq
Fine-Grained Controls
Required Parameters
path "secret/data/myapp/*" {
capabilities = ["create", "update"]
required_parameters = ["data"]
}
Allowed Parameters
# Only allow setting specific keys in a secret
path "secret/data/myapp/config" {
capabilities = ["create", "update"]
allowed_parameters = {
"data" = {
"db_host" = []
"db_port" = []
"db_name" = []
}
}
}
Denied Parameters
# Allow all parameters except "password"
path "secret/data/myapp/config" {
capabilities = ["create", "read", "update"]
denied_parameters = {
"data" = {
"password" = []
}
}
}
Min/Max Wrapping TTL
# Force response wrapping for sensitive paths
path "auth/approle/role/webapp/secret-id" {
capabilities = ["create", "update"]
min_wrapping_ttl = "60s"
max_wrapping_ttl = "300s"
}
Quick Reference
| Capability | Use When |
|---|---|
create |
Client needs to create new resources |
read |
Client needs to read data |
update |
Client needs to modify existing data |
delete |
Client needs to remove data |
list |
Client needs to browse/discover keys |
sudo |
Accessing protected system paths |
deny |
Explicitly blocking access |
Next: Policy Examples