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