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
Requires standard tier cluster
If you do not have access to an HCP Vault Dedicated standard tier cluster, visit the Create a Vault Cluster on HCP tutorial.
Launch the HCP Portal and login.
Click Vault in the left navigation pane.
In the Vault clusters pane, click vault-cluster.
Under Cluster URLs, click Public Cluster URL.

In a terminal, set the
VAULT_ADDRenvironment variable to the copied address.$ export VAULT_ADDR=<Public_Cluster_URL>Return to the Overview page and click Generate token.

Copy the Admin Token.

Return to the terminal and set the
VAULT_TOKENenvironment variable.$ export VAULT_TOKEN=<token>Set the
VAULT_NAMESPACEenvironment variable toadmin.$ export VAULT_NAMESPACE=adminType
vault statusto verify your connectivity to the Vault cluster.$ vault status Key Value --- ----- Recovery Seal Type shamir Initialized true Sealed false Total Recovery Shares 1 Threshold 1 Version 1.9.2+ent Storage Type raft ...snipped...Enable the KV secrets engine setting the path to
secret.$ vault secrets enable -path=secret -version=2 kv Success! Enabled the kv secrets engine at: secret/The Vault Dedicated cluster 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 amainrule 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 } EOFWrite a policy that allows
create,updateanddeleteoperations against thesecretpath from an internal IP within the122.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 } EOFTip
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/tapInstall Sentinel.
$ brew install hashicorp/tap/sentinelVerify 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-sentinelChange 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 testThe
testdirectory is where you store the test files.Create a sub-directory named
cidr-checkto store thecidr-check.sentineltest.$ mkdir -p test/cidr-checkCreate a sub-directory named
business-hrsto store thebusiness-hrs.sentineltest.$ mkdir -p test/business-hrsWrite a passing test case in a file named
success.jsonundertest/business-hrsdirectory.test/business-hrs/success.json
$ tee test/business-hrs/success.json <<EOF { "mock": { "time": { "now": { "weekday": 1, "hour": 12 } } }, "test": { "main": true } } EOFUnder
mock, you specify the mock test data. In this example, the mock data setsweekdayto1which isMondayandhourto12which isnoon. Therefore,mainshould returntrue.Write a failing test in a file named
fail.jsonundertest/business-hrs.test/business-hrs/fail.json
$ tee test/business-hrs/fail.json <<EOF { "mock": { "time": { "now": { "weekday": 0, "hour": 12 } } }, "test": { "main": false } } EOFThe mock data sets
weekdayto0which isSundayandhourto12which isnoon. Therefore, themainshould returnfalse.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" } } } EOFIn this example, the
globalblock specifies thecreateoperation invoked on the pathsecret/orders, initiated from the IP address122.22.3.4. Therefore, themainshould returntrue.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 } } EOFThis test will fail because of the IP address mismatch. However, the
precondshould pass since the requested operation iscreateand the targeted endpoint issecret/orders.The optional
testdefinition adds more context to why the test should fail. The expected behavior is that the test fails becausemainreturnsfalsebutprecondshould returntrue.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.jsonExecute the test.
$ sentinel testExample 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.jsonNote
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 namedPOLICY.$ POLICY=$(base64 -i cidr-check.sentinel)Create a policy
cidr-checkwith enforcement level ofhard-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 thesys/policies/egp/cidr-checkpath.$ vault read sys/policies/egp/cidr-checkExample 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 thebusiness-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 thesys/policies/egp/business-hrspath.$ vault read sys/policies/egp/business-hrsExample 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 thesecret/*path.$ vault policy write tester -<<EOF path "secret/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "kv-v2/*" { capabilities = ["create", "read", "update", "delete", "list"] } EOFCreate 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_TOKENExample output:
hvs.CAESIHyhJlnhp1CJ7GoFTTl4ubjOe5nNB0oTIvuAC7mPL5K9Gh4KHGh2cy5DbFQwVVB6S2szaGxscm40cEpUMFZXQmwTest the
cidr-checkEGP by sending a request from an IP address other than122.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-v2Send 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 deniedRun 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 1Tip
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-sentinelChange the working directory to
learn-vault-sentinel.$ cd learn-vault-sentinelMake sure that the
identity-setup.shfile is executable.$ chmod +x identity-setup.shvault 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.txtThe setup script attaches the
test-rgpRGP policy to thesysopsgroup (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-rgpExample 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 tosys/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 injames_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 pressreturn.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 inbob_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 pressreturn.Try to read the
adminpolicy.$ VAULT_TOKEN=$(cat bob_token.txt) vault policy read adminExample 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 deniedThe 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 serviceThe token details shows
admin,sysopsandtest-rgppolicies listed asidentity_policies. Although thesysopspolicy permits access to thesys/*path, thetest-rgpdoes not permit access to read theadminpolicy 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-hrsDelete the
cidr-checkpolicy.$ vault policy delete cidr-checkDelete the Sentinel test directory.
$ rm -r testUnset the
VAULT_TOKENenvironment variable.$ unset VAULT_TOKENUnset the
VAULT_ADDRenvironment variable.$ unset VAULT_ADDRIf you completed the Role Governing Policies (RGPs) section, run the
clean-up.shscript provided by thelearn-vault-sentinelrepository.$ ./clean-up.shIf 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
