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