1---
2layout: "guides"
3page_title: "ACL Policy Path Templating - Guides"
4sidebar_current: "guides-identity-policy-templating"
5description: |-
6  As of 0.11, ACL policies support templating to allow non-static policy paths.
7---
8
9# ACL Policy Path Templating
10
11Vault operates on a **secure by default** standard, and as such, an empty policy
12grants **no permissions** in the system. Therefore, policies must be created to
13govern the behavior of clients and instrument Role-Based Access Control (RBAC)
14by specifying access privileges (_authorization_).
15
16Since everything in Vault is path based, policy authors must be aware of
17all existing paths as well as paths to be created.
18
19The [Policies](/guides/identity/policies.html) guide walks you through the
20creation of ACL policies in Vault.
21
22-> This guide highlights the use of ACL templating which was introduced in
23**Vault 0.11**.
24
25## Reference Material
26
27- [Templated Policies](/docs/concepts/policies.html#templated-policies)
28- [Policy API](/api/system/policy.html)
29- [Identity: Entities and Groups](/guides/identity/identity.html)
30- [Streamline Secrets Management with Vault Agent and Vault 0.11](https://youtu.be/zDnIqSB4tyA?t=24m37s)
31
32~> **NOTE:** An [interactive
33tutorial](https://www.katacoda.com/hashicorp/scenarios/vault-policy-templating)
34is also available if you do not have a Vault environment to perform the steps
35described in this guide.
36
37## Estimated Time to Complete
38
3910 minutes
40
41## Challenge
42
43The only way to specify non-static paths in ACL policies was to use globs (`*`)
44at the end of paths.
45
46```hcl
47path "transit/keys/*" {
48  capabilities = [ "read" ]
49}
50
51path "secret/webapp_*" {
52  capabilities = [ "create", "read", "update", "delete", "list" ]
53}
54```
55
56This makes many management and delegation tasks challenging. For example,
57allowing a user to change their own password by invoking the
58`auth/userpass/users/<user_name>/password` endpoint can require either a policy
59for _every user_ or requires the use of Sentinel which is a part of [Vault
60Enterprise](/docs/enterprise/sentinel/index.html).
61
62## Solution
63
64As of **Vault 0.11**, ACL templating capability is available to allow a subset
65of user information to be used within ACL policy paths.
66
67-> **NOTE:** This feature leverages [Vault
68Identities](/docs/secrets/identity/index.html) to inject values into ACL policy
69paths.
70
71## Prerequisites
72
73To perform the tasks described in this guide, you need to have an environment
74with **Vault 0.11** or later. Refer to the [Getting
75Started](/intro/getting-started/install.html) guide to install Vault.
76
77Alternately, you can use the [Vault
78Playground](https://www.katacoda.com/hashicorp/scenarios/vault-playground)
79environment.
80
81~> This guide assumes that you know how to create ACL policies. If you don't,
82go through the interactive [Policy
83tutorial](https://www.katacoda.com/hashicorp/scenarios/vault-policies) or
84[Policies](/guides/identity/policies.html) guide first.
85
86### Policy requirements
87
88Since this guide demonstrates the creation of an `admin` policy, log in with the
89`root` token if possible. Otherwise, refer to the policy requirement in the
90[Policies](/guides/identity/policies.html#policy-requirements) guide.
91
92
93## Steps
94
95Assume that the following policy requirements were given:
96
97- Each _user_ can perform all operations on their allocated key/value secret
98 path (`user-kv/data/<user_name>`)
99
100- The education _group_ has a dedicated key/value secret store for each region where
101 all operations can be performed by the group members
102 (`group-kv/data/education/<region>`)
103
104- The _group_ members can update the group information such as metadata about
105 the group (`identity/group/id/<group_id>`)
106
107In this guide, you are going to perform the following steps:
108
1091. [Write templated ACL policies](#step1)
1101. [Deploy your policy](#step2)
1111. [Setup an entity and a group](#step3)
1121. [Test the ACL templating](#step4)
113
114### <a name="step1"></a>Step 1: Write templated ACL policies
115
116Policy authors can pass in a policy path containing double curly braces as
117templating delimiters: `{{<parameter>}}`.
118
119
120#### Available Templating Parameters
121
122|                                    Name                                |                                    Description                               |
123| :--------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
124| `identity.entity.id`                                                   | The entity's ID                                                              |
125| `identity.entity.name`                                                 | The entity's name                                                            |
126| `identity.entity.metadata.<<metadata key>>`                            | Metadata associated with the entity for the given key                        |
127| `identity.entity.aliases.<<mount accessor>>.id`                        | Entity alias ID for the given mount                                          |
128| `identity.entity.aliases.<<mount accessor>>.name`                      | Entity alias name for the given mount                                        |
129| `identity.entity.aliases.<<mount accessor>>.metadata.<<metadata key>>` | Metadata associated with the alias for the given mount and metadata key      |
130| `identity.groups.ids.<<group id>>.name`                                | The group name for the given group ID                                        |
131| `identity.groups.names.<<group name>>.id`                              | The group ID for the given group name                                        |
132| `identity.groups.ids.<<group id>>.metadata.<<metadata key>>`           | Metadata associated with the group for the given key                         |
133| `identity.groups.names.<<group name>>.metadata.<<metadata key>>`       | Metadata associated with the group for the given key                         |
134
135
136-> **NOTE:** Identity groups are not directly attached to a token and an entity
137can be associated with multiple groups. Therefore, in order to reference a
138group, the **group ID** or **group name** must be provided (e.g.
139`identity.groups.ids.59f001d5-dd49-6d63-51e4-357c1e7a4d44.name`).
140
141Example:
142
143This policy allows users to change their own password given that the username
144and password are defined in the `userpass` auth method. The mount accessor
145value (`auth_userpass_6671d643` in this example) can be read from the `sys/auth` endpoint.
146
147```hcl
148path "auth/userpass/users/{{identity.entity.aliases.auth_userpass_6671d643.name}}" {
149  capabilities = [ "update" ]
150  allowed_parameters = {
151    "password" = []
152  }
153}
154```
155
156#### Write the following policies:
157
158User template (`user-tmpl.hcl`)
159
160```hcl
161# Grant permissions on user specific path
162path "user-kv/data/{{identity.entity.name}}/*" {
163	capabilities = [ "create", "update", "read", "delete", "list" ]
164}
165
166# For Web UI usage
167path "user-kv/metadata" {
168  capabilities = ["list"]
169}
170```
171
172Group template (`group-tmpl.hcl`)
173
174```hcl
175# Grant permissions on the group specific path
176# The region is specified in the group metadata
177path "group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*" {
178	capabilities = [ "create", "update", "read", "delete", "list" ]
179}
180
181# Group member can update the group information
182path "identity/group/id/{{identity.groups.names.education.id}}" {
183  capabilities = [ "update", "read" ]
184}
185
186# For Web UI usage
187path "group-kv/metadata" {
188  capabilities = ["list"]
189}
190
191path "identity/group/id" {
192  capabilities = [ "list" ]
193}
194```
195
196
197### <a name="step2"></a>Step 2: Deploy your policy
198
199- [CLI command](#step2-cli)
200- [API call using cURL](#step2-api)
201- [Web UI](#step2-ui)
202
203#### <a name="step2-cli"></a>CLI command
204
205```shell
206# Create the user-tmpl policy
207$ vault policy write user-tmpl user-tmpl.hcl
208
209# Create the group-tmpl policy
210$ vault policy write group-tmpl group-tmpl.hcl
211```
212
213
214#### <a name="step2-api"></a>API call using cURL
215
216To create a policy, use the `/sys/policies/acl` endpoint:
217
218```sh
219$ curl --header "X-Vault-Token: <TOKEN>" \
220       --request PUT \
221       --data <PAYLOAD> \
222       <VAULT_ADDRESS>/v1/sys/policies/acl/<POLICY_NAME>
223```
224
225Where `<TOKEN>` is your valid token, and `<PAYLOAD>` includes the policy name and
226stringified policy.
227
228Example:
229
230```shell
231# API request payload for user-tmpl
232$ tee payload_user.json <<EOF
233{
234  "policy": "path "user-kv/data/{{identity.entity.name}}/*" {\n capabilities = [ "create", "update", "read", "delete", "list" ]\n } ..."
235}
236EOF
237
238# Create user-tmpl policy
239$ curl --header "X-Vault-Token: ..." \
240       --request PUT
241       --data @payload_user.json \
242       http://127.0.0.1:8200/v1/sys/policies/acl/user-tmpl
243
244# API request payload for group-tmpl
245$ tee payload_group.json <<EOF
246{
247   "policy": "path "group-kv/data/{{identity.group.id}}/*" {\n capabilities = [ "create", "update", "read", "delete", "list" ]\n }"
248}
249EOF
250
251# Create group-tmpl policy
252$ curl --header "X-Vault-Token: ..." \
253       --request PUT
254       --data @payload_group.json \
255       http://127.0.0.1:8200/v1/sys/policies/acl/group-tmpl
256```
257
258#### <a name="step2-ui"></a>Web UI
259
260Open a web browser and launch the Vault UI (e.g. http://127.0.0.1:8200/ui) and
261then login.
262
2631. Click the **Policies** tab, and then select **Create ACL policy**.
264
2651. Toggle **Upload file**, and click **Choose a file** to select the
266   `user-tmpl.hcl` file you wrote at [Step 1](#step1).
267
268    ![Create Policy](/img/vault-ctrl-grp-2.png)
269
270    This loads the policy and sets the **Name** to `user-tmpl`.
271
2721. Click the **Create Policy** button.
273
2741. Repeat the steps to create the `group-tmpl` policy.
275
276
277### <a name="step3"></a>Step 3: Setup an entity and a group
278
279Let's create an entity, **`bob_smith`** with a user **`bob`** as its entity
280alias. Also, create a group, **`education`** and add the **`bob_smith`** entity
281as its group member.
282
283![Entity & Group](/img/vault-acl-templating.png)
284
285-> This step only demonstrates CLI commands and Web UI to create
286entities and groups. Refer to the [Identity - Entities and
287Groups](/guides/identity/identity.html) guide if you need the full details.
288
289- [CLI command](#step3-cli)
290- [Web UI](#step3-ui)
291
292#### <a name="step3-cli"></a>CLI command
293
294The following command uses [`jq`](https://stedolan.github.io/jq/download/) tool
295to parse JSON output.
296
297```shell
298# Enable userpass
299$ vault auth enable userpass
300
301# Create a user, bob
302$ vault write auth/userpass/users/bob password="training"
303
304# Retrieve the userpass mount accessor and save it in a file named, accessor.txt
305$ vault auth list -format=json | jq -r '.["userpass/"].accessor' > accessor.txt
306
307# Create bob_smith entity and save the identity ID in the entity_id.txt
308$ vault write -format=json identity/entity name="bob_smith" policies="user-tmpl" \
309        | jq -r ".data.id" > entity_id.txt
310
311# Add an entity alias for the bob_smith entity
312$ vault write identity/entity-alias name="bob" \
313       canonical_id=$(cat entity_id.txt) \
314       mount_accessor=$(cat accessor.txt)
315
316# Finally, create education group and add bob_smith entity as a member
317# Save the generated group ID in the group_id.txt file
318$ vault write -format=json identity/group name="education" \
319      policies="group-tmpl" \
320      metadata=region="us-west" \
321      member_entity_ids=$(cat entity_id.txt)  \
322      | jq -r ".data.id" > group_id.txt
323```
324
325#### <a name="step3-ui"></a>Web UI
326
3271. Click the **Access** tab, and select **Enable new method**.
328
3291. Select **Username & Password** from the **Type** drop-down menu.
330
3311. Click **Enable Method**.
332
3331. Click the Vault CLI shell icon (**`>_`**) to open a command shell. Enter the
334following command to create a new user, **`bob`**.
335
336    ```plaintext
337    $ vault write auth/userpass/users/bob password="training"
338    ```
339    ![Create Policy](/img/vault-ctrl-grp-3.png)
340
3411. Click the icon (**`>_`**) again to hide the shell.
342
3431. From the **Access** tab, select **Entities** and then **Create entity**.
344
3451. Enter **`bob_smith`** in the **Name** field and enter **`user-tmpl`** in the
346**Policies** filed.
347
3481. Click **Create**.
349
3501. Select **Add alias**. Enter **`bob`** in the **Name** field and select
351**`userpass/ (userpass)`** from the **Auth Backend** drop-down list.
352
3531. Select the **`bob_smith`** entity and copy its **ID** displayed under the
354**Details** tab.
355
3561. Click **Groups** from the left navigation, and select **Create group**.
357
3581. Enter **`education`** in the **Name**, and enter **`group-tmpl`** in the
359**Policies** fields. Under **Metadata**, enter **`region`** as a key and
360**`us-west`** as the key value. Enter the `bob_smith` entity ID in the **Member
361Entity IDs** field.
362    ![Group](/img/vault-acl-templating-2.png)
363
3641. Click **Create**.
365
366
367### <a name="step4"></a>Step 4: Test the ACL templating
368
369- [CLI command](#step4-cli)
370- [API call using cURL](#step4-api)
371- [Web UI](#step4-ui)
372
373#### <a name="step4-cli"></a>CLI Command
374
3751. Enable key/value v2 secrets engine at `user-kv` and `group-kv` paths.
376
377    ```plaintext
378    $ vault secrets enable -path=user-kv kv-v2
379
380    $ vault secrets enable -path=group-kv kv-v2
381    ```
382
3831. Log in as **`bob`**.
384
385    ```plaintext
386    $ vault login -method=userpass username="bob" password="training"
387
388    Key                    Value
389    ---                    -----
390    token                  5f2b2594-f0b4-0a7b-6f51-767345091dcc
391    token_accessor         78b652dd-4320-f18f-b882-0732b7ae9ac9
392    token_duration         768h
393    token_renewable        true
394    token_policies         ["default"]
395    identity_policies      ["group-tmpl" "user-tmpl"]
396    policies               ["default" "group-tmpl" "user-tmpl"]
397    token_meta_username    bob
398    ```
399
4001. Remember that `bob` is a member of the `bob_smith` entity; therefore, the
401"`user-kv/data/{{identity.entity.name}}/*`" expression in the `user-tmpl` policy
402translates to "**`user-kv/data/bob_smith/*`**". Let's test!
403
404    ```plaintext
405    $ vault kv put user-kv/bob_smith/apikey webapp="12344567890"
406    Key              Value
407    ---              -----
408    created_time     2018-08-30T18:28:30.845345444Z
409    deletion_time    n/a
410    destroyed        false
411    version          1
412    ```
413
4141. The region was set to `us-west` for the `education` group that the
415`bob_smith` belongs to. Therefore, the
416"`group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*`"
417expression in the `group-tmpl` policy translates to
418"**`group-kv/data/education/us-west/*`**". Let's verify.
419
420    ```plaintext
421    $ vault kv put group-kv/education/us-west/db_cred password="ABCDEFGHIJKLMN"
422    Key              Value
423    ---              -----
424    created_time     2018-08-30T18:29:02.023749491Z
425    deletion_time    n/a
426    destroyed        false
427    version          1
428    ```
429
4301. Verify that you can update the group information. The `group-tmpl` policy
431permits "update" and "read" on the
432"`identity/group/id/{{identity.groups.names.education.id}}`" path. In [Step
4332](#step2), you saved the `education` group ID in the `group_id.txt` file.
434
435    ```plaintext
436    $ vault write identity/group/id/$(cat group_id.txt) \
437            policies="group-tmpl" \
438            metadata=region="us-west" \
439            metadata=contact_email="james@example.com"
440    ```
441
442    Read the group information to verify that the data has been updated.
443
444    ```plaintext
445    $ vault read identity/group/id/$(cat group_id.txt)
446
447    Key                  Value
448    ---                  -----
449    alias                map[]
450    creation_time        2018-08-29T20:38:49.383960564Z
451    id                   d6ee454e-915a-4bef-9e43-4ffd7762cd4c
452    last_update_time     2018-08-29T22:52:42.005544616Z
453    member_entity_ids    [1a272450-d147-c3fd-63ae-f16b65b5ee02]
454    member_group_ids     <nil>
455    metadata             map[contact_email:james@example.com region:us-west]
456    modify_index         3
457    name                 education
458    parent_group_ids     <nil>
459    policies             [group-tmpl]
460    type                 internal
461    ```
462
463#### <a name="step4-api"></a>API call using cURL
464
4651. Enable key/value v2 secrets engine at `user-kv` and `group-kv` paths.
466
467    ```plaintext
468    $ tee payload.json <<EOF
469    {
470      "type": "kv",
471      "options": {
472        "version": "2"
473      }
474    }
475    EOF
476
477    $ curl --header "X-Vault-Token: ..." \
478           --request POST \
479           --data @payload.json \
480           https://127.0.0.1:8200/v1/sys/mounts/user-kv
481
482    $ curl --header "X-Vault-Token: ..." \
483           --request POST \
484           --data @payload.json \
485           https://127.0.0.1:8200/v1/sys/mounts/group-kv
486    ```
487
4881. Log in as **`bob`**.
489
490    ```plaintext
491    $ curl --request POST \
492           --data '{"password": "training"}' \
493           http://127.0.0.1:8200/v1/auth/userpass/login/bob | jq
494    ```
495
496    Copy the generated **`client_token`** value for `bob`.
497
4981. Remember that `bob` is a member of the `bob_smith` entity; therefore, the
499"`user-kv/data/{{identity.entity.name}}/*`" expression in the `user-tmpl` policy
500translates to "**`user-kv/data/bob_smith/*`**". Let's test!
501
502    ```plaintext
503    $ curl --header "X-Vault-Token: <bob_client_token>" \
504           --request POST \
505           --data '{ "data": {"webapp": "12344567890"} }' \
506           http://127.0.0.1:8200/v1/user-kv/data/bob_smith/apikey
507    ```
508
5091. The region was set to `us-west` for the `education` group that the
510`bob_smith` belongs to. Therefore, the
511"`group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*`"
512expression in the `group-tmpl` policy translates to
513"**`group-kv/data/education/us-west/*`**". Let's verify.
514
515    ```plaintext
516    $ curl --header "X-Vault-Token: <bob_client_token>" \
517           --request POST \
518           --data '{ "data": {"password": "ABCDEFGHIJKLMN"} }' \
519           http://127.0.0.1:8200/v1/group-kv/data/education/us-west/db_cred
520    ```
521
5221. Verify that you can update the group information. The `group-tmpl` policy
523permits "update" and "read" on the
524"`identity/group/id/{{identity.groups.names.education.id}}`" path.
525
526    ```plaintext
527    $ tee group_info.json <<EOF
528    {
529      "metadata": {
530        "region": "us-west",
531        "contact_email": "james@example.com"
532      },
533      "policies": "group-tmpl"
534    }
535    EOF
536
537    $ curl --header "X-Vault-Token: <bob_client_token>" \
538           --request POST \
539           --data @group_info.json \
540           http://127.0.0.1:8200/v1/identity/group/id/<education_group_id>
541    ```
542
543    Where the group ID is the ID returned in [Step 2](#step2). (NOTE: If you performed
544    Step 2 using the CLI commands, the group ID is stored in the `group_id.txt`
545    file. If you performed the tasks via Web UI, copy the `education` group ID
546    from UI.)
547
548    Read the group information to verify that the data has been updated.
549
550    ```plaintext
551    $ curl --header "X-Vault-Token: <bob_client_token>" \
552           http://127.0.0.1:8200/v1/identity/group/id/<education_group_id>
553    ```
554
555
556#### <a name="step4-ui"></a>Web UI
557
5581. In **Secrets** tab, select **Enable new engine**.
559
5601. Select the radio-button for **KV**, and then click **Next**.
561
5621. Enter **`user-kv`** in the path field, and then select **2** for KV
563version.
564
5651. Click **Enable Engine**.
566
5671. Return to **Secrets** and then select **Enable new engine** again.
568
5691. Select the radio-button for **KV**, and then click **Next**.
570
5711. Enter **`group-kv`** in the path field, and then select **2** for KV
572version.
573
5741. Click **Enable Engine**.
575
5761. Now, sign out as the current user so that you can log in as `bob`. ![Sign
577off](/img/vault-acl-templating-3.png)
578
5791. In the Vault sign in page, select **Username** and then enter **`bob`** in
580the **Username** field, and **`training`** in the **Password** field.
581
5821. Click **Sign in**.
583
5841. Remember that `bob` is a member of the `bob_smith` entity; therefore, the
585"`user-kv/data/{{identity.entity.name}}/*`" expression in the `user-tmpl` policy
586translates to "**`user-kv/data/bob_smith/*`**". Select **`user-kv`** secrets
587engine, and then select **Create secret**.
588
5891. Enter **`bob_smith/apikey`** in the **PATH FOR THIS SECRET** field,
590**`webapp`** in the key field, and **`12344567890`** in its value field.
591
5921. Click **Save**. You should be able to perform this successfully.
593
5941. The region was set to `us-west` for the `education` group that the
595`bob_smith` belongs to. Therefore, the
596"`group-kv/data/education/{{identity.groups.names.education.metadata.region}}/*`"
597expression in the `group-tmpl` policy translates to
598"**`group-kv/data/education/us-west/*`**".  From the **Secrets** tab, select
599**`group-kv`** secrets engine, and then select **Create secret**.
600
6011. Enter **`education/us-west/db_cred`** in the **PATH FOR THIS SECRET** field.
602Enter **`password`** in the key field, and **`ABCDEFGHIJKLMN`** in its value
603field.
604
6051. Click **Save**. You should be able to perform this successfully.
606
6071. To verify that you can update the group information which is allowed by the
608"`identity/group/id/{{identity.groups.names.education.id}}`" expression in the
609`group-tmpl` policy, select the **Access** tab.
610
6111. Select **Groups**, and then **`education`**.
612
6131. Select **Edit group**. Add a new metadata where the key is
614**`contact_email`** and its value is **`james@example.com`**.
615
6161. Click **Save**. The group metadata should be successfully updated.
617
618
619## Next steps
620
621To learn about Sentinel policies to implement finer-grained policies, refer to
622the [Sentinel Policies](/guides/identity/sentinel.html) guide.
623