1---
2layout: "guides"
3page_title: "Identity: Entities and Groups - Guides"
4sidebar_title: "Identity - Entities & Groups"
5sidebar_current: "guides-identity-identity"
6description: |-
7  This guide demonstrates the commands to create entities, entity aliases, and
8  groups.  For the purpose of the demonstration, userpass auth method will be
9  used.
10---
11
12# Identity - Entities and Groups
13
14Vault supports multiple authentication methods and also allows enabling the same
15type of authentication method on different mount paths. Each Vault client may
16have multiple accounts with various identity providers that are enabled on the
17Vault server.
18
19Vault clients can be mapped as ***entities*** and their corresponding accounts
20with authentication providers can be mapped as ***aliases***. In essence, each
21entity is made up of zero or more aliases. Identity secrets engine internally
22maintains the clients who are recognized by Vault.
23
24## Reference Material
25
26- [Identity Secrets Engine](/docs/secrets/identity/index.html)
27- [Identity Secrets Engine (API)](/api/secret/identity/index.html)
28- [External vs Internal Groups](/docs/secrets/identity/index.html#external-vs-internal-groups)
29
30~> **NOTE:** An [interactive
31tutorial](https://www.katacoda.com/hashicorp/scenarios/vault-identity) is
32also available if you do not have a Vault environment to perform the steps
33described in this guide.
34
35## Estimated Time to Complete
36
3710 minutes
38
39## Personas
40
41The steps described in this guide are typically performed by **operations**
42persona.
43
44
45## Challenge
46
47Bob has accounts in both Github and LDAP.  Both Github and LDAP auth methods are
48enabled on the Vault server that he can authenticate using either one of his
49accounts. Although both accounts belong to Bob, there is no association between
50the two accounts to set some common properties.
51
52## Solution
53
54Create an _entity_ representing Bob, and associate aliases representing each of
55his accounts as the entity member. You can set additional policies and metadata
56on the entity level so that both accounts can inherit.
57
58When Bob authenticates using either one of his accounts, the entity identifier
59will be tied to the authenticated token. When such tokens are put to use, their
60entity identifiers are audit logged, marking a trail of actions performed by
61specific users.
62
63
64## Prerequisites
65
66To perform the tasks described in this guide, you need to have a Vault
67environment.  Refer to the [Getting
68Started](/intro/getting-started/install.html) guide to install Vault. Make sure
69that your Vault server has been [initialized and
70unsealed](/intro/getting-started/deploy.html).
71
72
73### Policy requirements
74
75-> **NOTE:** For the purpose of this guide, you can use the **`root`** token to work
76with Vault. However, it is recommended that root tokens are used for just
77enough initial setup or in emergencies. As a best practice, use tokens with
78an appropriate set of policies based on your role in the organization.
79
80To perform all tasks demonstrated in this guide, your policy must include the
81following permissions:
82
83```shell
84# Configure auth methods
85path "sys/auth" {
86  capabilities = [ "read", "list" ]
87}
88
89# Configure auth methods
90path "sys/auth/*" {
91  capabilities = [ "create", "update", "read", "delete", "list", "sudo" ]
92}
93
94# Manage userpass auth methods
95path "auth/userpass/*" {
96  capabilities = [ "create", "read", "update", "delete" ]
97}
98
99# Manage github auth methods
100path "auth/github/*" {
101  capabilities = [ "create", "read", "update", "delete" ]
102}
103
104# Display the Policies tab in UI
105path "sys/policies" {
106  capabilities = [ "read", "list" ]
107}
108
109# Create and manage ACL policies from UI
110path "sys/policies/acl/*" {
111  capabilities = [ "create", "read", "update", "delete", "list" ]
112}
113
114# Create and manage policies
115path "sys/policy" {
116  capabilities = [ "read", "list" ]
117}
118
119# Create and manage policies
120path "sys/policy/*" {
121  capabilities = [ "create", "read", "update", "delete", "list" ]
122}
123
124# List available secret engines to retrieve accessor ID
125path "sys/mounts" {
126  capabilities = [ "read" ]
127}
128
129# Create and manage entities and groups
130path "identity/*" {
131  capabilities = [ "create", "read", "update", "delete", "list" ]
132}
133```
134
135If you are not familiar with policies, complete the
136[policies](/guides/identity/policies.html) guide.
137
138
139## Steps
140
141In this lab, you are going to learn the API-based commands to create entities,
142entity aliases, and groups.  For the purpose of the training, you are going to
143leverage the userpass auth method.  The challenge exercise walks you through
144creating an external group by mapping a GitHub group to an identity group.
145
1461. [Create an Entity with Alias](#step1)
1472. [Test the Entity](#step2)
1483. [Create an Internal Group](#step3)
1494. [Create an External Group](#step4)
150
151
152
153### <a name="step1"></a>Step 1: Create an Entity with Alias
154
155You are going to create a new entity with base policy assigned.  The entity
156defines two entity aliases with each has a different policy assigned.
157
158**Scenario:**  A user, Bob Smith at ACME Inc. happened to have two sets of
159credentials: `bob` and `bsmith`.  He can authenticate with Vault using either
160one of his accounts.  To manage his accounts and link them to identity `Bob
161Smith` in QA team, you are going to create an entity for Bob.
162
163![Entity Bob Smith](/img/vault-entity-1.png)
164
165-> For the simplicity of this guide, you are going to work with the `userpass`
166auth method.  However, in reality, the user `bob` might be a username exists in
167Active Directory, and `bsmith` might be Bob's username in GitHub.
168
169#### Scenario Policies
170
171**`base.hcl`**
172
173```hcl
174path "secret/training_*" {
175   capabilities = ["create", "read"]
176}
177```
178
179**`test.hcl`**
180
181```hcl
182path "secret/test" {
183   capabilities = [ "create", "read", "update", "delete" ]
184}
185```
186
187**`team-qa.hcl`**
188
189```hcl
190path "secret/team-qa" {
191   capabilities = [ "create", "read", "update", "delete" ]
192}
193```
194
195~> **NOTE:** If you are running [K/V Secrets Engine v2](/api/secret/kv/kv-v2.html)
196at `secret`, set the policies path accordingly: `secret/data/training_*`,
197`secret/data/test`, and `secret/data/team-qa`.
198
199Now, you are going to create `bob` and `bsmith` users with appropriate policies
200attached.
201
202
203
204#### CLI command
205
2061. Create policies: `base`, `test`, and `team-qa`.
207
208    ```shell
209    # Create base policy
210    $ vault policy write base base.hcl
211
212    # Create test policy
213    $ vault policy write test test.hcl
214
215    # Create team-qa policy
216    $ vault policy write team-qa team-qa.hcl
217
218    # List all policies to verify that 'base', 'test' and 'team-qa' policies exist
219    $ vault policy list
220    base
221    default
222    team-qa
223    test
224    root
225    ```
226
2271. Enable the `userpass` auth method.
228
229    ```plaintext
230    $ vault auth enable userpass
231    ```
232
2331. Create a new user in userpass:
234    - username: bob
235    - password: training
236    - policy: test
237
238    ```plaintext
239    $ vault write auth/userpass/users/bob password="training" policies="test"
240    ```
241
2421. Create another user in userpass:
243    - username: bsmith
244    - password: training
245    - policy: team-qa
246
247    ```plaintext
248    $ vault write auth/userpass/users/bsmith password="training" policies="team-qa"
249    ```
250
2511. Execute the following command to discover the mount accessor for the userpass auth method:
252
253    ```plaintext
254    $ vault auth list -detailed
255    Path                  Type        Accessor                ...
256    ----                  ----        --------                ...
257    token/                token       auth_token_bec8530a     ...
258    userpass/             userpass    auth_userpass_70eba76b  ...
259    ```
260
261    In the output, locate the **Accessor** value for `userpass`.
262
263    Run the following command to store the userpass accessor value in a file named, `accessor.txt`.
264
265    ```plaintext
266    $ vault auth list -format=json | jq -r '.["userpass/"].accessor' > accessor.txt
267    ```
268
2691. Create an entity for `bob-smith`.
270
271    ```plaintext
272    $ vault write identity/entity name="bob-smith" policies="base" \
273         metadata=organization="ACME Inc." \
274         metadata=team="QA"
275
276    Key        Value
277    ---        -----
278    aliases    <nil>
279    id         631256b1-8523-9838-5501-d0a1e2cdad9c
280    ```
281
282    -> Make a note of the generated entity ID (**`id`**).
283
284
2851. Now, add the user `bob` to the `bob-smith` entity by creating an entity alias:
286
287    ```plaintext
288    $ vault write identity/entity-alias name="bob" \
289         canonical_id=<entity_id> \
290         mount_accessor=<userpass_accessor>
291    ```
292
293    The `<userpass_accessor>` value is stored in `accessor.txt`.
294
295    **Example:**
296
297    ```plaintext
298    $ vault write identity/entity-alias name="bob" \
299           canonical_id="631256b1-8523-9838-5501-d0a1e2cdad9c" \
300           mount_accessor=$(cat accessor.txt)
301
302    Key             Value
303    ---             -----
304    canonical_id    631256b1-8523-9838-5501-d0a1e2cdad9c
305    id              873f7b12-dec8-c182-024e-e3f065d8a9f1
306    ```
307
3081. Repeat the step to add user `bsmith` to the `bob-smith` entity.
309
310    **Example:**
311
312    ```plaintext
313    $ vault write identity/entity-alias name="bsmith" \
314           canonical_id="631256b1-8523-9838-5501-d0a1e2cdad9c" \
315           mount_accessor=$(cat accessor.txt)
316
317    Key             Value
318    ---             -----
319    canonical_id    631256b1-8523-9838-5501-d0a1e2cdad9c
320    id              55d46747-b99e-6a82-05f5-61bb60fd7d15
321    ```
322
3231. Review the entity details.
324
325    ```plaintext
326    $ vault read identity/entity/id/<entity_id>
327    ```
328
329    The output should include the entity aliases, metadata (organization, and
330    team), and base policy.
331
332
333
334
335#### API call using cURL
336
3371. Create policies: `base`, `test`, and `team-qa`.
338
339    To create a policy, use the `/sys/policy` endpoint:
340
341    ```shell
342    $ curl --header "X-Vault-Token: <TOKEN>" \
343           --request PUT \
344           --data <PAYLOAD> \
345           <VAULT_ADDRESS>/v1/sys/policy/<POLICY_NAME>
346    ```
347
348    Where `<TOKEN>` is your valid token, and `<PAYLOAD>` includes the policy name and
349    stringified policy.
350
351    **Example:**
352
353    ```shell
354    # Create the API request payload, payload-1.json
355    $ tee payload-1.json <<EOF
356    {
357      "policy": "path \"secret/training_*\" {\n capabilities = [\"create\", \"read\"]\n}"
358    }
359    EOF
360
361    # Create base policy
362    $ curl --header "X-Vault-Token: ..." \
363           --request PUT \
364           --data @payload-1.json \
365           http://127.0.0.1:8200/v1/sys/policy/base
366
367    # Create the API request payload, payload-2.json
368    $ tee payload-2.json <<EOF
369    {
370      "policy": "path \"secret/test\" {\n capabilities = [ \"create\", \"read\", \"update\", \"delete\" ]\n }"
371    }
372    EOF
373
374    # Create base policy
375    $ curl --header "X-Vault-Token: ..." \
376           --request PUT \
377           --data @payload-2.json \
378           http://127.0.0.1:8200/v1/sys/policy/test
379
380    # Create the API request payload, payload-1.json
381    $ tee payload-3.json <<EOF
382    {
383      "policy": "path \"secret/team-qa\" {\n capabilities = [ \"create\", \"read\", \"update\", \"delete\" ]\n }"
384    }
385    EOF
386
387    # Create base policy
388    $ curl --header "X-Vault-Token: ..." \
389           --request PUT \
390           --data @payload-3.json \
391           http://127.0.0.1:8200/v1/sys/policy/team-qa
392
393    # List all policies to verify that 'base', 'test' and 'team-qa' policies exist
394    $ curl --header "X-Vault-Token: ..." \
395           http://127.0.0.1:8200/v1/sys/policy | jq
396    ```
397
3981. Enable the `userpass` auth method.
399
400    ```plaintext
401    $ curl --header "X-Vault-Token: ..." \
402           --request POST \
403           --data '{"type": "userpass"}' \
404           http://127.0.0.1:8200/v1/sys/auth/userpass
405    ```
406
4071. Create a new user in userpass:
408    - username: bob
409    - password: training
410    - policy: test
411
412    ```plaintext
413    $ curl --header "X-Vault-Token: ..." \
414           --request POST \
415           --data '{"password": "training", "policies": "test"}' \
416           http://127.0.0.1:8200/v1/auth/userpass/users/bob
417    ```
418
4191. Create another user in userpass:
420    - username: bsmith
421    - password: training
422    - policy: team-qa
423
424    ```plaintext
425    $ curl --header "X-Vault-Token: ..." \
426           --request POST \
427           --data '{"password": "training", "policies": "team-qa"}' \
428           http://127.0.0.1:8200/v1/auth/userpass/users/bsmith
429    ```
430
4311. Execute the following command to discover the mount accessor for the userpass
432   auth method.
433
434    ```plaintext
435    $ curl --header "X-Vault-Token: ..." \
436           http://127.0.0.1:8200/v1/sys/auth | jq
437     {
438       ...
439       "userpass/": {
440         "accessor": "auth_userpass_9b6cd254",
441        ...
442       },
443       ...
444    ```
445
446    -> Make a note of the userpass accessor value (**`auth_userpass_XXXXX`**).
447
4481. Create an entity for bob-smith.
449
450    ```plaintext
451    $ tee payload.json <<EOF
452    {
453      "name": "bob-smith",
454      "metadata": {
455        "organization": "ACME Inc.",
456        "team": "QA"
457      },
458      "policies": ["base"]
459    }
460    EOF
461
462    $ curl --header "X-Vault-Token: ..." \
463           --request POST \
464           --data @payload.json \
465           http://127.0.0.1:8200/v1/identity/entity
466    {
467      "request_id": "4d4d340f-f4c9-0201-c87e-42cc140a383a",
468      "lease_id": "",
469      "renewable": false,
470      "lease_duration": 0,
471      "data": {
472        "aliases": null,
473        "id": "6ded4d31-481f-040b-11ad-c6db0cb4d211"
474      },
475      ...
476    ```
477
478    -> Make a note of the generated entity ID (**`id`**).
479
4801. Now, add the user `bob` to the `bob-smith` entity by creating an entity alias.
481In the request body, you need to pass the userpass name as `name`, the userpass
482accessor value as `mount_accessor`, and the entity id as `canonical_id`.
483
484    **Example:**
485
486    ```plaintext
487    $ tee payload-bob.json <<EOF
488    {
489      "name": "bob",
490      "canonical_id": "6ded4d31-481f-040b-11ad-c6db0cb4d211",
491      "mount_accessor": "auth_userpass_9b6cd254"
492    }
493    EOF
494
495    $ curl --header "X-Vault-Token: ..." \
496           --request POST \
497           --data @payload-bob.json \
498           http://127.0.0.1:8200/v1/identity/entity-alias
499    ```
500
501
5021. Repeat the step to add user `bsmith` to the `bob-smith` entity.
503
504    **Example:**
505
506    ```plaintext
507    $ tee payload-bsmith.json <<EOF
508    {
509      "name": "bsmith",
510      "canonical_id": "6ded4d31-481f-040b-11ad-c6db0cb4d211",
511      "mount_accessor": "auth_userpass_9b6cd254"
512    }
513    EOF
514
515    $ curl --header "X-Vault-Token: ..." \
516           --request POST \
517           --data @payload-bsmith.json \
518           http://127.0.0.1:8200/v1/identity/entity-alias
519    ```
520
5211. Review the entity details. (**NOTE:** Be sure to enter the entity ID matching
522  your environment.)
523
524    ```plaintext
525    $ curl --header "X-Vault-Token: ..." \
526           http://127.0.0.1:8200/v1/identity/entity/id/<ENTITY_ID>
527    {
528       "request_id": "cc0793bf-fafe-4b2c-fd82-88855712845c",
529       "lease_id": "",
530       "renewable": false,
531       "lease_duration": 0,
532       "data": {
533         "aliases": [
534           {
535             "canonical_id": "6ded4d31-481f-040b-11ad-c6db0cb4d211",
536             ...
537             "mount_type": "userpass",
538             "name": "bob"
539           },
540           {
541             "canonical_id": "6ded4d31-481f-040b-11ad-c6db0cb4d211",
542             ...
543             "mount_type": "userpass",
544             "name": "bsmith"
545           }
546         ],
547         ...
548    ```
549
550    The `bob` and `bsmith` users should appear in the entity alias list.
551
552
553#### Web UI
554
5551. Open a web browser and launch the Vault UI (e.g. http://127.0.01:8200/ui)
556and then login.
557
5581. Click the **Policies** tab, and then select **Create ACL policy**.
559
5601. Enter **`base`** in the **Name** field, and paste in the [`base.hcl` policy
561rules](#scenario-policies) in the **Policy** text editor.
562
563    ![Create Policy](/img/vault-policy-2.png)
564
5651. Click **Create Policy** to complete.
566
5671. Repeat the steps to create policies for **`test`** and **`team-qa`** as well.
568
569    ![Create Policy](/img/vault-policy-1.png)
570
5711. Click the **Access** tab, and select **Enable new method**.
572
5731. Select **Username & Password** from the **Type** drop-down menu.
574
575    ![Create Policy](/img/vault-auth-method-2.png)
576
5771. Click **Enable Method**.
578
5791. Click the Vault CLI shell icon (**`>_`**) to open a command shell.  Enter the
580following command to create a new user, **`bob`**:
581
582    ```plaintext
583    $ vault write auth/userpass/users/bob password="training" policies="test"
584    ```
585    ![Create Policy](/img/vault-auth-method-3.png)
586
5871. Enter the following command to create a new user, **`bsmith`**:
588
589    ```plaintext
590    $ vault write auth/userpass/users/bsmith password="training" policies="team-qa"
591    ```
592    ![Create Policy](/img/vault-auth-method-4.png)
593
5941. Click the icon (**`>_`**) again to hide the shell.
595
5961. From the **Access** tab, select **Entities** and then **Create entity**.
597
5981. Populate the **Name**, **Policies** and **Metadata** fields as shown below:
599
600    ![Create Policy](/img/vault-entity-4.png)
601
6021. Click **Create**.
603
6041. Select **Add alias**.  Enter **`bob`** in the **Name** field and select
605**`userpass/ (userpass)`** from the **Auth Backend** drop-down list.
606
607    ![Create Policy](/img/vault-entity-5.png)
608
6091. Click **Create**.
610
6111. Return to the **Entities** list.  Select **Add alias** from the **`bob-smith`**
612entity menu.
613
614    ![Create Policy](/img/vault-entity-6.png)
615
6161. Enter **`bsmith`** in the **Name** field and select **`userpass/ (userpass)`** from the
617**Auth Backend** drop-down list, and then click **Create**.
618
619
620
621
622### <a name="step2"></a>Step 2: Test the Entity
623
624To better understand how a token inherits the capabilities from the entity's
625policy, you are going to test it by logging in as `bob`.
626
627### CLI Command
628
629First, login as `bob`.
630
631```plaintext
632$ vault login -method=userpass username=bob password=training
633
634Key                    Value
635---                    -----
636token                  ac318416-0dc1-4311-67e4-b58381c86fde
637token_accessor         79cced7b-51df-9523-920f-a1579687516b
638token_duration         768h
639token_renewable        true
640token_policies         ["default" "test"]
641identity_policies      ["base"]
642policies               ["base" "default" "test"]
643token_meta_username    bob
644```
645
646> Upon a successful authentication, a token will be returned. Notice that the
647output displays **`token_policies`** and **`identity_policies`**. The generated
648token has both `test` and `base` policies attached.
649
650The `test` policy grants CRUD operations on the `secret/test` path.
651Test to make sure that you can write secrets in the path.
652
653```plaintext
654$ vault kv put secret/test owner="bob"
655Success! Data written to: secret/test
656```
657
658
659Although the username `bob` does not have `base` policy attached, the token
660inherits the capabilities granted in the base policy because `bob` is a member
661of the `bob-smith` entity, and the entity has base policy attached.
662
663Check to see that the bob's token inherited the capabilities.
664
665```plaintext
666$ vault token capabilities secret/training_test
667create, read
668```
669
670> The `base` policy grants create and read capabilities on
671`secret/training_*` path; therefore, `bob` is permitted to run create and
672read operations against any path starting with `secret/training_*`.
673
674
675What about the `secret/team-qa` path?
676
677```plaintext
678$ vault token capabilities secret/team-qa
679deny
680```
681682The user `bob` only inherits capability from its associating entity's policy.
683The user can access the `secret/team-qa` path only if he logs in with
684`bsmith` credentials.
685
686
687~> Log back in with the token you used to configure the entity before proceed to
688[Step 3](#step3).
689
690
691#### API call using cURL
692
693First, login as `bob`.
694
695```plaintext
696$ curl --request POST \
697       --data '{"password": "training"}' \
698       http://127.0.0.1:8200/v1/auth/userpass/login/bob
699{
700 ...
701 "auth": {
702   "client_token": "b3c2ac10-9f8f-4e64-9a1c-337236ba20f6",
703   "accessor": "92204429-6555-772e-cf51-52492d7f1686",
704   "policies": [
705     "base",
706     "default",
707     "test"
708   ],
709   "token_policies": [
710      "default",
711      "test"
712    ],
713    "identity_policies": [
714      "base"
715    ],
716   ...
717```
718
719> Upon a successful authentication, a token will be returned. Notice that the
720output displays **`token_policies`** and **`identity_policies`**. The generated
721token has both `test` and `base` policies attached.
722
723The `test` policy grants CRUD operations on the `secret/test` path. Test
724to make sure that you can write secrets in the path.
725
726```plaintext
727$ curl --header "X-Vault-Token: ..." \
728       --request POST \
729       --data '{"owner": "bob"}' \
730       http://127.0.0.1:8200/v1/secret/test
731```
732
733
734Although the username `bob` does not have `base` policy attached, the token
735inherits the capabilities granted in the base policy because `bob` is a member
736of the `bob-smith` entity, and the entity has base policy attached.
737
738Check to see that the bob's token inherited the capabilities.
739
740```plaintext
741$ curl --header "X-Vault-Token: ..." \
742         --request POST \
743         --data '{"paths": ["secret/training_test"]}'
744         http://127.0.0.1:8200/v1/sys/capabilities-self | jq
745{
746 "secret/training_test": [
747   "create",
748   "read"
749 ],
750 ...
751```
752
753> The `base` policy grants create and read capabilities on
754`secret/training_*` path; therefore, `bob` is permitted to run create and
755read operations against any path starting with `secret/training_*`.
756
757
758What about the `secret/team-qa` path?
759
760```plaintext
761$ curl --header "X-Vault-Token: ..." \
762       --request POST \
763       --data '{"paths": ["secret/team-qa"]}'
764       http://127.0.0.1:8200/v1/sys/capabilities-self | jq
765{
766 "secret/team-qa": [
767   "deny"
768 ],
769 ...
770```
771772The user `bob` only inherits capability from its associating entity's policy.
773The user can access the `secret/team-qa` path only if he logs in with
774`bsmith` credentials.
775
776
777!> **NOTE:** Log back in with the token you used to configure the entity before proceed to
778[Step 3](#step3).
779
780
781### <a name="step3"></a>Step 3: Create an Internal Group
782
783Now, you are going to create an internal group named, **`engineers`**.  Its
784member is `bob-smith` entity that you created in [Step 1](#step1).
785
786![Entity Bob Smith](/img/vault-entity-3.png)
787
788The group policy, `team-eng` defines the following: **`team-eng.hcl`**
789
790```plaintext
791path "secret/team/eng" {
792  capabilities = [ "create", "read", "update", "delete"]
793}
794```
795
796#### CLI Command
797
7981. Create a new policy named, `team-eng`:
799
800    ```plaintext
801    $ vault policy write team-eng ./team-eng.hcl
802    ```
803
8041. Create an internal group named, `engineers` and add `bob-smith` entity as a
805group member and attach `team-eng`.
806
807    ```plaintext
808    $ vault write identity/group name="engineers" \
809          policies="team-eng" \
810          member_entity_ids=<entity_id> \
811          metadata=team="Engineering" \
812          metadata=region="North America"
813    ````
814    Where `<entity_id>` is the value you copied at [Step 1](#step1).
815
816    **Example:**
817
818    ```plaintext
819    $ vault write identity/group name="engineers" \
820          policies="team-eng" \
821          member_entity_ids="631256b1-8523-9838-5501..."  \
822          metadata=team="Engineering" \
823          metadata=region="North America"
824    Key     Value
825    ---     -----
826    id      81bdac90-284a-7b8c-6289-5fa7693bcb4a
827    name    engineers
828    ```
829
830Now, when you login as `bob` or `bsmith`, its generated token inherits the
831group-level policy, **`team-eng`**. You can perform similar tests demonstrated
832in [Step 2](#step2) to verify that.
833
834
835#### API call using cURL
836
8371. Create a new policy named, `team-eng`:
838
839    ```shell
840    # API request payload containing stringified policy
841    $ tee payload.json <<EOF
842    {
843      "policy": "path \"secret/team/eng\" {\n capabilities = [\"create\", \"read\", \"delete\", \"update\"]\n }"
844    }
845    EOF
846
847    # Create base policy
848    $ curl --header "X-Vault-Token: ..." \
849           --request PUT \
850           --data @payload-1.json \
851           http://127.0.0.1:8200/v1/sys/policy/team-eng
852    ```
853
854
8551. Create an internal group named, `engineers` and add `bob-smith` entity as a
856group member and attach `team-eng`.
857
858    ```shell
859    # API request msg payload.  Be sure to replace <ENTITY_ID> with correct value
860    $ tee payload-group.json <<EOF
861    {
862      "name": "engineers",
863      "policies": ["team-eng"],
864      "member_entity_ids": ["<ENTITY_ID>"],
865      "metadata": {
866        "team": "Engineering",
867        "region": "North America"
868      }
869    }
870    EOF
871
872    # Use identity/group endpoint
873    $ curl --header "X-Vault-Token: ..." \
874           --request PUT \
875           --data @payload-group.json \
876           http://127.0.0.1:8200/v1/identity/group | jq
877    {
878       "request_id": "2b6eefd6-67a6-31c7-dbc3-11c1c132e2cf",
879       "lease_id": "",
880       "renewable": false,
881       "lease_duration": 0,
882       "data": {
883         "id": "d62157aa-b5f6-b6fe-aa40-0ffc54defc41",
884         "name": "engineers"
885       },
886       ...
887    ```
888
889Now, when you login as `bob` or `bsmith`, its generated token inherits the
890group-level policy, **`team-eng`**. You can perform similar tests demonstrated
891in [Step 2](#step2) to verify that.
892
893
894#### Web UI
895
8961. Click the **Policies** tab, and then select **Create ACL policy**.
897
8981. Enter **`team-eng`** in the **Name** field, and paste in the [`team-eng.hcl` policy
899rules](#step3) in the **Policy** text editor, and then click **Create Policy**.
900
9011. Click the **Access** tab and select **Entities**.
902
9031. Select the **`bob-smith`** entity and copy its **ID** displayed under the
904**Details** tab.
905
9061. Now, click **Groups** from the left navigation, and select **Create group**.
907
9081. Enter the group information as shown below.
909
910    ![Group](/img/vault-entity-7.png)
911
912    ~> **NOTE:** Make sure to enter the `bob-smith` entity **ID** you copied in the
913    **Member Entity IDs** field.
914
9151. Click **Create**.
916
917Now, when you login as `bob` or `bsmith`, its generated token inherits the
918group-level policy, **`team-eng`**. You can perform similar tests demonstrated
919in [Step 3](#step3) to verify that.
920
921<br>
922
923> **Summary:** By default, Vault creates an internal group. When you create an
924internal group, you specify the ***group members*** rather than ***group
925alias***. Group _aliases_ are mapping between Vault and external identity providers
926(e.g. LDAP, GitHub, etc.).  Therefore, you define group aliases only when you
927create **external** groups.  For internal groups, you specify `member_entity_ids`
928and/or `member_group_ids`.
929
930
931
932### <a name="step4"></a>Step 4: Create an External Group
933
934It is common for organizations to enable auth methods such as LDAP, Okta and
935perhaps GitHub to handle the Vault user authentication, and individual user's
936group memberships are defined within those identity providers.
937
938In order to manage the group-level authorization, you can create an external
939group to link Vault with the external identity provider (auth provider) and
940attach appropriate policies to the group.
941
942#### Example Scenario
943
944Any user who belongs to **`training`** team in GitHub organization,
945**`example-inc`** are permitted to perform all operations against the
946`secret/education` path.
947
948**NOTE:** This scenario assumes that the GitHub organization, `example-inc`
949exists as well as `training` team within the organization.
950
951### CLI Command
952
953```shell
954# Write a new policy file
955# If you are running KV v2, set the path to "secret/data/education" instead
956$ tee education.hcl <<EOF
957path "secret/education" {
958  capabilities = [ "create", "read", "update", "delete", "list" ]
959}
960EOF
961
962# Create a new policy named 'education'
963$ vault policy write education education.hcl
964
965# Enable GitHub auth method
966$ vault auth enable github
967
968# Retrieve the mount accessor for the GitHub auth method and save it in accessor.txt
969$ vault auth list -format=json | jq -r '.["github/"].accessor' > accessor.txt
970
971# Configure to point to your GitHub organization (e.g. hashicorp)
972$ vault write auth/github/config organization=example-inc
973
974# Create an external group named, "education"
975# Be sure to copy the generated group ID
976$ vault write identity/group name="education" \
977       policies="education" \
978       type="external" \
979       metadata=organization="Product Education"
980
981# Create a group alias where canonical_id is the group ID
982# 'name' is the actual GitHub team name (NOTE: Use slugified team name.)
983$ vault write identity/group-alias name="training" \
984       mount_accessor=$(cat accessor.txt) \
985       canonical_id="<group_ID>"
986```
987
988
989
990#### API call using cURL
991
992```shell
993# API request payload containing stringfied policy
994# If you are running KV v2, set the path to "secret/data/education" instead
995$ tee payload-pol.json <<EOF
996{
997  "policy": "path \"secret/education\" {\n capabilities = [\"create\", \"read\", \"delete\", \"update\", \"list\"]\n }"
998}
999EOF
1000
1001# Create education policy
1002$ curl --header "X-Vault-Token: ..." \
1003       --request PUT \
1004       --data @payload-pol.json \
1005       http://127.0.0.1:8200/v1/sys/policy/education
1006
1007# Enable GitHub Auth Method at github
1008$ curl --header "X-Vault-Token: ..." \
1009       --request POST \
1010       --data '{"type": "github"}' \
1011       http://127.0.0.1:8200/v1/sys/auth/github
1012
1013# Configure GitHub auth method by setting organization
1014$ curl --header "X-Vault-Token: ..." \
1015       --request POST \
1016       --data '{"organization": "example-inc"}' \
1017       http://127.0.0.1:8200/v1/auth/github/config
1018
1019# Get the github accessor value (**`auth_github_XXXXX`**)
1020$ curl --header "X-Vault-Token: ..." \
1021      http://127.0.0.1:8200/v1/sys/auth | jq
1022{
1023  ...
1024  "userpass/": {
1025    "accessor": "auth_github_91010f60",
1026   ...
1027  },
1028  ...
1029}
1030
1031# API request msg payload to create an external group
1032$ tee payload-edu.json <<EOF
1033{
1034   "name": "education",
1035   "policies": ["education"],
1036   "type": "external",
1037   "metadata": {
1038     "organization": "Product Education"
1039   }
1040}
1041EOF
1042
1043# Create an external group named, "education"
1044# Be sure to copy the group ID (id)
1045$ curl --header "X-Vault-Token: ..." \
1046       --request POST \
1047       --data @payload-edu.json \
1048       http://127.0.0.1:8200/v1/identity/group | jq
1049{
1050   "request_id": "a8161086-13db-f982-4216-7d996eae3fd9",
1051   "lease_id": "",
1052   "renewable": false,
1053   "lease_duration": 0,
1054   "data": {
1055     "id": "ea18cb62-2478-d370-b726-a77d1700de80",
1056     "name": "education"
1057   },
1058  ...
1059
1060# API request msg payload to create a group aliases, training
1061$ tee payload-training.json <<EOF
1062{
1063  "canonical_id": "<GROUP_ID>",
1064  "mount_accessor": "auth_github_XXXXX",
1065  "name": "training"
1066}
1067EOF
1068
1069# Create 'training' group alias
1070$ curl --header "X-Vault-Token: ..." \
1071       --request POST \
1072       --data @payload-training.json \
1073       http://127.0.0.1:8200/v1/identity/group-alias | jq
1074```
1075
1076#### Web UI
1077
10781. Click the **Policies** tab, and then select **Create ACL policy**.
1079
10801. Enter **`education`** in the **Name** field, and enter the following policy
1081in the **Policy** text editor, and then click **Create Policy**. (**NOTE:** If
1082you are running KV v2, set the path to **`secret/data/education`** instead.)
1083
1084    ```plaintext
1085    path "secret/education" {
1086      capabilities = [ "create", "read", "update", "delete", "list" ]
1087    }
1088    ```
1089
10901. Click the **Access** tab and select **Auth Methods**.
1091
10921. Select **Enable new method**.
1093
10941. Select **GitHub** from the **Type** drop-down menu, and then enter
1095**`example-inc`** in the **Organization** field.
1096
10971. Click **Enable Method**.
1098
10991. Click the **Access** tab and select **Groups**.
1100
11011. Select **Create group**. Enter the group information as shown below.
1102
1103    ![Create Policy](/img/vault-entity-9.png)
1104
11051. Click **Create**.
1106
11071. Select **Add alias** and enter **`training`** in the **Name** field.  Select
1108**github/ (github)** from the **Auth Backend** drop-down list.
1109
1110    ![Create Policy](/img/vault-entity-10.png)
1111
11121. Click **Create**.
1113
1114<br>
1115
1116> **Summary:** At this point, any GitHub user who belongs to `training`
1117team within the `example-inc` organization can authenticate with Vault. The
1118generated token for the user has `education` policy attached.
1119
1120
1121## Next steps
1122
1123Now that you have learned about managing user identity using entities and
1124groups, read the [AppRole Pull
1125Authentication](/guides/identity/authentication.html) guide to learn how apps or
1126machines can authenticate with Vault.
1127