hashicorp / vault

A tool for secrets management, encryption as a service, and privileged access management
https://www.vaultproject.io/
Other
30.91k stars 4.18k forks source link

Documentation: unclear meaning of "list" capability in policy page #13011

Open kkredit opened 2 years ago

kkredit commented 2 years ago

Documentation issue

The "Policies > Capabilities" documentation (here) is somewhat misleading about the list capability. The docs say,

~> In the list below, the associated HTTP verbs are shown in parenthesis next to the capability."

And then include

  • list (LIST)

This suggests that LIST is an HTTP verb, which it is not. My understanding is that a list capability on /things/* is equivalent to a read capability (which is GET) on /things. Please clarify the description of the list capability.

maxb commented 2 years ago

(Note: I don't work for HashiCorp, I just came across this whilst browsing for some of my own issues. Everything said below is things I've learned whilst working with Vault.)

Vault accepts LIST as a HTTP verb. I'd actually assumed it was a standard verb, and was surprised when I checked https://www.iana.org/assignments/http-methods/http-methods.xhtml and found it isn't!

Vault also accepts GET with query-params ?list=true as an alternative form of a list operation, for use when the HTTP client software doesn't allow sending a LIST verb.

list and read capabilities are not equivalent at all - in Vault, an operation is either a list or a read, and requires the appropriate capability.

There are some rather complex and completely undocumented subtleties involved with how Vault matches list requests to ACL policies, which I ended up having to teach myself by reading the source code:

  1. Whether the user includes it or not, all list operations are canonicalised by Vault to end with a trailing /, and this has an effect on what policy paths such requests match. (https://github.com/hashicorp/vault/blob/ec7c50a5035a3573154c4e89c7a5629b3dc6e156/http/logical.go#L75-L77 and similar code later in the file)

  2. When processing a list operation, there's an extra check for matching against a policy with the trailing / chopped off again - BUT, and here's a tricky exception - it doesn't apply if there's a /+/ wildcard in the policy path - my guess is someone overlooked coding that case when /+/ wildcard support was added to Vault. (https://github.com/hashicorp/vault/blob/ec7c50a5035a3573154c4e89c7a5629b3dc6e156/vault/acl.go#L365-L372)

Put these together, and you get a variety of behaviours, some useful, some infuriating.

Useful: a policy like this:

path "auth/approle/role/*" {
  capabilities = ["read", "list"]
}

turns out to be sufficient to allow vault list auth/approle/role even though an understanding based on basic shell globbing would make you think it didn't match. You don't have to write this repetitive style of policy every time you want to manage a collection:

path "auth/approle/role" {
  capabilities = ["list"]
}

path "auth/approle/role/*" {
  capabilities = ["read"]
}

Useful: a policy like this:

path "auth/approle/role/some-role/secret-id" {
  capabilities = ["update"]
  control_group { ... all the usual control group stuff ... }
}

will apply a control group to the path for all operations. But, if you additionally define a policy with a trailing slash, and no control group:

path "auth/approle/role/some-role/secret-id/" {
  capabilities = ["list"]
}

then list operations will match the second policy and not be subject to the control group. (OK, this is somewhat less vital since support for controlled_capabilities was added, but I haven't been able to upgrade to a version with that yet.)

Infuriating: a policy like this:

path "some-specific-namespace/auth/token/accessors" {
  capabilities = ["list", "sudo"]
}

works as intended, but if you try to set up a policy covering wildcarded namespaces:

path "+/auth/token/accessors" {
  capabilities = ["list", "sudo"]
}

it fails to allow the access! You have to write this policy with a trailing slash for it to take effect:

path "+/auth/token/accessors/" {
  capabilities = ["list", "sudo"]
}
heatherezell commented 2 years ago

@taoism4504 - another issue where we may want to think about how we're describing capabilities in our docs. Thanks! :)

nafarlee commented 1 year ago

@maxb I cannot express how much your comprehensive description of this behavior rescued my sanity. Thank you so much.

maxb commented 1 year ago

Thank you - it's always nice to know my words had a positive effect on someone!

macmiranda commented 1 year ago

I guess the closest the documentation gets to what was described here is https://github.com/hashicorp/vault/blob/1361932d9151194ea06e9677394244729873d31c/website/content/docs/concepts/policies.mdx?plain=1#L197-L199

@solutiongeek any way this could be better?