Vault
Enforce access control with Sentinel policies
Enterprise Only
Sentinel requires Vault Enterprise license or an HCP Vault standard tier cluster.
Organizations face on-going security challenges in the modern technology landscape. Most security programs focus on defense in depth strategies to secure their systems. Part of this strategy is to implement controls, such as requiring approval, before a user or workload can access sensitive data such as secrets.
HashiCorp Vault allows you to configure control groups based on Vault access control list (ACL) policies. However, you may not be able to meet all requirements using just control groups.
Challenge
ACL policies are path-based and present the following challenges:
- Cannot grant permissions based on logic other than paths
- Paths are merged in ACL policies which can potentially cause a conflict as the number of policies grows
What if the policy requirement was to grant the read capability on the
secret/orders path if the request came from an IP address within a certain
CIDR?
Solution
HashiCorp Sentinel is a language and framework for writing fine-grained policies as code.
Sentinel Role Governing Policies (RGPs) and Endpoint Governing Policies (EGPs) help you fulfill more complex policy requirements.
Sentinel can access properties of the incoming requests and make a decision based on a certain set of conditions. Available properties include:
- request - Information about the request itself (path, operation type, parameters, etc.)
- token - Information about the token being used (creation time, attached policies, etc.)
- identity - Identity entities and all related data
- mfa - Information about successful MFA validations
Sentinel is a language framework to write fine-grained policies for Vault Enterprise with logic-based policy decisions which cannot be fully handled by the ACL policies.
- EGPs are tied to particular paths such as aws/creds/.
- RGPs are tied to particular tokens, identity entities, or identity groups.
Note
This tutorial walks you through the authoring of Endpoint Governing Policies (EGPs) and Role Governing Policies (RGPs). For ACL policy authoring, refer to the Policies tutorial.
Personas
Sentinel policies enable a declarative way to grant or forbid access to certain paths and operations in Vault. The steps described in this tutorial are typically performed by Vault admins or security operations.
Prerequisites
To perform the tasks described in this tutorial, you need to have:
- Vault Enterprise binary and license key or an HCP Vault Dedicated cluster.
- jq binary installed in your system PATH.
- Git binary installed in your system PATH.
Policy requirements
Since this tutorial demonstrates the creation of policies, log in with highly
privileged token such as root.
The specific required policy capabilities are as follows.
# To list policies
path "sys/policies/*"
{
  capabilities = ["list"]
}
# Create and manage EGPs
path "sys/policies/egp/*"
{
  capabilities = ["create", "read", "update", "delete", "list"]
}
# Create and manage RGPs
path "sys/policies/rgp/*"
{
  capabilities = ["create", "read", "update", "delete", "list"]
}
Set up the lab
- Open a new terminal window and start a Vault dev server with - rootas the root token.- $ vault server -dev -dev-root-token-id root- The Vault dev server starts initialized, unsealed, and defaults to running at - 127.0.0.1:8200.- Insecure operation - Do not run a Vault dev server in production. This approach starts a Vault server with an in-memory database and runs in an insecure way. 
- Export an environment variable for the - vaultCLI to address the Vault server.- $ export VAULT_ADDR=http://127.0.0.1:8200
- Export an environment variable for the - vaultCLI to authenticate with the Vault server.- Note - For these tasks, you can use Vault's root token. However, it is recommended that you use root tokens for enough initial setup or in emergencies. - $ export VAULT_TOKEN=root
- Export an environment variable for the Vault Enterprise license. - $ export VAULT_LICENSE=actual-license-key- The Vault server is ready. 
Write Sentinel policies
Sentinel policies use the Sentinel language. This example is the general format of a Sentinel policy.
import "<library>"
<variable> = <value>
main = rule {
     <conditions_to_evaluate>
}
- import- Enables your policy to access reusable libraries. There are a set of built-in imports available to help define your policy rules.
- main(required) - Every Sentinel policy must have a- mainrule that determines the result of a policy.
- rule- Describes a set of conditions resulting in either true or false. Refer to the Boolean Expressions for the full list of available operators in writing rules.
- <variable>- Variables are dynamically typed in Sentinel. You can define its value explicitly or implicitly by the host system or function.
Note
The Sentinel language supports features such as functions, loops, and slices. You can learn about more in the Sentinel Language documentation.
Endpoint governing policies (EGPs)
Write endpoint governing policies (EGPs) that fulfill the following requirements:
- Write a policy that allows incoming request against the - kv-v2/*path during the business hours (7:00 am to 6:00 pm during the work days).- business-hrs.sentinel - $ tee business-hrs.sentinel <<EOF import "time" # Expect requests to only happen during work days (Monday through Friday) # 0 for Sunday and 6 for Saturday workdays = rule { time.now.weekday > 0 and time.now.weekday < 6 } # Expect requests to only happen during work hours (7:00 am - 6:00 pm) workhours = rule { time.now.hour > 7 and time.now.hour < 18 } main = rule { workdays and workhours } EOF
- Write a policy that allows - create,- updateand- deleteoperations against the- secretpath from an internal IP within the- 122.22.3.4/32CIDR block.- The - mainsection has a conditional rule (- when precond) to ensure that the rule gets evaluated if the request is relevant.- cidr-check.sentinel - $ tee cidr-check.sentinel <<EOF import "sockaddr" import "strings" # Only care about create, update, and delete operations against secret path precond = rule { request.operation in ["create", "update", "delete"] and strings.has_prefix(request.path, "secret/") } # Requests to come only from our private IP range cidrcheck = rule { sockaddr.is_contained("122.22.3.4/32",request.connection.remote_addr) } # Check the precondition before execute the cidrcheck main = rule when precond { cidrcheck } EOF- Tip - Refer to the Sentinel Properties documentation for available properties which Vault injects to Sentinel to allow fine-grained controls. 
Simulate Sentinel policies
You can test the Sentinel policies before deployment to validate the syntax and to document expected behavior.
- Install the HashiCorp Homebrew tap. - $ brew tap hashicorp/tap
- Install Sentinel. - $ brew install hashicorp/tap/sentinel
- Verify the installation with the - --helpflag.- $ sentinel --help Usage: sentinel [--version] [--help] <command> [<args>] Available commands are: apply Execute a policy and output the result fmt Format Sentinel policy to a canonical format test Test policies version Prints the Sentinel runtime version
Write the test cases
Note
You can follow the instructions to write the test files, or
clone the
learn-vault-sentinel
repository which includes the test files.
- Clone the repository. - $ git clone https://github.com/hashicorp-education/learn-vault-sentinel
- Change the working directory to - learn-vault-sentinel/sentinel.- $ cd learn-vault-sentinel/sentinel
Store test files under the /test/<policy_name> directory.
- Create a sub-folder named - test.- $ mkdir test- The - testdirectory is where you store the test files.
- Create a sub-directory named - cidr-checkto store the- cidr-check.sentineltest.- $ mkdir -p test/cidr-check
- Create a sub-directory named - business-hrsto store the- business-hrs.sentineltest.- $ mkdir -p test/business-hrs
- Write a passing test case in a file named - success.jsonunder- test/business-hrsdirectory.- test/business-hrs/success.json - $ tee test/business-hrs/success.json <<EOF { "mock": { "time": { "now": { "weekday": 1, "hour": 12 } } }, "test": { "main": true } } EOF- Under - mock, you specify the mock test data. In this example, the mock data sets- weekdayto- 1which is- Mondayand- hourto- 12which is- noon. Therefore,- mainshould return- true.
- Write a failing test in a file named - fail.jsonunder- test/business-hrs.- test/business-hrs/fail.json - $ tee test/business-hrs/fail.json <<EOF { "mock": { "time": { "now": { "weekday": 0, "hour": 12 } } }, "test": { "main": false } } EOF- The mock data sets - weekdayto- 0which is- Sundayand- hourto- 12which is- noon. Therefore, the- mainshould return- false.
- Write a passing test case for - cidr-checkpolicy,- test/cidr-check/success.json.- test/cidr-check/success.json - $ tee test/cidr-check/success.json <<EOF { "global": { "request": { "connection": { "remote_addr": "122.22.3.4" }, "operation": "create", "path": "secret/orders" } } } EOF- In this example, the - globalblock specifies the- createoperation invoked on the path- secret/orders, initiated from the IP address- 122.22.3.4. Therefore, the- mainshould return- true.
- Write a failing test for - cidr-checkpolicy,- test/cidr-check/fail.json.- test/cidr-check/fail.json - $ tee test/cidr-check/fail.json <<EOF { "global": { "request": { "connection": { "remote_addr": "122.22.3.10" }, "operation": "create", "path": "secret/orders" } }, "test": { "precond": true, "main": false } } EOF- This test will fail because of the IP address mismatch. However, the - precondshould pass since the requested operation is- createand the targeted endpoint is- secret/orders.- The optional - testdefinition adds more context to why the test should fail. The expected behavior is that the test fails because- mainreturns- falsebut- precondshould return- true.- You have written both success and failure tests. - ├── business-hrs.sentinel ├── cidr-check.sentinel └── test ├── business-hrs │  ├── fail.json │  └── success.json └── cidr-check ├── fail.json └── success.json
- Execute the test. - $ sentinel test- Example output: - PASS - business-hrs.sentinel PASS - test/business-hrs/fail.json PASS - test/business-hrs/success.json PASS - cidr-check.sentinel PASS - test/cidr-check/fail.json PASS - test/cidr-check/success.json- Note - If you want to see the tracing and log output for those tests, run the command with - -verboseflag.
Deploy EGP policies
Sentinel policies have three enforcement levels:
| Level | Description | 
|---|---|
| advisory | The policy is allowed to fail. Can be used as a tool to educate new users. | 
| soft-mandatory | The policy must pass unless an override is specified. | 
| hard-mandatory | The policy must pass. | 
Since both policies reference specific paths, the policy type that you are going to create is Endpoint Governing Policies (EGPs).
- Store the Base64 encoded - cidr-check.sentinelpolicy in an environment variable named- POLICY.- $ POLICY=$(base64 -i cidr-check.sentinel)
- Create a policy - cidr-checkwith enforcement level of- hard-mandatoryto reject all requests coming from IP addresses that are not internal.- $ vault write sys/policies/egp/cidr-check \ policy="${POLICY}" \ paths="secret/*" \ enforcement_level="hard-mandatory"
- Read the policy by executing - vault readon the- sys/policies/egp/cidr-checkpath.- $ vault read sys/policies/egp/cidr-check- Example output: - Key Value --- ----- enforcement_level hard-mandatory name cidr-check paths [secret/*] policy import "sockaddr" import "strings" # Only care about create, update, and delete operations against secret path precond = rule { request.operation in ["create", "update", "delete"] and strings.has_prefix(request.path, "secret/") } # Requests to come only from our private IP range cidrcheck = rule { sockaddr.is_contained(request.connection.remote_addr, "122.22.3.4/32") } # Check the precondition before execute the cidrcheck main = rule when precond { cidrcheck }
- Repeat the steps to create a policy named - business-hrs. First, encode the- business-hrspolicy.- $ POLICY2=$(base64 -i business-hrs.sentinel)
- Create a policy with - soft-mandatoryenforcement level.- $ vault write sys/policies/egp/business-hrs \ policy="${POLICY2}" \ paths="kv-v2/*" \ enforcement_level="soft-mandatory"
- Execute - vault readagainst the- sys/policies/egp/business-hrspath.- $ vault read sys/policies/egp/business-hrs- Example output: - Key Value --- ----- enforcement_level soft-mandatory name business-hrs paths [kv-v2/*] policy import "time" # Expect requests to only happen during work days (Monday through Friday) # 0 for Sunday and 6 for Saturday workdays = rule { time.now.weekday > 0 and time.now.weekday < 6 } # Expect requests to only happen during work hours (7:00 am - 6:00 pm) workhours = rule { time.now.hour > 7 and time.now.hour < 18 } main = rule { workdays and workhours }
Unlike ACL policies, EGPs are a prefix walk which allows you to apply policies
at various points in the Vault path. If you have EGPs tied to
"secret/orders", "secret/*" and "*", Sentinel will evaluate all EGPs for a
request on "secret/orders".
Verification
Like ACL policies, root tokens are not subject to Sentinel policy
checks. Use a non-root token for verification tests. For HCP Vault Dedicated,
the admin token is subject to Sentinel policy checks.
- Create a - testerpolicy which allows operations on the- secret/*path.- $ vault policy write tester -<<EOF path "secret/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "kv-v2/*" { capabilities = ["create", "read", "update", "delete", "list"] } EOF
- Create a token with the tester policy attached, and store the token in a - TEST_TOKENenvironment variable.- $ export TEST_TOKEN=$(vault token create -policy="tester" -field=token) \ && echo $TEST_TOKEN- Example output: - hvs.CAESIHyhJlnhp1CJ7GoFTTl4ubjOe5nNB0oTIvuAC7mPL5K9Gh4KHGh2cy5DbFQwVVB6S2szaGxscm40cEpUMFZXQmw
- Test the - cidr-checkEGP by sending a request from an IP address other than- 122.22.3.4.- $ VAULT_TOKEN=$TEST_TOKEN \ vault kv put secret/accounting/test acct_no="29347230942"- Example failure output: - Error writing data to secret/accounting/test: Error making API request. URL: PUT https://127.0.0.1:8200/v1/secret/accounting/test Code: 403. Errors: * 2 errors occurred: * egp standard policy "root/cidr-check" evaluation resulted in denial. The specific error was: <nil> A trace of the execution for policy "root/cidr-check" is available: Result: false Description: Check the precondition before execute the cidrcheck Rule "main" (byte offset 442) = false false (offset 314): sockaddr.is_contained(request.connection.remote_addr, "122.22.3.4/32") Rule "cidrcheck" (byte offset 291) = false Rule "precond" (byte offset 113) = true true (offset 134): request.operation in ["create", "update", "delete"] true (offset 194): strings.has_prefix(request.path, "secret/") * permission denied
Similarly, you will get an error if you make a request outside of the business
hours defined by the business-hrs policy. However, the enforcement level set
on the business-hrs policy is soft-mandatory, so it can be overridden.
- Enable KV v2 secrets engine at - kv-v2.- $ vault secrets enable kv-v2
- Send some test data. - $ VAULT_TOKEN=$TEST_TOKEN \ vault kv put kv-v2/test id="29347230942"- If the current time is outside of the business hours checked by the - business-hrspolicy, the request fails.- Example output: - Error writing data to kv-v2/data/test: Error making API request. URL: PUT http://127.0.0.1:8200/v1/kv-v2/data/test Code: 403. Errors: * 2 errors occurred: * egp standard policy "root/business-hrs" evaluation resulted in denial. The specific error was: <nil> A trace of the execution for policy "root/business-hrs" is available: Result: false Description: <none> Rule "main" (root/business-hrs:14:1) = false Rule "workdays" (root/business-hrs:5:1) = true Rule "workhours" (root/business-hrs:10:1) = false Note: specifying an override of the operation would have succeeded. * permission denied
- Run the command again using the policy override flag ( - -policy-override).- $ VAULT_TOKEN=$TEST_TOKEN \ vault kv put -policy-override kv-v2/test id="29347230942"- Because the policy enforcement level is - soft-mandatory, the request completes.- Example output: - = Secret Path = kv-v2/data/test ======= Metadata ======= Key Value --- ----- created_time 2023-08-11T23:16:55.485525Z custom_metadata <nil> deletion_time n/a destroyed false version 1- Tip - If you are connecting to Vault through the API, set - X-Vault-Policy-Override: truein the request header.
Role governing policies (RGPs)
RGPs reference client tokens or identities which is similar to ACL policies. Vault evaluates the RGP attached to the token to determine whether to accept or reject the request.
Scenario introduction
To demonstrate the use of RGP, you are going to create the following:
- Create ACL policies: secretsandadmin, andsysops
- Enable a userpass auth method at userpass-test/and create a userjamesandbob
- Create an entity named James Thomas
- Create an entity named Bob Smith
- Create a RGP policy named test-rgp
- Create a group named sysopswithJames ThomasandBob Smithentities as its members
- Attach sysopsandtest-rgppolicies to the group

The sysops group has the sysops policy attached which grants capabilities to
manage all policies. All group members inherit the group-level policies. (If
you are not familiar with Vault Identities, refer to the Implement identity
entities and groups tutorial.)
Use the role governing policy to restrict access to the admin policy such that
James or a user with the Team Lead role can manage the admin policy. Other group
members can manage all other policies but not the admin policy.
Create the demo resources
- Clone the - learn-vault-sentinelrepository.- $ git clone https://github.com/hashicorp-education/learn-vault-sentinel
- Change the working directory to - learn-vault-sentinel.- $ cd learn-vault-sentinel
- Make sure that the - identity-setup.shfile is executable.- $ chmod +x identity-setup.sh- vault policy write secrets -<<EOF path "secret/*" { capabilities = [ "create", "read", "update", "delete" ] } EOF vault policy write admin -<<EOF path "auth/*" { capabilities = [ "create", "read", "update", "delete", "list", "sudo" ] } EOF vault policy write sysops -<<EOF path "sys/*" { capabilities = [ "create", "read", "update", "delete", "list", "sudo" ] } EOF vault auth enable -path="userpass-test" userpass vault write auth/userpass-test/users/james password="training" policies="secrets" vault write auth/userpass-test/users/bob password="training" policies="secrets" vault auth list -format=json | jq -r '.["userpass-test/"].accessor' > accessor_test.txt # Create 'James Thomas' entity vault write -format=json identity/entity name="James Thomas" policies="admin" \ metadata=role="Team Lead" \ | jq -r ".data.id" > entity_id_james.txt vault write identity/entity-alias name="james" \ canonical_id=$(cat entity_id_james.txt) \ mount_accessor=$(cat accessor_test.txt) # Create Bob Smith entity vault write -format=json identity/entity name="Bob Smith" policies="admin" \ metadata=role="Kubernetes Expert" \ | jq -r ".data.id" > entity_id_bob.txt vault write identity/entity-alias name="bob" \ canonical_id=$(cat entity_id_bob.txt) \ mount_accessor=$(cat accessor_test.txt) # Add an RGP policy cat <<EOF | base64 | vault write sys/policies/rgp/test-rgp policy=- enforcement_level="hard-mandatory" import "strings" precond = rule { strings.has_prefix(request.path, "sys/policies/acl/admin") } main = rule when precond { identity.entity.metadata.role is "Team Lead" or identity.entity.name is "James Thomas" } EOF # Create 'sysops' group vault write -format=json identity/group name="sysops" \ policies="sysops, test-rgp" \ member_entity_ids="$(cat entity_id_james.txt), $(cat entity_id_bob.txt)" \ | jq -r ".data.id" > group_id_sysops.txt- The setup script attaches the - test-rgpRGP policy to the- sysopsgroup (line 58).
- Run the - identity-setup.shscript.- $ ./identity-setup.sh Success! Uploaded policy: secrets Success! Uploaded policy: admin Success! Uploaded policy: sysops Success! Enabled userpass auth method at: userpass-test/ Success! Data written to: auth/userpass-test/users/james Success! Data written to: auth/userpass-test/users/bob Key Value --- ----- canonical_id 07f6868e-8a87-5141-1828-93097f59f424 id 55972826-f3c8-2601-3acf-6568273672e2 Key Value --- ----- canonical_id 73decd4f-ae4c-1dc1-a1a9-a74068ef42c4 id 20e36023-c181-cbbf-f225-df9592797f56 Success! Data written to: sys/policies/rgp/test-rgp
Review the created identities and policies
- Examine the - test-rgppolicy.- $ vault policy read test-rgp- Example output: - import "strings" precond = rule { strings.has_prefix(request.path, "sys/policies/acl/admin") } main = rule when precond { identity.entity.metadata.role is "Team Lead" or identity.entity.name is "James Thomas" }- The - precondchecks the incoming request endpoint. If the request is targeted to- sys/policies/acl/admin, Vault checks to see if the request was made by an entity named, James Thomas or has Team Lead role defined as its metadata. Refer to the Entity Properties documentation for the list of available properties.
- Review the James Thomas entity details. The entity ID is stored in the - entity_id_james.txtfile by the script.- $ vault read identity/entity/id/$(cat entity_id_james.txt)- Example output: - James Thomas entity has Team Lead role defined in its metadata. - Key Value --- ----- aliases [map[canonical_id:5e8cba9e-b663-97e9-5e1f-b68248e53534 creation_time:2022-09-14T01:34:53.174277Z custom_metadata:map[] id:857fedd9-038b-8c16-ddff-3b891336699b last_update_time:2022-09-14T01:34:53.174277Z local:false merged_from_canonical_ids:<nil> metadata:<nil> mount_accessor:auth_userpass_fb364660 mount_path:auth/userpass-test/ mount_type:userpass name:james]] creation_time 2022-09-14T01:34:53.081739Z direct_group_ids [87d8a8df-cfac-f6be-0ee7-bcf227ab098b] disabled false group_ids [87d8a8df-cfac-f6be-0ee7-bcf227ab098b] id 5e8cba9e-b663-97e9-5e1f-b68248e53534 inherited_group_ids [] last_update_time 2022-09-14T01:34:53.081739Z merged_entity_ids <nil> metadata map[role:Team Lead] mfa_secrets map[] name James Thomas namespace_id root policies [admin]
- Review the Bob Smith entity details. The entity ID is available in - entity_id_bob.txt.- $ vault read identity/entity/id/$(cat entity_id_bob.txt)- Example output: - Bob's functional role is Kubernetes expert. - Key Value --- ----- aliases [map[canonical_id:83e66ad6-e6ee-d6ed-8063-e88d90dd4de3 creation_time:2022-09-14T23:30:46.079077Z custom_metadata:map[] id:437cc7a4-2e6d-3b2b-0bd6-d0f57c8e3644 last_update_time:2022-09-14T23:30:46.079077Z local:false merged_from_canonical_ids:<nil> metadata:<nil> mount_accessor:auth_userpass_427c2404 mount_path:auth/userpass-test/ mount_type:userpass name:bob]] creation_time 2022-09-14T23:30:45.958557Z direct_group_ids [2652cb82-c798-3a42-1fc7-9c4005190ec5] disabled false group_ids [2652cb82-c798-3a42-1fc7-9c4005190ec5] id 83e66ad6-e6ee-d6ed-8063-e88d90dd4de3 inherited_group_ids [] last_update_time 2022-09-14T23:30:45.958557Z merged_entity_ids <nil> metadata map[role:Kubernetes Expert] mfa_secrets map[] name Bob Smith namespace_id root policies [admin]
Verification
- Login as - jamesand store the generated token in- james_token.txt- $ vault login -method=userpass -path=userpass-test -field=token \ username=james > james_token.txt Password (will be hidden):
- Enter the password - trainingwhen prompted, and press- return.
- Read the - adminpolicy.- $ VAULT_TOKEN=$(cat james_token.txt) vault policy read admin path "auth/*" { capabilities = [ "create", "read", "update", "delete", "list", "sudo" ] }- The command returns the policy. 
- Login as - boband store the generated token in- bob_token.txt- $ vault login -method=userpass -path=userpass-test -field=token \ username=bob > bob_token.txt Password (will be hidden):
- Enter the password - trainingwhen prompted and press- return.
- Try to read the - adminpolicy.- $ VAULT_TOKEN=$(cat bob_token.txt) vault policy read admin- Example output: - Error reading policy named admin: Error making API request. URL: GET http://127.0.0.1:8200/v1/sys/policies/acl/admin Code: 403. Errors: * 2 errors occurred: * rgp standard policy "root/test-rgp" evaluation resulted in denial. The specific error was: <nil> A trace of the execution for policy "root/test-rgp" is available: Result: false Description: <none> Rule "main" (root/test-rgp:7:1) = false Rule "precond" (root/test-rgp:3:1) = true * permission denied- The request is denied because neither Bob's entity metadata nor his name matched the conditions in the main rule, which returned false. 
- Read the token details. - $ VAULT_TOKEN=$(cat bob_token.txt) vault token lookup Key Value --- ----- accessor NfBU02DcEAVSJACJUkVmpOnK creation_time 1663124784 creation_ttl 768h display_name userpass-test-bob entity_id 6090ff87-e3d8-09f1-b8d8-94ec9a7bb05b expire_time 2022-10-15T20:06:24.77325-07:00 explicit_max_ttl 0s external_namespace_policies map[] id hvs.CAESIEZ4R6stpJNirlgggzY0SknVO9YkFbUZ8OoUsuV32tL7Gh4KHGh2cy5Bc2NYaXVOQzJVemJTRjFzU1U2d0c2bjA identity_policies [admin sysops test-rgp] issue_time 2022-09-13T20:06:24.773255-07:00 meta map[username:bob] num_uses 0 orphan true path auth/userpass-test/login/bob policies [default secrets] renewable true ttl 767h44m29s type service- The token details shows - admin,- sysopsand- test-rgppolicies listed as- identity_policies. Although the- sysopspolicy permits access to the- sys/*path, the- test-rgpdoes not permit access to read the- adminpolicy unless the entity's name is "James Thomas" or has "Team Lead" defined in the entity metadata.
- To verify, read the - sysopspolicy with Bob's token.- $ VAULT_TOKEN=$(cat bob_token.txt) vault policy read sysops path "sys/*" { capabilities = [ "create", "read", "update", "delete", "list", "sudo" ] }- Bob can access other policies. 
Challenge question
What can you do to allow Bob Smith to access the admin policy?
One of the solutions is to change Bob's entity metadata to contain Team Lead.
$ vault write identity/entity/id/$(cat entity_id_bob.txt) metadata=role="Team Lead"
Another possible solution is to update the test-rgp policy to check for Bob
Smith entity name.
test-rgp
import "strings"
precond = rule {
    strings.has_prefix(request.path, "sys/policies/acl/admin")
}
main = rule when precond {
    identity.entity.metadata.role is "Team Lead" or
        identity.entity.name is "James Thomas" or
         identity.entity.name is "Bob Smith"
}
Now, Bob should be able to read the admin policy.
$ VAULT_TOKEN=$(cat bob_token.txt) vault policy read admin
path "auth/*" {
   capabilities = [ "create", "read", "update", "delete", "list", "sudo" ]
}
Clean up
If you wish to clean up your environment after completing the tutorial, follow the steps in this section.
- Delete the - business-hrspolicy.- $ vault policy delete business-hrs
- Delete the - cidr-checkpolicy.- $ vault policy delete cidr-check
- Delete the Sentinel test directory. - $ rm -r test
- Unset the - VAULT_TOKENenvironment variable.- $ unset VAULT_TOKEN
- Unset the - VAULT_ADDRenvironment variable.- $ unset VAULT_ADDR
- If you completed the Role Governing Policies (RGPs) section, run the - clean-up.shscript provided by the- learn-vault-sentinelrepository.- $ ./clean-up.sh
- If you are running Vault locally in - -devmode, you can stop the Vault dev server by pressing Ctrl+C where the server is running. Or, execute the following command.- $ pgrep -f vault | xargs kill
Summary
You learned the basics of endpoint governing policies (EGPs) and role governing policies (RGPs). To learn more about Sentinel policies in Vault, continue onto the following tutorials:
Help and reference
- Sentinel documentation
- Vault Sentinel documentation
- Security and Fundamentals at Scale with Vault
- Identity - Entities and Groups tutorial
- Sentinel Properties
