21 KiB
layout | page_title | sidebar_current | description |
---|---|---|---|
guides | ACL Policy Path Templating - Guides | guides-identity-policy-templating | As of 0.11, ACL policies support templating to allow non-static policy paths. |
ACL Policy Path Templating
Vault operates on a secure by default standard, and as such, an empty policy grants no permissions in the system. Therefore, policies must be created to govern the behavior of clients and instrument Role-Based Access Control (RBAC) by specifying access privileges (authorization).
Since everything in Vault is path based, policy authors must be aware of all existing paths as well as paths to be created.
The Policies guide walks you through the creation of ACL policies in Vault.
-> This guide highlights the use of ACL templating which was introduced in Vault 0.11.
Reference Material
- Templated Policies
- Policy API
- Identity: Entities and Groups
- Streamline Secrets Management with Vault Agent and Vault 0.11
~> NOTE: An interactive tutorial is also available if you do not have a Vault environment to perform the steps described in this guide.
Estimated Time to Complete
10 minutes
Challenge
The only way to specify non-static paths in ACL policies was to use globs (*
)
at the end of paths.
path "transit/keys/*" {
capabilities = [ "read" ]
}
path "secret/webapp_*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
This makes many management and delegation tasks challenging. For example,
allowing a user to change their own password by invoking the
auth/userpass/users/<user_name>/password
endpoint can require either a policy
for every user or requires the use of Sentinel which is a part of Vault
Enterprise.
Solution
As of Vault 0.11, ACL templating capability is available to allow a subset of user information to be used within ACL policy paths.
-> NOTE: This feature leverages Vault Identities to inject values into ACL policy paths.
Prerequisites
To perform the tasks described in this guide, you need to have an environment with Vault 0.11 or later. Refer to the Getting Started guide to install Vault.
Alternately, you can use the Vault Playground environment.
~> This guide assumes that you know how to create ACL policies. If you don't, go through the interactive Policy tutorial or Policies guide first.
Policy requirements
Since this guide demonstrates the creation of an admin
policy, log in with the
root
token if possible. Otherwise, refer to the policy requirement in the
Policies guide.
Steps
Assume that the following policy requirements were given:
-
Each user can perform all operations on their allocated key/value secret path (
user-kv/data/<user_name>
) -
The education group has a dedicated key/value secret store for each region where all operations can be performed by the group members (
group-kv/data/education/<region>
) -
The group members can update the group information such as metadata about the group (
identity/group/id/<group_id>
)
In this guide, you are going to perform the following steps:
Step 1: Write templated ACL policies
Policy authors can pass in a policy path containing double curly braces as
templating delimiters: {{<parameter>}}
.
Available Templating Parameters
Name | Description |
---|---|
identity.entity.id |
The entity's ID |
identity.entity.name |
The entity's name |
identity.entity.metadata.<<metadata key>> |
Metadata associated with the entity for the given key |
identity.entity.aliases.<<mount accessor>>.id |
Entity alias ID for the given mount |
identity.entity.aliases.<<mount accessor>>.name |
Entity alias name for the given mount |
identity.entity.aliases.<<mount accessor>>.metadata.<<metadata key>> |
Metadata associated with the alias for the given mount and metadata key |
identity.groups.ids.<<group id>>.name |
The group name for the given group ID |
identity.groups.names.<<group name>>.id |
The group ID for the given group name |
identity.groups.names.<<group id>>.metadata.<<metadata key>> |
Metadata associated with the group for the given key |
identity.groups.names.<<group name>>.metadata.<<metadata key>> |
Metadata associated with the group for the given key |
-> NOTE: Identity groups are not directly attached to a token and an entity
can be associated with multiple groups. Therefore, in order to reference a
group, the group ID or group name must be provided (e.g.
identity.groups.ids.59f001d5-dd49-6d63-51e4-357c1e7a4d44.name
).
Example:
This policy allows users to change their own password given that the username
and password are defined in the userpass
auth method.
path "auth/userpass/users/{{identity.entity.aliases.auth_userpass_6671d643.name}}/password" {
capabilities = [ "update" ]
}
Write the following policies:
User template (user-tmpl.hcl
)
# Grant permissions on user specific path
path "user-kv/data/{{identity.entity.name}}/*" {
capabilities = [ "create", "update", "read", "delete", "list" ]
}
# For Web UI usage
path "user-kv/metadata" {
capabilities = ["list"]
}
Group template (group-tmpl.hcl
)
# Grant permissions on the group specific path
# The region is specified in the group metadata
path "group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*" {
capabilities = [ "create", "update", "read", "delete", "list" ]
}
# Group member can update the group information
path "identity/group/id/{{identity.groups.names.education.id}}" {
capabilities = [ "update", "read" ]
}
# For Web UI usage
path "group-kv/metadata" {
capabilities = ["list"]
}
path "identity/group/id" {
capabilities = [ "list" ]
}
Step 2: Deploy your policy
CLI command
# Create the user-tmpl policy
$ vault policy write user-tmpl user-tmpl.hcl
# Create the group-tmpl policy
$ vault policy write group-tmpl group-tmpl.hcl
API call using cURL
To create a policy, use the /sys/policies/acl
endpoint:
$ curl --header "X-Vault-Token: <TOKEN>" \
--request PUT \
--data <PAYLOAD> \
<VAULT_ADDRESS>/v1/sys/policies/acl/<POLICY_NAME>
Where <TOKEN>
is your valid token, and <PAYLOAD>
includes the policy name and
stringified policy.
Example:
# API request payload for user-tmpl
$ tee payload_user.json <<EOF
{
"policy": "path "user-kv/data/{{identity.entity.name}}/*" {\n capabilities = [ "create", "update", "read", "delete", "list" ]\n } ..."
}
EOF
# Create user-tmpl policy
$ curl --header "X-Vault-Token: ..." \
--request PUT
--data @payload_user.json \
http://127.0.0.1:8200/v1/sys/policies/acl/user-tmpl
# API request payload for group-tmpl
$ tee payload_group.json <<EOF
{
"policy": "path "group-kv/data/{{identity.group.id}}/*" {\n capabilities = [ "create", "update", "read", "delete", "list" ]\n }"
}
EOF
# Create group-tmpl policy
$ curl --header "X-Vault-Token: ..." \
--request PUT
--data @payload_group.json \
http://127.0.0.1:8200/v1/sys/policies/acl/group-tmpl
Web UI
Open a web browser and launch the Vault UI (e.g. http://127.0.0.1:8200/ui) and then login.
-
Click the Policies tab, and then select Create ACL policy.
-
Toggle Upload file, and click Choose a file to select the
user-tmpl.hcl
file you wrote at Step 1.This loads the policy and sets the Name to
user-tmpl
. -
Click the Create Policy button.
-
Repeat the steps to create the
group-tmpl
policy.
Step 3: Setup an entity and a group
Let's create an entity, bob_smith
with a user bob
as its entity
alias. Also, create a group, education
and add the bob_smith
entity
as its group member.
-> This step only demonstrates CLI commands and Web UI to create entities and groups. Refer to the Identity - Entities and Groups guide if you need the full details.
CLI command
The following command uses jq
tool
to parse JSON output.
# Enable userpass
$ vault auth enable userpass
# Create a user, bob
$ vault write auth/userpass/users/bob password="training"
# Retrieve the userpass mount accessor and save it in a file named, accessor.txt
$ vault auth list -format=json | jq -r '.["userpass/"].accessor' > accessor.txt
# Create bob_smith entity and save the identity ID in the entity_id.txt
$ vault write -format=json identity/entity name="bob_smith" policies="user-tmpl" \
| jq -r ".data.id" > entity_id.txt
# Add an entity alias for the bob_smith entity
$ vault write identity/entity-alias name="bob" \
canonical_id=$(cat entity_id.txt) \
mount_accessor=$(cat accessor.txt)
# Finally, create education group and add bob_smith entity as a member
# Save the generated group ID in the group_id.txt file
$ vault write -format=json identity/group name="education" \
policies="group-tmpl" \
metadata=region="us-west" \
member_entity_ids=$(cat entity_id.txt) \
| jq -r ".data.id" > group_id.txt
Web UI
-
Click the Access tab, and select Enable new method.
-
Select Username & Password from the Type drop-down menu.
-
Click Enable Method.
-
Click the Vault CLI shell icon (
>_
) to open a command shell. Enter the following command to create a new user,bob
.$ vault write auth/userpass/users/bob password="training"
-
Click the icon (
>_
) again to hide the shell. -
From the Access tab, select Entities and then Create entity.
-
Enter
bob_smith
in the Name field and enteruser-tmpl
in the Policies filed. -
Click Create.
-
Select Add alias. Enter
bob
in the Name field and selectuserpass/ (userpass)
from the Auth Backend drop-down list. -
Select the
bob_smith
entity and copy its ID displayed under the Details tab. -
Click Groups from the left navigation, and select Create group.
-
Enter
education
in the Name, and entergroup-tmpl
in the Policies fields. Under Metadata, enterregion
as a key andus-west
as the key value. Enter thebob_smith
entity ID in the Member Entity IDs field. -
Click Create.
Step 4: Test the ACL templating
CLI Command
-
Enable key/value v2 secrets engine at
user-kv
andgroup-kv
paths.$ vault secrets enable -path=user-kv kv-v2 $ vault secrets enable -path=group-kv kv-v2
-
Log in as
bob
.$ vault login -method=userpass username="bob" password="training" Key Value --- ----- token 5f2b2594-f0b4-0a7b-6f51-767345091dcc token_accessor 78b652dd-4320-f18f-b882-0732b7ae9ac9 token_duration 768h token_renewable true token_policies ["default"] identity_policies ["group-tmpl" "user-tmpl"] policies ["default" "group-tmpl" "user-tmpl"] token_meta_username bob
-
Remember that
bob
is a member of thebob_smith
entity; therefore, the "user-kv/data/{{identity.entity.name}}/*
" expression in theuser-tmpl
policy translates to "user-kv/data/bob_smith/*
". Let's test!$ vault kv put user-kv/bob_smith/apikey webapp="12344567890" Key Value --- ----- created_time 2018-08-30T18:28:30.845345444Z deletion_time n/a destroyed false version 1
-
The region was set to
us-west
for theeducation
group that thebob_smith
belongs to. Therefore, the "group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*
" expression in thegroup-tmpl
policy translates to "group-kv/data/education/us-west/*
". Let's verify.$ vault kv put group-kv/education/us-west/db_cred password="ABCDEFGHIJKLMN" Key Value --- ----- created_time 2018-08-30T18:29:02.023749491Z deletion_time n/a destroyed false version 1
-
Verify that you can update the group information. The
group-tmpl
policy permits "update" and "read" on the "identity/group/id/{{identity.groups.names.education.id}}
" path. In Step 2, you saved theeducation
group ID in thegroup_id.txt
file.$ vault write identity/group/id/$(cat group_id.txt) \ policies="group-tmpl" \ metadata=region="us-west" \ metadata=contact_email="james@example.com"
Read the group information to verify that the data has been updated.
$ vault read identity/group/id/$(cat group_id.txt) Key Value --- ----- alias map[] creation_time 2018-08-29T20:38:49.383960564Z id d6ee454e-915a-4bef-9e43-4ffd7762cd4c last_update_time 2018-08-29T22:52:42.005544616Z member_entity_ids [1a272450-d147-c3fd-63ae-f16b65b5ee02] member_group_ids <nil> metadata map[contact_email:james@example.com region:us-west] modify_index 3 name education parent_group_ids <nil> policies [group-tmpl] type internal
API call using cURL
-
Enable key/value v2 secrets engine at
user-kv
andgroup-kv
paths.$ tee payload.json <<EOF { "type": "kv", "options": { "version": "2" } } EOF $ curl --header "X-Vault-Token: ..." \ --request POST \ --data @payload.json \ https://127.0.0.1:8200/v1/sys/mounts/user-kv $ curl --header "X-Vault-Token: ..." \ --request POST \ --data @payload.json \ https://127.0.0.1:8200/v1/sys/mounts/group-kv
-
Log in as
bob
.$ curl --request POST \ --data '{"password": "training"}' \ http://127.0.0.1:8200/v1/auth/userpass/login/bob | jq
Copy the generated
client_token
value forbob
. -
Remember that
bob
is a member of thebob_smith
entity; therefore, the "user-kv/data/{{identity.entity.name}}/*
" expression in theuser-tmpl
policy translates to "user-kv/data/bob_smith/*
". Let's test!$ curl --header "X-Vault-Token: <bob_client_token>" \ --request POST \ --data '{ "data": {"webapp": "12344567890"} }' \ http://127.0.0.1:8200/v1/user-kv/data/bob_smith/apikey
-
The region was set to
us-west
for theeducation
group that thebob_smith
belongs to. Therefore, the "group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*
" expression in thegroup-tmpl
policy translates to "group-kv/data/education/us-west/*
". Let's verify.$ curl --header "X-Vault-Token: <bob_client_token>" \ --request POST \ --data '{ "data": {"password": "ABCDEFGHIJKLMN"} }' \ http://127.0.0.1:8200/v1/group-kv/data/education/us-west/db_cred
-
Verify that you can update the group information. The
group-tmpl
policy permits "update" and "read" on the "identity/group/id/{{identity.groups.names.education.id}}
" path.$ tee group_info.json <<EOF { "metadata": { "region": "us-west", "contact_email": "james@example.com" }, "policies": "group-tmpl" } EOF $ curl --header "X-Vault-Token: <bob_client_token>" \ --request POST \ --data @group_info.json \ http://127.0.0.1:8200/v1/identity/group/id/<education_group_id>
Where the group ID is the ID returned in Step 2. (NOTE: If you performed Step 2 using the CLI commands, the group ID is stored in the
group_id.txt
file. If you performed the tasks via Web UI, copy theeducation
group ID from UI.)Read the group information to verify that the data has been updated.
$ curl --header "X-Vault-Token: <bob_client_token>" \ http://127.0.0.1:8200/v1/identity/group/id/<education_group_id>
Web UI
-
In Secrets tab, select Enable new engine.
-
Select the radio-button for KV, and then click Next.
-
Enter
user-kv
in the path field, and then select 2 for KV version. -
Click Enable Engine.
-
Return to Secrets and then select Enable new engine again.
-
Select the radio-button for KV, and then click Next.
-
Enter
group-kv
in the path field, and then select 2 for KV version. -
Click Enable Engine.
-
Now, sign out as the current user so that you can log in as
bob
. -
In the Vault sign in page, select Username and then enter
bob
in the Username field, andtraining
in the Password field. -
Click Sign in.
-
Remember that
bob
is a member of thebob_smith
entity; therefore, the "user-kv/data/{{identity.entity.name}}/*
" expression in theuser-tmpl
policy translates to "user-kv/data/bob_smith/*
". Selectuser-kv
secrets engine, and then select Create secret. -
Enter
bob_smith/apikey
in the PATH FOR THIS SECRET field,webapp
in the key field, and12344567890
in its value field. -
Click Save. You should be able to perform this successfully.
-
The region was set to
us-west
for theeducation
group that thebob_smith
belongs to. Therefore, the "group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*
" expression in thegroup-tmpl
policy translates to "group-kv/data/education/us-west/*
". From the Secrets tab, selectgroup-kv
secrets engine, and then select Create secret. -
Enter
education/us-west/db_cred
in the PATH FOR THIS SECRET field. Enterpassword
in the key field, andABCDEFGHIJKLMN
in its value field. -
Click Save. You should be able to perform this successfully.
-
To verify that you can update the group information which is allowed by the "
identity/group/id/{{identity.groups.names.education.id}}
" expression in thegroup-tmpl
policy, select the Access tab. -
Select Groups, and then
education
. -
Select Edit group. Add a new metadata where the key is
contact_email
and its value isjames@example.com
. -
Click Save. The group metadata should be successfully updated.
Next steps
To learn about Sentinel policies to implement finer-grained policies, refer to the Sentinel Policies guide.