Using Sentinel's HTTP Import in HashiCorp Vault Enterprise
New Sentinel HTTP import capabilities in Vault Enterprise 1.5 enable new sophisticated governance policies. See it in action.
HashiCorp Vault Enterprise 1.5 added support for the Sentinel HTTP Import, which allows Sentinel policies to retrieve data from external API endpoints. This makes it possible for Vault Sentinel policies to apply sophisticated governance controls that were not previously possible with Vault’s traditional Access Control List (ACL) policies or with Vault’s Sentinel policies. And that makes Sentinel in Vault 1.5 much more powerful than it was in earlier versions.
In this blog post, I’ll describe a Vault Sentinel policy that requires all subgroups and member entities of a new Vault Group to belong to the same Vault Namespace as that group or to one of the descendant namespaces (children, grandchildren, great-grandchildren, and so on) of that namespace.
Vault Enterprise does not actually impose this restriction itself, but a customer asked me to enforce it with Sentinel to make it easier for them to do some reporting about group/entity relationships. The restriction is imposed by using the Sentinel HTTP import to call into the Vault HTTP API to retrieve a namespace map and to determine the namespaces that the subgroups and member entities of a new group belong to.
The following screenshot shows part of a Vault namespace hierarchy:
I’ll also describe an auxiliary Sentinel policy that is used to build the namespace map that the primary policy reads.
Both Sentinel policies are Endpoint Governing Policies (EGPs) applied to specific Vault paths. They should both be created in the root namespace of a Vault cluster or server using the Vault UI, CLI, or HTTP API.
If you have a Vault Enterprise 1.5 server or cluster, you can test this policy yourself by following this guide.
What is Sentinel?
HashiCorp’s Sentinel is a language and framework that implements policy as code with fine-grained, logic-based policy decisions just as HashiCorp’s Terraform implements infrastructure as code. Sentinel is embedded in HashiCorp’s enterprise products including Vault Enterprise, in which Sentinel extends Vault’s native ACL policies.
The Auxiliary Policy
Let’s first discuss the auxiliary Sentinel policy, get-namespace-map.sentinel
, that builds the namespace map. This policy is applied to the path, secret/get-namespace-map
in the root namespace.
The policy calls the function get_namespace_map
recursively starting with the root namespace. For each namespace, it uses the HTTP import to call Vault’s v1/<namespace>/sys/namespaces
API endpoint to get a list of all of that namespace’s children. By repeating the calls recursively, the function is able to find all descendant namespaces of every namespace and build a complete namespace map.
The policy returns the namespace map as a JSON document with each key set to the name of a namespace and the corresponding value set to a list containing the namespace itself and all of its descendant namespaces.
The main
rule of the policy always returns false
so that the namespace map will be printed in the Sentinel output.
A Vault operator can rebuild the namespace map at any time by running this Vault CLI command:
vault read secret/get-namespace-map
You can see example output from running this command against a Vault cluster with a deep namespace hierarchy in the guide.
Each time the Vault operator runs the above Vault command to build the namespace map, they should also write the generated JSON document to the path secret/current-namespace-map
in the root namespace with this command:
vault write secret/current-namespace-map namespace-map='<generated_namespace_map>'
where <generated_namespace_map>
is the JSON document returned by the previous command.
The Primary Policy
Now I can describe the primary policy, restrict-namespaces-of-group-members.sentinel, that actually restricts the subgroups and member entities of new Vault groups.
We apply the policy to all paths in all namespaces that match the regex, identity/group(.*)
. We accomplish this by actually applying the policy to all paths by specifying the path *
but then using Sentinel's when
predicate in the policy’s main
rule to only do significant processing against paths that match identity/group(.*)
. This technique works because Vault breaks up the full path of a secret into the namespace portion, namespace.path
, and the path within the namespace, request.path
, before passing the path to Sentinel policies. Using this approach avoids having to list the <namespace>/identity/group
path for every namespace; doing so would be operationally complex since Vault operators would need to update the policy every time they added a new namespace.
The primary policy first reads the namespace map generated by the auxiliary policy from the path secret/current-namespace-map
.
The policy then iterates over all subgroups listed in the member_group_ids
attribute of the new group being created. For each of these subgroups, it uses Sentinel’s HTTP import to make multiple calls against the Vault HTTP API endpoints v1/<namespace>/identity/group/id
to determine the namespaces that the subgroups belong to. (This is done until the right namespace is found.) The policy then checks whether the namespace that subgroup belongs to is in the list of namespaces associated with the parent group's namespace in the namespace map.
The policy then performs similar operations against the entities listed in the member_entity_ids
attribute of the new group being created.
Ultimately, the policy returns false
if it finds any violations and true
if it does not.
The end result is that all subgroups and entities of a new group must belong to the same namespace as that group or to one of that namespace’s descendant namespaces.
Conclusion
This blog post has illustrated how the addition of the Sentinel HTTP import to Vault’s Sentinel implementation in Vault 1.5 makes it possible to implement very sophisticated governance policies in Vault.
While our examples called some of Vault’s own HTTP API endpoints, you could also write Vault Sentinel policies that call public cloud HTTP API endpoints or API endpoints exposed by your company’s own internal systems.
So, if you ever found it difficult to implement specific governance controls with Vault’s native ACL policies or with Vault Sentinel policies, I think you’ll find you can now implement them by using the Sentinel HTTP import.
For more details on how to implement these Sentinel policies yourself, please check out the guide.
For more tips on writing Vault Sentinel policies, see my Validating Vault Secrets with Sentinel post.
Sign up for the latest HashiCorp news
More blog posts like this one
Fix the developers vs. security conflict by shifting further left
Resolve the friction between dev and security teams with platform-led workflows that make cloud security seamless and scalable.
HashiCorp at AWS re:Invent: Your blueprint to cloud success
If you’re attending AWS re:Invent in Las Vegas, Dec. 2 - Dec. 6th, visit us for breakout sessions, expert talks, and product demos to learn how to take a unified approach to Infrastructure and Security Lifecycle Management.
HCP Vault Secrets adds enterprise capabilities for auto-rotation, dynamic secrets, and more
HCP Vault Secrets focuses on making a fast and easy path for secure development with key new features including auto-rotation (GA), dynamic secrets (beta), a new secret sync destination, and more.