Vault "permission denied" reading a secret in CI
The token that CI is using is valid, but the policies attached to it do not grant the read capability on the path you requested. Vault authorized the request holder and then refused the specific operation.
What this error means
A vault kv get or API read fails with "Error reading secret/data/app: Code: 403. Errors: * permission denied" while auth itself succeeded.
$ vault kv get secret/data/ci/app
Error reading secret/data/ci/app: Error making API request.
URL: GET https://vault.example.com/v1/secret/data/ci/app
Code: 403. Errors:
* permission deniedCommon causes
The policy lacks read capability on the path
The token authenticated fine, but no attached policy lists read (or list) capability for secret/data/ci/app, so Vault returns 403.
The path in the policy does not match the request path
For KV v2 the ACL path is secret/data/... (and secret/metadata/... for listing), not secret/.... A policy written against the wrong prefix never matches.
How to fix it
Grant read on the exact KV v2 data path
- Write a policy that grants
readonsecret/data/ci/app(addlistonsecret/metadata/ci/*if you list). - Attach the policy to the AppRole, JWT, or Kubernetes role CI logs in with.
- Re-run the job and confirm the read now returns the secret.
path "secret/data/ci/app" {
capabilities = ["read"]
}
path "secret/metadata/ci/*" {
capabilities = ["list"]
}Bind the policy to the auth role
A policy only takes effect when it is attached to the role the CI login uses.
vault write auth/approle/role/ci token_policies="ci-read"How to prevent it
- Write ACL paths against the real KV v2 layout (
data/to read,metadata/to list). - Use least-privilege read-only policies scoped to the CI paths only.
- Test a policy with
vault token capabilities <token> secret/data/ci/appbefore shipping.