* conversion stage 1 * correct image paths * add sidebar title to frontmatter * docs/concepts and docs/internals * configuration docs and multi-level nav corrections * commands docs, index file corrections, small item nav correction * secrets converted * auth * add enterprise and agent docs * add extra dividers * secret section, wip * correct sidebar nav title in front matter for apu section, start working on api items * auth and backend, a couple directory structure fixes * remove old docs * intro side nav converted * reset sidebar styles, add hashi-global-styles * basic styling for nav sidebar * folder collapse functionality * patch up border length on last list item * wip restructure for content component * taking middleman hacking to the extreme, but its working * small css fix * add new mega nav * fix a small mistake from the rebase * fix a content resolution issue with middleman * title a couple missing docs pages * update deps, remove temporary markup * community page * footer to layout, community page css adjustments * wip downloads page * deps updated, downloads page ready * fix community page * homepage progress * add components, adjust spacing * docs and api landing pages * a bunch of fixes, add docs and api landing pages * update deps, add deploy scripts * add readme note * update deploy command * overview page, index title * Update doc fields Note this still requires the link fields to be populated -- this is solely related to copy on the description fields * Update api_basic_categories.yml Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages. * Add bottom hero, adjust CSS, responsive friendly * Add mega nav title * homepage adjustments, asset boosts * small fixes * docs page styling fixes * meganav title * some category link corrections * Update API categories page updated to reflect the second level headings for api categories * Update docs_detailed_categories.yml Updated to represent the existing docs structure * Update docs_detailed_categories.yml * docs page data fix, extra operator page remove * api data fix * fix makefile * update deps, add product subnav to docs and api landing pages * Rearrange non-hands-on guides to _docs_ Since there is no place for these on learn.hashicorp, we'll put them under _docs_. * WIP Redirects for guides to docs * content and component updates * font weight hotfix, redirects * fix guides and intro sidenavs * fix some redirects * small style tweaks * Redirects to learn and internally to docs * Remove redirect to `/vault` * Remove `.html` from destination on redirects * fix incorrect index redirect * final touchups * address feedback from michell for makefile and product downloads
5.3 KiB
layout | page_title | sidebar_title | sidebar_current | description |
---|---|---|---|---|
docs | Sentinel Examples | Examples | docs-vault-enterprise-sentinel-examples | An overview of how Sentinel interacts with Vault Enterprise. |
Examples
Following are some examples that help to introduce concepts. If you are unfamiliar with writing Sentinel policies in Vault, please read through to understand some best practices.
MFA and CIDR Check on Login
The following Sentinel policy requires the incoming user to successfully validate with an Okta MFA push request before authenticating with LDAP. Additionally, it ensures that only users on the 10.20.0.0/16 subnet are able to authenticate using LDAP.
import "sockaddr"
import "mfa"
import "strings"
# We expect logins to come only from our private IP range
cidrcheck = rule {
sockaddr.is_contained(request.connection.remote_addr, "10.20.0.0/16")
}
# Require Ping MFA validation to succeed
ping_valid = rule {
mfa.methods.ping.valid
}
main = rule when strings.has_prefix(request.path, "auth/ldap/login") {
ping_valid and cidrcheck
}
Note the rule when
construct on the main
rule. This scopes the policy to
the given condition.
Vault takes a default-deny approach to security. Without such scoping, because active Sentinel policies must all pass successfully, the user would be forced to start with a passing status and then define the conditions under which access is denied, breaking the default-deny concept.
By instead indicating the conditions under which the main
rule (and thus, in
this example, the entire policy) should be evaluated, the policy instead
describes the conditions under which a matching request is successful. This
keeps the default-deny feeling of Vault; if the evaluation condition isn't met,
the policy is simply a no-op.
Allow Only Specific Identity Entities or Groups
main = rule {
identity.entity.name is "jeff" or
identity.entity.id is "fe2a5bfd-c483-9263-b0d4-f9d345efdf9f" or
"sysops" in identity.groups.names or
"14c0940a-5c07-4b97-81ec-0d423accb8e0" in keys(identity.groups.by_id)
}
This example shows accessing Identity properties to make decisions, showing that for Identity values IDs or names can be used for reference.
In general, it is more secure to use IDs. While convenient, entity names and group names can be switched from one entity to another, because their only constraint is that they must be unique. Using IDs guarantees that only that specific entity or group is sufficient; if the group or entity are deleted and recreated with the same name, the match will fail.
Instantly Disallow All Previously-Generated Tokens
Imagine a break-glass scenario where it is discovered that there have been compromises of some unknown number of previously-generated tokens.
In such a situation it would be possible to revoke all previous tokens, but this may take a while for a number of reasons, from requiring revocation of generated secrets to the simple delay required to remove many entries from storage. In addition, it could revoke tokens and generated secrets that later forensic analysis shows were not compromised, unnecessarily widening the impact of the mass revocation.
In Vault's ACL system a simple deny could be put into place, but this is a very coarse-grained control and would require forethought to ensure that a policy that can be modified in such a way is attached to every token. It also would not prevent access to login paths or other unauthenticated paths.
Sentinel offers much more fine-grained control:
import "time"
main = rule when not request.unauthenticated {
time.load(token.creation_time).unix >
time.load("2017-09-17T13:25:29Z").unix
}
Created as an EGP on *
, this will block all access to any path Sentinel
operates on with a token created before the given time. Tokens created after
this time, since they were not a part of the compromise, will not be subject to
this restriction.
Delegate EGP Policy Management Under a Path
The following policy gives token holders with this policy (via their tokens or their Identity entities/groups) the ability to write EGP policies that can only take effect at Vault paths below certain prefixes. This effectively delegates policy management to the team for their own key-value spaces.
import "strings"
data_match = func() {
# Make sure there is request data
if length(request.data else 0) is 0 {
return false
}
# Make sure request data includes paths
if length(request.data.paths else 0) is 0 {
return false
}
# For each path, verify that it is in the allowed list
for strings.split(request.data.paths, ",") as path {
# Make it easier for users who might be used to starting paths with
# slashes
sanitizedPath = strings.trim_prefix(path, "/")
if not strings.has_prefix(sanitizedPath, "dev-kv/teama/") and
not strings.has_prefix(sanitizedPath, "prod-kv/teama/") {
return false
}
}
return true
}
# Only care about writing; reading can be allowed by normal ACLs
precond = rule {
request.operation in ["create", "update"] and
strings.has_prefix(request.path, "sys/policies/egp/")
}
main = rule when precond {
strings.has_prefix(request.path, "sys/policies/egp/teama-") and data_match()
}