Sentinel 0.17 provides the ability to return non-boolean data within a policy. See examples of how to use this new functionality to improve compliance reporting capabilities.
Sentinel is a policy as code language and framework that enables fine-grained, logic-based policy decisions. Sentinel is an enterprise-only feature and is embedded in HashiCorp Consul, Nomad, Terraform, and Vault.
Recently we announced the release of Sentinel 0.17, which is a fundamental change to the Sentinel runtime. It includes several new features:
sentinel apply
and sentinel test
.In this post, I will demonstrate how, by using a mixture of Map Expressions and Rich Return Types, you can greatly improve the process of returning policy compliance reporting data.
From Sentinel 0.17 onward, you can use a higher-order map expression to return a list based on an input collection.
In map expressions, a list is always returned regardless of the input collection type. Upon evaluation, each element within an input collection is identified according to the map expression body, and the resulting data is added to the map.
// Input Collectioninput = [ { "name":"sentinel", "version":"0.17.1", "shasums":"sentinel_0.17.1_SHA256SUMS", "shasums_signature":"sentinel_0.17.1_SHA256SUMS.sig", },] // Map Expressionresult = map input as _, i { { "name": i.name, "version": i.version, }} main = rule { result // [{"name": "sentinel", "version": "0.17.1"}]}
If you would like to view this policy in its entirety, visit the Sentinel Playground.
Rules are a core feature in the Sentinel runtime and form the basis of a policy. Up until now, a rule has been a single boolean expression that returns either true
or false
to indicate a passing or failing rule.
Boolean expression will short-circuit when evaluated, which is critical in time-sensitive applications like HashiCorp Vault. For integrations like Terraform Cloud, which tend to have larger data sets, short-circuit behavior is less of a concern.
When working with large data sets, understanding why a rule evaluation failed, and identifying the offending resources is far more important and can require multiple evaluations before all policy violations are understood and remediated. Achieving the desired result can lead to the adoption of creative workarounds that tend to circumvent the standard behavior and favor round-about tricks to report meaningful data.
With the release of Sentinel 0.17, rules have been updated so that they can evaluate any expression and hold non-boolean values. By supporting all basic types, Sentinel rules can accept collections (lists and maps), strings, and numeric (floating-point and integer) values. Combined with the new higher order map expression, this allows practitioners to create rich sets of report data without having to resort to workarounds such as print
messages and rules that would otherwise serve no real purpose.
So far we have covered what Map Expressions and Rich Return Types are and why we have introduced them to the Sentinel runtime. Let’s take a look at how we can apply our knowledge to a real-world policy based on the following requirements:
All provisioned server instances should have a type of:
All server instance configuration that violates the policy requirements should be reported and should include:
In order to fulfill the first requirement, we need to declare a list of allowedServerTypes
that we can cross-reference to ensure that all provisioned server instances are compliant.
import "tfplan/v2" as tfplan // Allowed Server Instance TypesallowedServerTypes = ["t2.small", "t2.medium", "t2.large"]
We then use a filter expression to return a subset of all server instances that have a type
value that violates the values in the allowedServerTypes
list.
// Filter all instances that will be created that has a type value that is not listed in allowedServerTypesallServerInstanceTypeViolations = filter tfplan.resource_changes as _, rc { rc.change.actions is ["create"] and rc.type is "fakewebservices_server" and rc.change.after.type not in allowedServerTypes}
We can now take the contents of the allServerInstanceTypeViolations
data set and use it to report all compliance violations.
We can use the new map expression to build a dynamic map that contains a message
that describes why a violation has occurred, the address
of the violating resource as well as the type
value and list of allowed_types
.
// This Sentinel policy ensures that server instance type configuration does not violate a list of allowed types.main = rule { // Sentinel map expression providing contextual violation data map allServerInstanceTypeViolations as _, violation { { "message": violation.change.after.name + " has an unsupported instance type", "address": violation.address, "type": violation.change.after.type, "allowed_types": allowedServerTypes, } }}
By encapsulating the expression in main
, we can take advantage of Rich Return Types as well as the enhancements that we have made to Sentinel tracing. With the redesign we have moved from a fully verbose stack-like trace, to a human-readable output that is easier to understand.
1 policies evaluated. ## Policy 1: policy.sentinel (hard-mandatory) Result: false policy.sentinel:14:1 - Rule "main" Description: This Sentinel policy ensures that server instance type configuration does not violate a list of allowed types. Value: [ { "message": "BESRV0 has an unsupported instance type" "address": "fakewebservices_server.backend[0]" "type": "t2.macro" "allowed_types": [ "t2.small" "t2.medium" "t2.large" ] } {...} ]
If you would like to view this policy in its entirety, visit the Sentinel Playground.
The latest release of Sentinel includes several new features that build on previous investments in the policy authoring workflow. You can start exploring these new capabilities now by downloading the latest version of the Sentinel CLI from the Sentinel download page.
For more information on Sentinel language and specification, visit the Sentinel documentation page. If you would like to engage with the community to discuss information related to Sentinel use cases and best practices, visit the HashiCorp Community Forum.
If you would like to play with Sentinel in a safe development environment, you can do so by visiting the Sentinel Playground, which provides the ability to evaluate and share example Sentinel policies and mock data.
ServiceNow Service Catalog for Terraform now lets users provision infrastructure powered by no-code modules published in their organization’s private registry.
No-code provisioning module version upgrades are now GA in HCP Terraform, providing validated self-service infrastructure to reduce toil and lower cloud spend.
Do cloud right with The Infrastructure Cloud from HashiCorp. Unlock developer potential while controlling cloud costs and risk.