I want to create a KV secrets engine that would store secrets for multiple users, with each user having access to their own top-level “folder”, being able to do anything under their “folder” including the permanent deletion of the secrets that are inside but not delete their “folder” itself nor access the other user’s “folders”. The management is supposed to be done using the Vault Web UI. I was able to do this with the key-vault engine version 1, but for the version 2 the UI seems to be using wrong paths.
Imagine the following setup: there are two secret engines, called “secrets1” and “secrets2”, the first one is KV version 1, the second is KV version 2. Both engines have “user1/secret” and “user2/secret” pre-configured. When I navigate to “user1” I can delete the “user1/secret” from the UI:
But when I go to the secrets2 engine there is no option to permanenty delete the user1’s secret:
The problem seems to be caused by the incorrect path sent by the UI when the user clicks that “three dots” button: the UI sends POST /v1/sys/capabilities-self with the body {“paths”:[“secrets2/metadata/secret”]} and another with {“paths”:[“secrets2/data/secret”]}, so instead of checking the “user1/secret” it checks just the “secret” as if it was in the root of the secret engine, to which the user doesn’t have access and thus can not delete. If I edit the request to send the body with the “secrets2/metadata/user1/secret” it correctly returns the permissions defined in the policy.
Here are the policies:
The secret1 policy:
# list access to secret1
path "secrets1/*" { capabilities = ["list"] }
# access to secret1/user1
path "secrets1/user1" { capabilities = ["update","patch","list","read"] }
# full access to secret1/user1/*
path "secrets1/user1/*" { capabilities = ["create","delete","update","patch","list","read"] }
And the secret2 policy (note that the “+” placeholder doesn’t seem to be working despite what the documentation says, but that’s an issue for another time):
path "secrets2/*" { capabilities = ["list"] }
# Doesn't work: path "secrets2/+/user1" { capabilities = ["update","patch","list","read"] }
path "secrets2/data/user1" { capabilities = ["update","patch","list","read"] }
path "secrets2/metadata/user1" { capabilities = ["update","patch","list","read"] }
path "secrets2/delete/user1" { capabilities = ["update","patch","list","read"] }
path "secrets2/undelete/user1" { capabilities = ["update","patch","list","read"] }
# Doesn't work: path "secrets2/+/user1/*" { capabilities = ["create","delete","update","patch","list","read"] }
path "secrets2/data/user1/*" { capabilities = ["create","delete","update","patch","list","read"] }
path "secrets2/metadata/user1/*" { capabilities = ["create","delete","update","patch","list","read"] }
path "secrets2/delete/user1/*" { capabilities = ["create","delete","update","patch","list","read"] }
path "secrets2/undelete/user1/*" { capabilities = ["create","delete","update","patch","list","read"] }
path "secrets2/destroy/user1/*" { capabilities = ["create","delete","update","patch","list","read"] }
Am I missing something or is it a bug of the Web UI?