Bird
Raised Fist0
Terraformcloud~5 mins

Sentinel policy as code in Terraform - Commands & Configuration

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Sometimes you want to make sure your cloud resources follow rules before they are created. Sentinel lets you write these rules as code to check your Terraform plans automatically.
When you want to block creating resources that don't meet your company's security rules.
When you need to enforce cost limits on cloud resources before deployment.
When you want to ensure naming conventions are followed for all infrastructure.
When you want to prevent accidental deletion of critical resources.
When you want to automate policy checks in your Terraform workflow.
Config File - policy.sentinel
policy.sentinel
import "tfplan/v2" as tfplan

# Check that no AWS EC2 instance is of type t2.micro
main = rule {
  all tfplan.resources.aws_instance as _, instances {
    all instances as instance {
      instance.applied.instance_type is not "t2.micro"
    }
  }
}

This Sentinel policy imports the Terraform plan data and checks all AWS EC2 instances. It ensures none of them use the instance type "t2.micro". If any instance is of that type, the policy fails and blocks deployment.

Commands
Initializes the Terraform working directory and downloads required providers.
Terminal
terraform init
Expected OutputExpected
Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/aws... - Installing hashicorp/aws v4.0.0... - Installed hashicorp/aws v4.0.0 (signed by HashiCorp) Terraform has been successfully initialized!
Creates an execution plan and saves it to a file for Sentinel to evaluate.
Terminal
terraform plan -out=tfplan.binary
Expected OutputExpected
An execution plan has been generated and is saved to tfplan.binary. To perform exactly these actions, run the following command to apply: terraform apply "tfplan.binary"
-out=tfplan.binary - Saves the plan to a file for later use
Runs the Sentinel policy against the saved Terraform plan to check if it passes the rules.
Terminal
sentinel apply -policy=policy.sentinel -input=tfplan.binary
Expected OutputExpected
Policy 'policy.sentinel' passed.
-policy=policy.sentinel - Specifies the Sentinel policy file to use
-input=tfplan.binary - Provides the Terraform plan file as input for evaluation
Key Concept

If you remember nothing else from this pattern, remember: Sentinel lets you write code rules that automatically check your Terraform plans before applying changes.

Common Mistakes
Running Sentinel without generating a Terraform plan file first.
Sentinel needs the Terraform plan as input to evaluate resources; without it, Sentinel cannot check anything.
Always run 'terraform plan -out=tfplan.binary' before running Sentinel with that plan file.
Writing Sentinel rules that do not match the Terraform resource structure.
If the policy code does not correctly access resource fields, it will not evaluate properly and may always pass or fail incorrectly.
Use the official Sentinel Terraform import documentation to write rules that correctly access resource attributes.
Ignoring Sentinel policy failures and applying Terraform changes anyway.
This defeats the purpose of policy enforcement and can lead to non-compliant infrastructure.
Treat Sentinel policy failures as blockers and fix the Terraform code or policy before applying.
Summary
Initialize Terraform to prepare your working directory.
Create a Terraform plan and save it to a file for policy evaluation.
Run Sentinel with your policy file against the saved plan to enforce rules before deployment.

Practice

(1/5)
1. What is the main purpose of a Sentinel policy in Terraform?
easy
A. To enforce rules that control changes to cloud infrastructure
B. To write Terraform configuration files
C. To deploy cloud resources automatically
D. To monitor cloud resource usage

Solution

  1. Step 1: Understand Sentinel policy role

    Sentinel policies are designed to enforce rules and guardrails on infrastructure changes.
  2. Step 2: Differentiate from other Terraform tasks

    Writing configs and deploying resources are Terraform tasks, not Sentinel's role.
  3. Final Answer:

    To enforce rules that control changes to cloud infrastructure -> Option A
  4. Quick Check:

    Sentinel policy = enforce rules [OK]
Hint: Sentinel = rules to control changes, not deployment [OK]
Common Mistakes:
  • Confusing Sentinel with Terraform configuration writing
  • Thinking Sentinel deploys resources
  • Assuming Sentinel monitors usage
