» Policy Language

Sentinel defines and uses its own policy language.

The language was designed to be approachable by non-programmers, since there are many use cases where the individual defining policy may not be a developer. However, the language includes constructs that are familiar to developers to enable powerful policies.

To learn more about the language, please see the writing policy section or the language reference.

An example of the policy language is shown below:

import "time"

# Validate time is between 8 AM and 4 PM
valid_time = rule { time.hour > 8 and time.hour < 16 }

# Validate day is M - Th
valid_day  = rule { time.day in ["monday", "tuesday", "wednesday", "thursday"] }

main = rule { valid_time and valid_day }

» Why?

To explain why Sentinel defines and uses its own language, the question can be more easily split into roughly two types of languages: configuration languages and programming languages.

» Configuration Languages

Configuration languages are formats such as JSON, YAML, XML, etc. Many applications use configuration languages as their ACL format. Configuration languages are good for static, declarative information. ACL systems are a good fit for this. ACL systems are focused, providing the limiting options necessary to restrict access to a system.

Configuration languages are not good for dynamic or logical rules. They typically only contain limited conditions, loops, or functions. Further configuration is often declarative, which can introduce complexities to logical statements that depend on ordering.

The use cases that Sentinel was built for require the ability to perform complex behavior that didn't model well into a configuration format or a declarative form.

» Programming Languages

The Sentinel language was designed with the following goals:

  • Non-programmer friendly. Sentinel was built to be used by non-programmers. For the use cases we discovered, non-programmers needed the ability to enforce certain rules within a system. For example, a person responsible for compliance may need to insert rules into a system.

  • Programmer friendly. At the same time, the language needed to support programmer-friendly constructs such as conditionals, loops, and functions for complex policies that a programmer may be writing.

  • Embeddable. Sentinel is embedded in existing software. The language itself needs to be easily embeddedable. Further, Sentinel was designed to be embedded in HashiCorp software written in Go, so it needed to be easily embeddable in Go.

  • Safe. The language is used in highly security-sensitive environments. It must not be able to crash its host system or access system resources without explicit approval.

Prior to building our own language, Sentinel evaluated other languages. Some languages worked quite well. As we continued to develop Sentinel, we found that the flexibility and control over designing our own language outweighed the costs.

Because the language itself doesn't need to be general purpose, building a language focused on policy proved to be the best route for Sentinel. It allows us to build powerful tracing capabilities for debugging, make interesting performance choices, and extend the language as needed in the future.