1--- 2layout: "guides" 3page_title: "Control Groups - Guides" 4sidebar_title: "Control Groups" 5sidebar_current: "guides-identity-control-groups" 6description: |- 7 Vault Enterprise has a support for Control Group Authorization which adds 8 additional authorization factors to be required before satisfying a request. 9--- 10 11# Control Groups 12 13~> **Enterprise Only:** Control Groups is a part of _Vault Enterprise Premium_. 14 15Control Groups add additional authorization factors to be required before 16processing requests to increase the governance, accountability, and security of 17your secrets. When a control group is required for a request, the requesting 18client receives the [wrapping token](/docs/concepts/response-wrapping.html) in 19return. Only when all authorizations are satisfied, the wrapping token can be 20used to unwrap the requested secrets. 21 22 23## Reference Material 24 25- [Vault Enterprise Control Group Support](/docs/enterprise/control-groups/index.html) 26- [Policies](http://localhost:4567/docs/concepts/policies.html) 27- [Identity Groups](/docs/secrets/identity/index.html) 28- [Control Group API](/api/system/control-group.html) 29- [Sentinel Policies](/docs/enterprise/sentinel/index.html) 30 31## Estimated Time to Complete 32 3310 minutes 34 35 36## Personas 37 38The end-to-end scenario described in this guide involves three personas: 39 40- **`admin`** with privileged permissions to create policies and identities 41- **processor** with permission to approve secret access 42- **controller** with limited permission to access secrets 43 44 45## Challenge 46 47In order to operate in EU, a company must abide by the [General Data Protection 48Regulation (GDPR)](https://www.eugdpr.org/) as of May 2018. The regulation 49enforces two or more controllers jointly determine the purposes and means of 50processing ([Chapter 4: Controller and 51Processor](https://gdpr-info.eu/chapter-4/)). 52 53Consider the following scenarios: 54 55- Anytime an authorized user requests to read data at "`EU_GDPR_data/orders/*`", 56at least two people from the _Security_ group must approve to ensure that the 57user has a valid business reason for requesting the data. 58 59- Anytime a database configuration is updated, it requires that one person from 60the _DBA_ and one person from _Security_ group must approve it. 61 62 63## Solution 64 65Use ***Control Groups*** in your policies to implement dual controller 66authorization required. 67 68 69## Prerequisites 70 71To perform the tasks described in this guide, you need to have a ***Vault 72Enterprise*** environment. 73 74This guide assumes that you have some hands-on experience with [ACL 75policies](/docs/concepts/policies.html) as well as 76[Identities](/docs/secrets/identity/index.html). If you are not familiar, 77go through the following guides first: 78 79- [Policies](/guides/identity/policies.html) 80- [Identity - Entities & Groups](/guides/identity/identity.html) 81 82### Policy requirements 83 84Since this guide demonstrates the creation of policies, log in with a highly 85privileged token such as **`root`**. 86Otherwise, required permissions to perform 87the steps in this guide are: 88 89```shell 90# Create and manage ACL policies via CLI 91path "sys/policy/*" 92{ 93 capabilities = ["create", "read", "update", "delete", "list", "sudo"] 94} 95 96# Create and manage ACL policies via Web UI 97path "sys/policies/acl/*" 98{ 99 capabilities = ["create", "read", "update", "delete", "list", "sudo"] 100} 101 102# To enable secret engines 103path "sys/mounts/*" { 104 capabilities = [ "create", "read", "update", "delete" ] 105} 106 107# Setting up test data 108path "EU_GDPR_data/*" 109{ 110 capabilities = ["create", "read", "update", "delete", "list"] 111} 112 113# Manage userpass auth method 114path "auth/userpass/*" 115{ 116 capabilities = ["create", "read", "update", "delete", "list"] 117} 118 119# List, create, update, and delete auth methods 120path "sys/auth/*" 121{ 122 capabilities = ["create", "read", "update", "delete"] 123} 124 125# Create and manage entities and groups 126path "identity/*" { 127 capabilities = [ "create", "read", "update", "delete", "list" ] 128} 129``` 130 131 132## Steps 133 134The scenario in this guide is that a user, **`Bob Smith`** has 135_read-only_ permission on the "**`EU_GDPR_data/orders/*`**" path; however, 136someone in the **`acct_manager`** group must approve it before he can actually 137read the data. 138 139As a member of the **`acct_manager`** group, **`Ellen Wright`** can authorize 140Bob's request. 141 142![Scenario](/img/vault-ctrl-grp-1.png) 143 144You are going to perform the following: 145 1461. [Implement a control group](#step1) 1471. [Deploy the policies](#step2) 1481. [Setup entities and a group](#step3) 1491. [Verification](#step4) 1501. [ACL Policies vs. Sentinel Policies](#step5) 151 152 153-> Step 1, 2 and 3 are the tasks need to be performed by administrators or 154operators who have the privileges to create policies and configure entities and 155groups. 156 157 158### <a name="step1"></a>Step 1: Implement a control group 159(**Persona:** admin) 160 1611. Author a policy named, **`read-gdpr-order.hcl`**. 162 163 Bob needs "`read`" permit on "`EU_GDPR_data/orders/*`": 164 165 ```hcl 166 path "EU_GDPR_data/orders/*" { 167 capabilities = [ "read" ] 168 } 169 ``` 170 171 Now, add control group to this policy: 172 173 ```hcl 174 path "EU_GDPR_data/orders/*" { 175 capabilities = [ "read" ] 176 177 control_group = { 178 factor "authorizer" { 179 identity { 180 group_names = [ "acct_manager" ] 181 approvals = 1 182 } 183 } 184 } 185 } 186 ``` 187 188 For the purpose of this guide, the number of **`approvals`** is set to 189 **`1`** to keep it simple and easy to test. Any member of the identity 190 group, **`acct_manager`** can approve the read request. Although this 191 example has only one factor (`authorizer`), you can add as many factor 192 blocks as you need. 193 1941. Now, write another policy for the **`acct_manager`** group named 195**`acct_manager.hcl`**. 196 197 ```hcl 198 # To approve the request 199 path "sys/control-group/authorize" { 200 capabilities = ["create", "update"] 201 } 202 203 # To check control group request status 204 path "sys/control-group/request" { 205 capabilities = ["create", "update"] 206 } 207 ``` 208 209 > **NOTE:** The important thing here is that the authorizer (`acct_manager`) 210 must have `create` and `update` permission on the 211 **`sys/control-group/authorize`** endpoint so that they can approve the request. 212 213 2141. Enable key/value secrets engine at **`EU_GDPR_data`** and write some mock data: 215 216 ```shell 217 # Enable kv-v1 at EU_GDPR_data 218 $ vault secrets enable -path=EU_GDPR_data -version=1 kv 219 220 # Write some mock data 221 $ vault kv put EU_GDPR_data/orders/acct1 order_number="12345678" product_id="987654321" 222 ``` 223 224### <a name="step2"></a>Step 2: Deploy the policies 225(**Persona:** admin) 226 227Deploy the `read-gdpr-order` and `acct_manager` policies that you wrote. 228 229#### CLI command 230 231```shell 232# Create read-gdpr-order policy 233$ vault policy write read-gdpr-order read-gdpr-order.hcl 234 235# Create acct_manager policy 236$ vault policy write acct_manager acct_manager.hcl 237``` 238 239 240#### API call using cURL 241 242```shell 243# Construct API request payload to create read-gdpr-read policy 244$ tee payload-1.json <<EOF 245{ 246 "policy": "path \"EU_GDPR_data/orders/*\" {capabilities = [ \"read\" ]control_group = {factor \"authorizer\" ..." 247} 248EOF 249 250# Create read-gdpr-order policy 251$ curl --header "X-Vault-Token: ..." \ 252 --request PUT \ 253 --data @payload-1.json \ 254 http://127.0.0.1:8200/v1/sys/policies/acl/read-gdpr-order 255 256# Construct API request payload to create acct_manager policy 257$ tee payload-2.json <<EOF 258{ 259 "policy": "path \"sys/control-group/authorize\" {capabilities = [\"create\", \"update\"]} ..." 260} 261EOF 262 263# Create acct_manager policy 264$ curl --header "X-Vault-Token: ..." \ 265 --request PUT \ 266 --data @payload-2.json \ 267 http://127.0.0.1:8200/v1/sys/policies/acl/acct_manager 268``` 269 270#### Web UI 271 272Open a web browser and launch the Vault UI (e.g. http://127.0.0.1:8200/ui) and 273then login. 274 2751. Click the **Policies** tab, and then select **Create ACL policy**. 276 2771. Toggle **Upload file**, and click **Choose a file** to select your **`read-gdpr-order.hcl`** file you authored at [Step 1](#step1). 278 279 ![Create Policy](/img/vault-ctrl-grp-2.png) 280 281 This loads the policy and sets the **Name** to be `read-gdpr-order`. 282 2831. Click **Create Policy** to complete. 284 2851. Repeat the steps to create a policy for **`acct_manager`**. 286 287 288 289### <a name="step3"></a>Step 3: Setup entities and a group 290(**Persona:** admin) 291 292-> This step only demonstrates CLI commands and Web UI to create 293entities and groups. Refer to the [Identity - Entities and 294Groups](/guides/identity/identity.html) guide if you need the full details. 295 296Now you have policies, let's create a user, **`bob`** and an **`acct_manager`** 297group with **`ellen`** as a group member. 298 299> **NOTE:** For the purpose of this guide, use `userpass` auth method to create 300user `bob` and `ellen` so that the scenario can be easily tested. 301 302#### CLI command 303 304The following command uses [`jq`](https://stedolan.github.io/jq/download/) tool 305to parse JSON output. 306 307```shell 308# Enable userpass 309$ vault auth enable userpass 310 311# Create a user, bob 312$ vault write auth/userpass/users/bob password="training" 313 314# Create a user, ellen 315$ vault write auth/userpass/users/ellen password="training" 316 317# Retrieve the userpass mount accessor and save it in a file named, accessor.txt 318$ vault auth list -format=json | jq -r '.["userpass/"].accessor' > accessor.txt 319 320# Create Bob Smith entity and save the identity ID in the entity_id_bob.txt 321$ vault write -format=json identity/entity name="Bob Smith" policies="read-gdpr-order" \ 322 metadata=team="Processor" \ 323 | jq -r ".data.id" > entity_id_bob.txt 324 325# Add an entity alias for the Bob Smith entity 326$ vault write identity/entity-alias name="bob" \ 327 canonical_id=$(cat entity_id_bob.txt) \ 328 mount_accessor=$(cat accessor.txt) 329 330# Create Ellen Wright entity and save the identity ID in the entity_id_ellen.txt 331$ vault write -format=json identity/entity name="Ellen Wright" policies="default" \ 332 metadata=team="Acct Controller" \ 333 | jq -r ".data.id" > entity_id_ellen.txt 334 335# Add an entity alias for the Ellen Wright entity 336$ vault write identity/entity-alias name="ellen" \ 337 canonical_id=$(cat entity_id_ellen.txt) \ 338 mount_accessor=$(cat accessor.txt) 339 340# Finally, create acct_manager group and add Ellen Wright entity as a member 341$ vault write identity/group name="acct_manager" \ 342 policies="acct_manager" \ 343 member_entity_ids=$(cat entity_id_ellen.txt) 344``` 345 346 347#### Web UI 348 3491. Click the **Access** tab, and select **Enable new method**. 350 3511. Select **Username & Password** from the **Type** drop-down menu. 352 3531. Click **Enable Method**. 354 3551. Click the Vault CLI shell icon (**`>_`**) to open a command shell. Enter the 356following command to create a new user, **`bob`**: 357 358 ```plaintext 359 $ vault write auth/userpass/users/bob password="training" 360 ``` 361 ![Create Policy](/img/vault-ctrl-grp-3.png) 362 3631. Enter the following command to create a new user, **`ellen`**: 364 365 ```plaintext 366 $ vault write auth/userpass/users/ellen password="training" 367 ``` 368 3691. Click the icon (**`>_`**) again to hide the shell. 370 3711. From the **Access** tab, select **Entities** and then **Create entity**. 372 3731. Populate the **Name**, **Policies** and **Metadata** fields as shown below. 374 375 ![Create Entity](/img/vault-ctrl-grp-7.png) 376 3771. Click **Create**. 378 3791. Select **Add alias**. Enter **`bob`** in the **Name** field and select 380**`userpass/ (userpass)`** from the **Auth Backend** drop-down list. 381 3821. Return to the **Entities** tab and then **Create entity**. 383 3841. Populate the **Name**, **Policies** and **Metadata** fields as shown below. 385 386 ![Create Entity](/img/vault-ctrl-grp-4.png) 387 3881. Click **Create**. 389 3901. Select **Add alias**. Enter **`ellen`** in the **Name** field and select 391**`userpass/ (userpass)`** from the **Auth Backend** drop-down list. 392 3931. Click **Create**. 394 3951. Select the **`Ellen Wright`** entity and copy its **ID** displayed under the 396**Details** tab. 397 3981. Click **Groups** from the left navigation, and select **Create group**. 399 4001. Enter **`acct_manager`** in the **Name**, and again enter **`acct_manager`** 401in the **Policies** fields. 402 4031. Enter the `Ellen Wright` entity ID in the **Member Entity IDs** field, and 404then click **Create**. 405 406 407### <a name="step4"></a>Step 4: Verification 408(**Persona:** bob and ellen) 409 410Now, let's see how the control group works. 411 412#### CLI Command 413 4141. Log in as **`bob`**. 415 416 ```plaintext 417 $ vault login -method=userpass username="bob" password="training" 418 ``` 419 4201. Request to read "`EU_GDPR_data/orders/acct1`": 421 422 ```plaintext 423 $ vault kv get EU_GDPR_data/orders/acct1 424 425 Key Value 426 --- ----- 427 wrapping_token: 1f1411bc-2f18-551a-5e58-0fe44432e9a5 428 wrapping_accessor: bbb4deef-e06d-9b2a-64a9-56f815c69ee7 429 wrapping_token_ttl: 24h 430 wrapping_token_creation_time: 2018-08-08 09:36:32 -0700 PDT 431 wrapping_token_creation_path: EU_GDPR_data/orders/acct1 432 ``` 433 434 The response includes `wrapping_token` and `wrapping_accessor`. 435 Copy this **`wrapping_accessor`** value. 436 4371. Now, a member of `acct_manager` must approve this request. Log in as 438**`ellen`** who is a member of `acct_manager` group. 439 440 ```plaintext 441 $ vault login -method=userpass username="ellen" password="training" 442 ``` 443 4441. As a user, `ellen`, you can check and authorize bob's request using the 445following commands. 446 447 ```shell 448 # To check the current status 449 $ vault write sys/control-group/request accessor=<wrapping_accessor> 450 451 # To approve the request 452 $ vault write sys/control-group/authorize accessor=<wrapping_accessor> 453 ``` 454 455 **Example:** 456 457 ```shell 458 # Check the current status 459 $ vault write sys/control-group/request accessor=bbb4deef-e06d-9b2a-64a9-56f815c69ee7 460 Key Value 461 --- ----- 462 approved false 463 authorizations <nil> 464 request_entity map[name:Bob Smith id:38700386-723d-3d65-43b7-4fb44d7e6c30] 465 request_path EU_GDPR_data/orders/acct1 466 467 # Approve the request 468 $ vault write sys/control-group/authorize accessor=bbb4deef-e06d-9b2a-64a9-56f815c69ee7 469 Key Value 470 --- ----- 471 approved true 472 ``` 473 474 Now, the `approved` status is `true`. 475 4761. Since the control group requires one approval from a member of `acct_manager` 477group, the condition has been met. Log back in as `bob` and unwrap the secret. 478 479 **Example:** 480 481 ```shell 482 # Log back in as bob - you can use the bob's token: vault login <bob_token> 483 $ vault login -method=userpass username="bob" password="training" 484 485 # Unwrap the secrets by passing the wrapping_token 486 $ vault unwrap 1f1411bc-2f18-551a-5e58-0fe44432e9a5 487 Key Value 488 --- ----- 489 refresh_interval 768h 490 order_number 12345678 491 product_id 987654321 492 ``` 493 494 495#### API call using cURL 496 4971. Log in as **`bob`**. 498 499 ```plaintext 500 $ curl --request POST \ 501 --data '{"password": "training"}' \ 502 http://127.0.0.1:8200/v1/auth/userpass/login/bob | jq 503 ``` 504 505 Copy the generated **`client_token`** value. 506 5071. Request to `EU_GDPR_data/orders/acct1`: 508 509 ```plaintext 510 $ curl --header "X-Vault-Token: <bob_client_token>" \ 511 http://127.0.0.1:8200/v1/EU_GDPR_data/orders/acct1 | jq 512 { 513 ... 514 "wrap_info": { 515 "token": "20a2f2b3-8bea-4e16-980b-82724dcdc38b", 516 "accessor": "9910cb38-600c-29d8-1c39-764a1c89a481", 517 "ttl": 86400, 518 "creation_time": "2018-08-08T10:13:06-07:00", 519 "creation_path": "EU_GDPR_data/orders/acct1" 520 }, 521 ... 522 } 523 ``` 524 525 The response includes **`wrap_info`** instead of the actual data. 526 Copy the **`accessor`** value. 527 5281. Now, a member of `acct_manager` must approve this request. Log in as 529**`ellen`** who is a member of `acct_manager` group. 530 531 ```plaintext 532 $ curl --request POST \ 533 --data '{"password": "training"}' \ 534 http://127.0.0.1:8200/v1/auth/userpass/login/ellen | jq 535 ``` 536 537 Copy the generated **`client_token`** value. 538 5391. As a user, `ellen`, you can check the current status and then authorize bob's 540request. (NOTE: Be sure to replace `<accessor>` with the `accessor` value you 541copied earlier.) 542 543 ```shell 544 # To check the current status using sys/control-group/request endpoint 545 $ curl --header "X-Vault-Token: <ellen_client_token>" \ 546 --request POST \ 547 --data '{"accessor": "<accessor>"}' \ 548 http://127.0.0.1:8200/v1/sys/control-group/request | jq 549 { 550 ... 551 "data": { 552 "approved": false, 553 "authorizations": null, 554 "request_entity": { 555 "id": "38700386-723d-3d65-43b7-4fb44d7e6c30", 556 "name": "Bob Smith" 557 }, 558 "request_path": "EU_GDPR_data/orders/acct1" 559 }, 560 ... 561 } 562 563 # Now, authorize the request using sys/control-group/authorize endpoint 564 $ curl --header "X-Vault-Token: <ellen_client_token>" \ 565 --request POST \ 566 --data '{"accessor": "<accessor>"}' \ 567 http://127.0.0.1:8200/v1/sys/control-group/authorize | jq 568 { 569 ... 570 "data": { 571 "approved": true 572 }, 573 ... 574 } 575 ``` 576 577 Now, the `approved` status is `true`. 578 5791. The `bob` user should be able to unwrap the secrets. 580 581 ```plaintext 582 $ curl --header "X-Vault-Token: <bob_client_token>" \ 583 --request POST \ 584 --data '{"token": "<wrapping_token>"}' \ 585 http://127.0.0.1:8200/v1/sys/wrapping/unwrap | jq 586 { 587 ... 588 "data": { 589 "order_number": "12345678", 590 "product_id": "987654321" 591 }, 592 ... 593 } 594 ``` 595 596#### Web UI 597 598The user, **`ellen`** can approve the data access request via UI. 599 600 6011. Open the Vault sign in page in a web browser (e.g. 602http://127.0.0.1:8200/ui/vault/auth?with=userpass). In the **Userpass** tab, 603enter **`ellen`** in the **Username** field, and **`training`** in the 604**Password** field. 605 6061. Click **Sign in**. 607 6081. Select the **Access** tab, and then **Control Groups**. 609 6101. Enter the **`wrapping_accessor`** value in the **Accessor** field and click 611**Lookup**. ![Control Groups](/img/vault-ctrl-grp-5.png) 612 6131. _Awaiting authorization_ message displays. ![Control 614Groups](/img/vault-ctrl-grp-6.png) 615 6161. Click **Authorize**. The message changes to "_Thanks! You have given 617authorization_." 618 619> Bob needs to request data access via CLI or API. Once the access request was 620approved, use the CLI or API to unwrap the secrets. 621 622 623### <a name="step5"></a>Step 5: ACL Policy vs. Sentinel Policy 624 625Although the [**`read-gdpr-order.hcl`**](#step1) was written as ACL policy, you 626can implement Control Groups in either ACL or Sentinel policies. 627 628Using Sentinel, the same policy may look something like: 629 630```hcl 631import "controlgroup" 632 633control_group = func() { 634 numAuthzs = 0 635 for controlgroup.authorizations as authz { 636 if "acct_manager" in authz.groups.by_name { 637 numAuthzs = numAuthzs + 1 638 } 639 } 640 if numAuthzs >= 1 { 641 return true 642 } 643 return false 644} 645 646main = rule { 647 control_group() 648} 649``` 650 651Deploy this policy as an Endpoint Governing Policy attached to 652"**`EU_GDPR_data/orders/*`**" path. 653 654-> Refer to the [Sentinel 655Properties](/docs/enterprise/sentinel/properties.html#control-group-properties) 656documentation for the list of available properties associated with control 657groups. 658 659 660## Next steps 661 662To protect your secrets, it may become necessary to write finer-grained 663policies to introspect different aspects of incoming requests. If you have not 664already done so, read [Sentinel](https://docs.hashicorp.com/sentinel/) 665documentation to learn more about what you can accomplish writing policies as a 666code. 667