2. Which of the following is the correct way to start a Sentinel policy block?
easy
A. sentinel policy example {
B. policy "example" {
C. policy example {
D. policy "example" = {

Solution

  1. Step 1: Recall Sentinel policy syntax

    Sentinel policies start with the keyword 'policy' followed by the policy name in quotes and curly braces.
  2. Step 2: Compare options

    policy "example" { matches the correct syntax: policy "example" { ... }
  3. Final Answer:

    policy "example" { -> Option B
  4. Quick Check:

    Correct Sentinel block start = policy "name" { [OK]
Hint: Policy name must be in quotes after 'policy' keyword [OK]
Common Mistakes:
  • Omitting quotes around policy name
  • Using '=' instead of '{' to start block
  • Adding extra keywords like 'sentinel'
3. Given this Sentinel policy snippet:
policy "check_tags" {
  main = rule {
    all tfplan.resource_changes as _, rc {
      rc.change.after.tags contains "environment"
    }
  }
}

What does this policy check?
medium
A. All resources must have a tag named "environment"
B. At least one resource must have a tag named "environment"
C. No resource should have a tag named "environment"
D. Resources can have any tags without restriction

Solution

  1. Step 1: Analyze the 'all' keyword usage

    The policy uses 'all' to check every resource change in the plan.
  2. Step 2: Understand the condition

    It requires each resource's tags to contain the key "environment".
  3. Final Answer:

    All resources must have a tag named "environment" -> Option A
  4. Quick Check:

    all resources have "environment" tag = All resources must have a tag named "environment" [OK]
Hint: 'all' means every resource must meet condition [OK]
Common Mistakes:
  • Confusing 'all' with 'any' keyword
  • Thinking it checks only one resource
  • Ignoring the 'contains' check on tags
4. Identify the error in this Sentinel policy snippet:
policy "check_region" {
  main = rule {
    all tfplan.resource_changes as _, rc {
      rc.change.after.region is "us-east-1"
    }
  }
}
medium
A. The 'main' rule must be a function, not a rule
B. Missing 'all' or 'any' keyword before the loop
C. Policy name must not be in quotes
D. Incorrect use of 'is' instead of '==' for comparison

Solution

  1. Step 1: Check comparison operator

    Sentinel uses '==' for equality, not 'is'. 'is' causes syntax error.
  2. Step 2: Verify other parts

    The loop uses 'all' correctly. Policy name requires quotes. 'main = rule { }' is standard syntax.
  3. Final Answer:

    Incorrect use of 'is' instead of '==' for comparison -> Option D
  4. Quick Check:

    Use '==' for equality in Sentinel [OK]
Hint: Use '==' for equality, not 'is' in Sentinel [OK]
Common Mistakes:
  • Using 'is' instead of '==' for comparisons
  • Thinking policy name cannot be quoted
  • Confusing rule and function syntax
5. You want to write a Sentinel policy that blocks any Terraform plan which tries to create an AWS EC2 instance without a tag named "owner". Which approach correctly enforces this?
hard
A. Use 'any' to check if any resource has 'owner' tag and allow plan if true
B. Check only the first resource's tags for 'owner' and ignore others
C. Use 'all' to check every resource of type 'aws_instance' has 'owner' tag in 'after' changes
D. Allow plan if no resources are of type 'aws_instance'

Solution

  1. Step 1: Identify the requirement

    Policy must block plans creating EC2 instances missing 'owner' tag.
  2. Step 2: Choose correct logic

    'all' ensures every EC2 instance resource has the 'owner' tag in the planned changes.
  3. Step 3: Evaluate other options

    'any' would allow plans if just one has the tag, which is unsafe. Checking only first resource misses others. Allowing plans with no EC2 instances is unrelated to the requirement.
  4. Final Answer:

    Use 'all' to check every resource of type 'aws_instance' has 'owner' tag in 'after' changes -> Option C
  5. Quick Check:

    All EC2 instances must have 'owner' tag = Use 'all' to check every resource of type 'aws_instance' has 'owner' tag in 'after' changes [OK]
Hint: 'all' enforces every EC2 instance has the tag [OK]
Common Mistakes:
  • Using 'any' instead of 'all' allowing missing tags
  • Checking only one resource instead of all
  • Ignoring resource type filtering