Terraform Cloud - Governance

The Sentinel Language in Terraform Cloud

Let's start by looking at a real Sentinel policy:

hour = 4
main = rule { hour >= 0 and hour < 12 }

This first line of this example declares a variable named hour with the value 4. The second line declares a rule that will return true if hour is between 0 and 12.

This policy can be applied using Sentinel Simulator to determine whether this policy passed or failed. Save this file as policy.sentinel and run the Sentinel Simulator against it.

$ sentinel apply policy.sentinel

You should receive an output of Pass from this command.

This example introduces a core concept of Sentinel; Rules. Rules are the primary definitions within a policy. Rules are boolean operators that evaluate whether a statement is true or false. The result of a rule can be used to determine whether or not a Terraform action can execute. We'll look more at rules and how they function.

Rules

All policies need a main rule. This is the rule that that defines the final output of Pass or Fail in Sentinel. Let's take a look at more complex rule:

import "tfplan"

main = rule {
  all tfplan.resources.aws_instance as _, instances {
    all instances as _, r {
      (length(r.applied.tags) else 0) > 0
    }
  }
}

This policy has several more rules than our previous example. We won't check this in Sentinel Simulator yet, but let's break down the structure of this rule to understand the Sentinel language logic.

Building Policies

At the core of a policy, Sentinel evaluates factors from defined conditions and imported data to two possible outcomes: Pass or Fail. These conditions are defined with variables and operators. Sentinel can parse variables of several different types. First, are the basic comparisons:

OperatorEvaluation
==equal
!=not equal
<less
<=less or equal
>greater
>=greator or equal
isequal
is notnot equal

These operators can evaluate basic variables like strings and integers. Sentinel can also evaluate with conditions like contains, in, and matches.

main = rule {
  all tfplan.resources.aws_instance as _, instances {
    all instances as _, r {
      (length(r.applied.tags) else 0) > 0
    }
  }
}

Our main rule here searches for all aws_instance resources within the tfplan import. Any matching instances are then scanned for the tags attribute.

Our main rule depends on the tfplan import which we will go over in another section. The tfplan import must contain at least one aws_instance resource. All aws_instance resources are then evaluated to see if there is at least one tag attribute applied.

(length(r.applied.tags) else 0) > 0 is the evaluation that determines the outcome. We have a length function to calculate if the value of the tag attribute applied to the instance is greater than 0. There are several built-in functions Sentinel can access for rule evaluation.

If the instances all contain tags, the policy passes. If the instances do not contain tags, the policy fails.