SaltStack, Vault and host/role policies?

Hi,

I’m using SaltStack for provisioning and have the vault runner configured, but don’t want hosts to be able to access all secrets.

I’ve got it generating tokens for minions with the following policies:

    policies:
        - saltstack/minions
        - saltstack/minion/{minion}
        - saltstack/roles/{grains[roles]}

Then i’m arranging secrets in a KV v2 like:
salt/roles/webserver/key
salt/roles/database/key
salt/hosts/myhostname/key

I then need to add policies so each host can access secrets under the path for that host and the roles it has only.

I don’t really want to have to generate a separate policy for each role and host and maintain them, so I was hoping I could do it with the templated policies (or some other way?).

It looks like I could do something like this?:

path "salt/hosts/{{identity.entity.id}}/*" {
  ...
}

Is it possible to debug those variables and see what they contain for a certain token?

Would that work?

Is it possible to do something similar for the roles?

Anyone done similar?

Thanks,

Ian

Hi @ichilton,

this is an interesting question. The full list of available ACL policy path template parameters can be found here: policy-templating#available-templating-parameters

I think using ACL policy path templating can be used to reduce the number of required policies like you described. However, it sounds like your orchestrator uses the token auth backend to create tokens for the managed hosts. The token auth backend doesn’t support entities. The problem is that you need an entity for templating to work. When you just create a token, no entity is associated with it.

You would have to use a different auth backend to pursue this idea, e. g. the AppRole backend. You could use a generic “managedHost” AppRole. The process from the viewpoint of the orchestrator would look something like this:

  1. Get the role_id by using vault read -field=role_id auth/approle/role/<role_name>/role-id
  2. Get the secret_id by using vault write -field=secret_id -f auth/approle/role/<role_name>/secret-id
  3. Use vault login for the AppRole ID and Secret ID (this step creates the entity)
  4. Get the entity_id by using vault write -field=id identity/lookup/entity alias_name=<role_id> alias_mount_accessor=<accessor> where accessor is the ID of your AppRole authentication method (from the Auth Methods section in Vault). Reference: api-docs/secret/identity/lookup#lookup-an-entity
  5. Write the metadata that will be used in the templated policies to the entity, e. g. by using vault write identity/entity/id/<entity_id>/ metadata=host=postgresql001.
  6. Pass the token to the managed host.

It might be possible to let the orchestrator create the entity explicitly beforehand. The orchestrator then would pass the AppRole ID and AppRole secret to the managed host which logs in by itself.

Best
Nick

Hi @ichilton,

regarding your question “anyone done similar?”: I went the route of maintaining policies per host (or rather per Kubernetes namespace, but it maps to a similar problem). I used Terraform to manage the policies.

Best
Nick

Hi @Nick-Triller,

Thank you for the replies! - for some reason I missed the notification of your original reply and only just saw it.

Thank you for the information - i’ll have to do some experimenting!

SaltStack supports the AppRole authentication method as well as token [1] - in fact it says it’s the preferred method - I just went with token to get started easily. I assume it’ll do the process you describe in the background.

I’ll have to dig in to whether it supports the passing of metadata. If I understand correctly, that’s probably what I need as then I could pass my role name(s) from salt when the ‘minion’ (host being provisioned) authenticates with vault and then I could refer to that in a policy?

I did read the templating parameters section on that page before posting, but it doesn’t give examples of what the values of those parameters might be or where they come from…and I can’t think of a way of being able to debug that - i.e print them out for a given request.

I was thinking what I could do is have either salt - or a script querying salt write out a policy for each host and for each role. That just seemed like it would get a bit unwieldy en-mass and also wouldn’t be instant when a new host/role was added. It sounds like that’s what you do though, so maybe it’s not the bad idea I thought it maybe was!

Thanks,

Ian

[1] - salt.modules.vault module

1 Like