Templated Policy

Hi,

I’m using Vault with SaltStack and am trying to create a single policy to replace a policy per host.

When SaltStack creates a token for a minion (host), it automatically includes metadata. In particular, saltstack-minion is set to the hostname.

It makes a request to:
POST /v1/auth/token/create HTTP/1.0

The request contains:

{"policies": ["salt/minions", "salt/minion/myhost.domain.net"], "num_uses": 50, "meta": {"saltstack-jid": "20210622154012124421", "saltstack-minion": "myhost.domain.net", "saltstack-user": "root"}, "explicit_max_ttl": "300"}

The response contains:

"policies":["default","salt/minion/myhost.domain.net","salt/minions"],"token_policies":["default","salt/minion/myhost.domain.net","salt/minions"],"metadata":{"saltstack-jid":"20210622154012124421","saltstack-minion":"myhost.domain.net","saltstack-user":"root"},

A request for auth/token/lookup-self contains:

    meta:
        ----------
        saltstack-jid:
            20210622154012124421
        saltstack-minion:
            myhost.domain.net
        saltstack-user:
            root
    num_uses:

I then create a policy containing:

path "salt/minion/{{identity.entity.metadata.saltstack-minion}}/*" {
  capabilities = ["read"]
}

I then do a request for:

GET /v1/salt/minion/myhost.domain.net/db HTTP/1.0

and it returns 403!

Any ideas why this doesn’t work or how I can debug it further?

Thanks,

Ian

Check what token capabilities shows for the token and the desired path…
Also, confirm the policy is applied to the token?

I’m not sure whether this applies to the templated policies but I’ve run into an issue where the dash/minus sign is interpreted as an operator as opposed to a normal character with Sentinel policies. I’m curious if the same is occurring here and maybe adding single quotes around saltstack-minion would help.

In my case with Sentinel I was able to rename the endpoint in question to use an underscore. I don’t recall whether I tested with single quotes, unfortunately.

Like this? -

path "salt/minion/{{identity.entity.metadata.'saltstack-minion'}}/*" {

That doesn’t work, unfortunately, but thanks for the suggestion.

Ian

$ vault token capabilities s.mytoken salt/minion/myhost.domain.net/db
deny

The policy is definitely being assigned to the token:

$ vault token lookup s.mytoken
Key                 Value
---                 -----
...
policies            [default salt/minion/myhost.domain.net salt/minions]
$ vault policy read salt/minions
path "salt/global/*" {
  capabilities = ["read"]
}

path "salt/minion/{{identity.entity.metadata.saltstack-minion}}/*" {
  capabilities = ["read"]
}

Thanks,

Ian

Namespaces in use?
If you do a
GET /v1/salt/minion/myhost.domain.net/db
with the root or admin-like token, it works?

Not using namespaces.

If I use the root token or a token with the policy salt/minion/myhost.domain.net, which doesn’t have the dynamic/template part, it works fine.

$ vault policy read salt/minion/myhost.domain.net
path "salt/minion/myhost.domain.net/*" {
  capabilities = ["read"]
}

Thanks,

Ian

I meant an actual secret read at the path within the policy - confirming the secret exists.

Yeah salt/minion/myhost.domain.net/db is an actual secret, which I can read fine using the salt/minion/myhost.domain.net policy or root token.

Or am I mis-understanding?

It seems to be the dynamic/template part which isn’t working…

Thanks,

Ian

Your understanding seems correct.
Using terrestrial/cloud Vault deployment, not HCP-Vault, right?

Thanks - have opened a bug report:

Yeah using vault 1.7.x on Linux.

Thanks,

Ian