Vault KV Engine & Policies¶
dotvault stores per-user secrets in a KVv2 secrets engine under a user prefix. This page describes how to set up the KV namespace and write a template policy so each user can only access their own secrets.
KV namespace layout¶
The default layout uses the kv mount with a users/ prefix:
kv/
data/
users/
jane/
gh ← GitHub credentials
ssh ← SSH private key
aws ← AWS credentials
bob/
gh
ssh
Each user has their own subtree under users/{username}/. The username is determined by the auth method — for OIDC it typically comes from the email or preferred_username claim; for LDAP it's the login name.
Enable the KVv2 secrets engine¶
If not already enabled:
Template policy¶
Vault's template policies let you write a single policy that dynamically scopes access to the authenticated user's identity. This avoids creating per-user policies.
Create a file dotvault-user.hcl:
# Allow users to manage their own secrets under the user prefix.
# The {{identity.entity.aliases.<MOUNT_ACCESSOR>.name}} template
# resolves to the authenticated username.
# List the user's own secret keys
path "kv/metadata/users/{{identity.entity.aliases.<MOUNT_ACCESSOR>.name}}/*" {
capabilities = ["list", "read"]
}
# Read and write the user's own secrets
path "kv/data/users/{{identity.entity.aliases.<MOUNT_ACCESSOR>.name}}/*" {
capabilities = ["create", "update", "read"]
}
# Allow deleting the user's own secrets
path "kv/delete/users/{{identity.entity.aliases.<MOUNT_ACCESSOR>.name}}/*" {
capabilities = ["update"]
}
Replace the mount accessor
The <MOUNT_ACCESSOR> placeholder must be replaced with the actual accessor for your auth method. Find it with:
For example, if the accessor is auth_oidc_12345678, the path becomes:
Apply the policy:
Then attach it to the auth method role:
# For OIDC
vault write auth/oidc/role/default \
token_policies="dotvault-user" \
...
# For LDAP (via group mapping)
vault write auth/ldap/groups/developers \
policies="dotvault-user"
Seeding secrets¶
Administrators or users can pre-populate secrets using the Vault CLI:
vault kv put kv/users/jane/gh oauth_token="ghp_xxxxxxxxxxxx" user="jane"
vault kv put kv/users/jane/ssh private_key=@~/.ssh/id_ed25519
Or through the Vault UI, if available.
dotvault's service onboarding feature can also automate this — for example, running a GitHub OAuth device flow to obtain a token and writing it to Vault automatically.
Customising the namespace¶
The KV mount and user prefix are configurable:
vault:
kv_mount: "secrets" # use a different mount
user_prefix: "personal/" # use a different prefix
With these settings, secrets are read from secrets/data/personal/{username}/{vault_key}.
Note
The user_prefix must end with a trailing slash. dotvault enforces this — if you omit the slash, it is appended automatically.