Introduction
How to create a policy such that the user assigned the policy is an administrator of a particular namespace as well as child namespaces. The policy, as well as the commands required to set this up can be confusing as working with namespaces adds complexity.
Procedure
Before getting into the complexities of the policies and commands, please review some documentation to familiarize yourself with some topics:
Root Namespace Example
The first approach to take is creating a policy in the root
namespace that will grant the user administrator access to a particular namespace, in our case named foo
. Additionally, this policy allows the user to administrate namespaces that are children to the foo
namespace, down one level. This policy must be assigned to a token created in the root
namespace.
$ vault policy write foo-admin - <<EOF
# Manage namespaces
path "foo/sys/namespaces/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "foo/+/sys/namespaces/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Manage policies
path "foo/sys/policies/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "foo/+/sys/policies/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List policies
path "foo/sys/policies/acl" {
capabilities = ["list"]
}
path "foo/+/sys/policies/acl" {
capabilities = ["list"]
}
# Enable and manage secrets engines
path "foo/sys/mounts/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "foo/+/sys/mounts/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# List available secrets engines
path "foo/sys/mounts" {
capabilities = ["read"]
}
path "foo/+/sys/mounts" {
capabilities = ["read"]
}
EOF
In the above policy, there are two versions of each policy path, one with a wildcard (+
) and one without. The path without a wildcard allows permission directly in the foo
namespace. While the path with the wildcard allows permission in any namespace that is a child of foo
. This is because the wildcard (+
) character can be used to denote any number of characters bounded within a single path segment. In this case, the path segment is a child namespace of foo
.
This pattern can be repeated any number of times. For example, if wanting to update the policy to administer two levels of nested namespaces, rather than just one, update the policy to include another path with the syntax +/+
. This will denote that the user has permissions to all namespaces two levels deep. Example below:
path "foo/sys/mounts" {
capabilities = ["read"]
}
path "foo/+/sys/mounts" {
capabilities = ["read"]
}
path "foo/+/+/sys/mounts" {
capabilities = ["read"]
}
After creating this policy, you would then be able to create a token in the root
namespace and assign it the foo-admin
policy. The resultant token is then an administrator of the foo
namespace. The example below demonstrates creating the token with the appropriate policy, creating a child bar
namespace and listing the capabilities to prove that we can administrate the child namespace.
$ FOO_ADMIN_TOKEN=$(vault token create -format=json -policy=foo-admin | jq -r '.auth.client_token')
$ vault login $FOO_ADMIN_TOKEN
$ vault namespace create -namespace=foo bar
Key Value
--- -----
id glTCa
path foo/bar/
$ vault token capabilities foo/bar/sys/namespaces/
create, delete, list, read, sudo, update
Foo Namespace Example
The second approach is setting up a policy in the foo
namespace, rather than in the root
namespace. Some of the benefits of this approach are that the user with the foo-admin
policy can actually alter the foo-admin
policy themselves, something that's not possible with a policy created in the root
namespace. Additionally, it can be a "cleaner" approach as the policies related to the namespace are held within the namespace, rather than in the root
namespace.
Many of the below commands we will be leveraging the -namespace
option, which allows choosing which namespace the command is executed against.
vault policy write -namespace=foo foo-admin - << EOF
# Manage namespaces
path "sys/namespaces/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "+/sys/namespaces/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Manage policies
path "sys/policies/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "+/sys/policies/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# List policies
path "sys/policies/acl" {
capabilities = ["list"]
}
path "+/sys/policies/acl" {
capabilities = ["list"]
}
# Enable and manage secrets engines
path "sys/mounts/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "+/sys/mounts/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# List available secrets engines
path "sys/mounts" {
capabilities = [ "read" ]
}
path "+/sys/mounts" {
capabilities = [ "read" ]
}
EOF
Note that this policy is created in the foo
namespace via the -namespace=foo
option. This means that it will only be returned when running a vault policy
list -namespace=foo
. It won't be returned when listing policies in the root
namespace via vault policy
list
. Also note how the policy paths change. Since this policy exists in the foo
namespace, there's no need to include foo
in the policy path. The policy path is thus relative to the namespace which it was created in.
To repeat the previous example for this particular use case, a few changes need to be made in how to create the token. There's a need to specify the -namespace
option when creating the token, as well as specifying it when logging in. An example is below:
$ FOO_ADMIN_TOKEN=$(vault token create -format=json -policy=foo-admin -namespace=foo | jq -r '.auth.client_token') $ vault login -namespace=foo $FOO_ADMIN_TOKEN
$vault namespace create -namespace=foo bar Key Value --- ----- id asjOj path foo/bar/
$ vault token capabilities -namespace=foo bar/sys/namespaces/ create, delete, list, read, sudo, update
For the token creation examples, auth methods can also be enabled and mounted within a namespace that can be configured to assign policies as desired.
Additional Information
- Vault Policy Concepts: https://developer.hashicorp.com/vault/docs/concepts/policies