Vault databases engine policies filtering

Hello everybody,

I’m looking to set up databases dynamics credentials with two roles for each one. reader & operator.

This is the case studie:

2 devel databases:

  • dev01
  • dev02

3 production databases:

  • prod01
  • prod02
  • prod03

3 policies:

  • dev
  • ops
  • support

My aim is to setup one engine databases.
With roles:

dev01-reader
dev01-operator

prod03-reader
prod03-operator

I would like:

  • dev user can read and list only dev* credentials/roles
  • ops user can read and list only dev*reader & prod* credentials/roles
  • support user can read and list only dev*reader & prod*reader credentials/roles.

My tests reveal the conclusion that policies’ granularity permits only allowing access to the entire engine content or nothing.

Is it possible or do I have to create one engine for each combination of kind of environment and kind of role like this ?:

databases-dev-reader
databases-dev-operator
databases-prod-reader
databases-prod-operator

Have a great day

Yes, I think it’s possible to do what you want.

First, configure the database secrets engine something like this:

vault write database/config/dev01 \
    plugin_name="..." \
    connection_url="..." \
    allowed_roles="..." \
    username="vault-dev01" \
    password="..." \
vault write database/config/dev02 \
    plugin_name="..." \
    connection_url="..." \
    allowed_roles="..." \
    username="vault-dev02" \
    password="..." \
...
vault write database/config/prod03 \
    plugin_name="..." \
    connection_url="..." \
    allowed_roles="..." \
    username="vault-prod03" \
    password="..." \

vault write database/roles/dev01-reader \
    db_name=dev01 \
    creation_statements="<GRANT RO, etc.>" \
    default_ttl="1h" \
    max_ttl="24h"
vault write database/roles/dev01-operator \
    db_name=dev01 \
    creation_statements="<GRANT RW, etc.>" \
    default_ttl="1h" \
    max_ttl="24h"
...
vault write database/roles/prod03-operator \
    db_name=prod03 \
    creation_statements="<GRANT RW, etc.>" \
    default_ttl="1h" \
    max_ttl="24h"

Then write a database secrets engine administrator policy something like this:

path "database/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}

# Manage the leases
# Note you could just glob on the creds path if you wanted to simplify
# or cut down on the paths in your policy
path "sys/leases/+/database/creds/<each role>" {
  capabilities = [ "create", "read", "update", "delete", "list", "sudo" ]
}

path "sys/leases/+/database/creds/<each role>/*" {
  capabilities = [ "create", "read", "update", "delete", "list", "sudo" ]
}

Then write your reader policies to have read on the appropriate database/creds/XXX0N-reader paths, and your operator ones to have read on their creds paths. And you could also have a databases reader policy that grants read on multiple ‘reader’ creds paths, etc.

Finally, you could grant list at role related endpoints / paths too, I’d imagine. Also, don’t forget that you always have the ability to explicitly deny paths too, so you have a lot of flexibility when it comes to Vault policy development and administration.

Hi,

Thank you very much for your response.

I’ve attempted your suggestions, but I’m still unclear about the effect of

path “sys/leases/+/database/creds/” {
capabilities = [ “create”, “read”, “update”, “delete”, “list”, “sudo” ]
}

This doesn’t change anything for me.

The best I can is following policies:

dev.hcl

path “database/roles” {
capabilities = [“list”]
}

path “database/creds/each devxx-reader” {
capabilities = [“read”]
}

path “database/creds/each devxx-operator” {
capabilities = [“read”]
}

ops.hcl

path “database/roles” {
capabilities = [“list”]
}

path “database/creds/each-reader” {
capabilities = [“read”]
}

path “database/creds/each-prod-operator” {
capabilities = [“read”]
}

support.hcl

path “database/roles” {
capabilities = [“list”]
}

path “database/creds/each-reader” {
capabilities = [“read”]
}

The last problem is this capability:

path “database/roles” {
capabilities = [“list”]
}

It’s allow user to list absolutly all roles, but I think is not very user-frendly to be able to list prod01-operator without the permissions to read his credentials :crazy_face:

EDIT: I have enhanced policy definition by using wildcard with role permission as prefix like this

path “databases/creds/reader-prod*” {
capabilities = [“list”, “read”]
}

path “databases/creds/reader-dev*” {
capabilities = [“list”, “read”]
}

path “databases/creds/operator-prod*” {
capabilities = [“list”, “read”]
}

path “databases/creds/operator-dev*” {
capabilities = [“list”, “read”]
}