HashiCorp : Terraform Cloud

Policy as Code Sentinel and OPA

Lab Solution Terraform Cloud Sentinel Policy

In this lab, we’ll implement Policy as Code in Terraform Cloud with Sentinel. Sentinel enforces organizational policies between the terraform plan and terraform apply stages, ensuring your infrastructure remains compliant before changes are applied.

The image shows a KodeKloud lab interface for Terraform Cloud Sentinel Policy, featuring a diagram explaining how Sentinel works with Terraform Cloud and a Visual Studio Code editor with instructions for opening a terminal.

Prerequisites: Teams & Governance Tier

Sentinel policies require the Teams & Governance tier in Terraform Cloud. In Settings → Plan & Billing, activate your free trial or subscription for this tier to unlock Policy as Code, cost estimation, and run tasks.

Note

You must have an active Teams & Governance plan in Terraform Cloud before you can enforce Sentinel policies.

The image shows a KodeKloud lab interface for Terraform Cloud Sentinel Policy, with instructions on activating the "Team and Governance" plan and a Visual Studio Code editor on the right.

In Plan & Billing you’ll see your current plan:

The image shows a pricing plan page for a service, detailing options for Free, Trial, and Team plans, with features and pricing information. The sidebar includes navigation options like Workspaces, Plan & Billing, and Integrations.

The Teams & Governance tier includes all Team features plus Policy as Code and additional run capabilities:

The image shows a pricing and feature comparison for different plans in a software application, with options for "Team & Governance" and "Business" plans. The sidebar includes navigation options like "Plan & billing" and "Integrations."

Fork the Sentinel Policy Repository

Start by forking the HashiCorp Sentinel policy repository into your GitHub account. This gives you a local copy to customize and connect to Terraform Cloud.

The image shows a KodeKloud lab interface for Terraform Cloud Sentinel Policy, with instructions to create a fork of a HashiCorp repository on GitHub. On the right, there's a Visual Studio Code editor with a terminal open.

Review Sentinel Policies

Below are two example policies from the repository.

1. Enforce Mandatory Tags

This policy uses the tfplan-functions import to require that every AWS EC2 instance in the plan has a Name tag. The main rule fails if any instance is missing this tag.

import "tfplan-functions" as plan

# Tags that must be present on every EC2 instance
mandatory_tags = ["Name"]

# Gather EC2 instances from the plan
allEC2Instances = plan.find_resources("aws_instance")

# Identify instances missing required tags
violatingEC2Instances = plan.filter_attribute_not_contains_list(
    allEC2Instances, "tags", mandatory_tags, true
)

# Fail the policy if any violations exist
main = rule {
    length(violatingEC2Instances["messages"]) is 0
}

2. Restrict EC2 Instance Types

This policy ensures only specific EC2 instance types (t2.micro, t2.small, t2.medium) are allowed. Any other type triggers a violation.

import "tfplan-functions" as plan

# List of approved EC2 instance types
allowed_types = ["t2.micro", "t2.small", "t2.medium"]

# Gather EC2 instances from the plan
allEC2Instances = plan.find_resources("aws_instance")

# Find instances with disallowed types
violatingEC2Instances = plan.filter_attribute_not_in_list(
    allEC2Instances, "instance_type", allowed_types, true
)

# Count how many violations we have
violations = length(violatingEC2Instances["messages"])

# Enforce zero violations
main = rule {
    violations is 0
}

Define a Policy Set

Group your Sentinel policies in a sentinel.hcl file at the repository root. Specify each policy and its enforcement level:

module "tfplan-functions" {
  source = "https://raw.githubusercontent.com/hashicorp/terraform-guides/master/governance/third-generation/common-functions/tfplan-functions/tfplan-functions"
}

module "tfconfig-functions" {
  source = "https://raw.githubusercontent.com/hashicorp/terraform-guides/master/governance/third-generation/common-functions/tfconfig-functions/tfconfig-functions"
}

policy "enforce-mandatory-tags" {
  enforcement_level = "advisory"
}

policy "restrict-ec2-instance-type" {
  enforcement_level = "hard-mandatory"
}

Enforcement levels determine how Sentinel handles violations:

Enforcement LevelBehavior
advisoryEmits a warning but does not block the run
soft-mandatoryBlocks runs unless an admin override is added
hard-mandatoryStrictly enforces the policy; no bypass allowed

Warning

The hard-mandatory level cannot be bypassed. Any violation will block the run.

The image shows a KodeKloud lab interface for Terraform Cloud Sentinel Policy, with instructions on setting up a policy set and a Visual Studio Code editor displaying a welcome message for the HashiCorp Terraform Cloud Lab.

Connect the Policy Set to Terraform Cloud

  1. In Terraform Cloud, go to Settings → Policy sets.
  2. Click Connect new policy set, select GitHub (or your VCS), then choose your fork.
  3. Set Policy framework to Sentinel, give it a name (e.g., “AWS Global Policies”), add a description, and specify the path:
    terraform-cloud/policy-as-code/sentinel/global
    
  4. Apply to All workspaces.
  5. Click Connect policy set.

The image shows a web interface for connecting a policy set to a version control provider, with options for GitHub and GitHub (Custom). The sidebar includes navigation options like Teams, Users, and Policy sets.

The image shows a user interface for connecting a policy set in Terraform Cloud, where a repository is being selected from a list. The sidebar includes options like teams, users, and policy sets.

The image shows a "Policy Sets" page from a Terraform Cloud interface, featuring options to connect a new policy set and information about existing AWS-Global-Policies.

Test Policy Enforcement in the UI

Trigger a new run in your workspace. After the plan stage, you’ll see Policy check:

The image shows a Terraform Cloud workspace dashboard for "devops-aws-myapp-dev," displaying details of the latest run, including instance type changes, policy checks, and cost estimates. The "Actions" menu is open, offering options to start a new run or lock the workspace.

The image shows a Terraform Cloud interface with a "Test Sentinel" run in progress, indicating no changes to the infrastructure. Various stages like cost estimation, policy check, and apply are pending.

Policy results appear in the run output:

## Policy 1: AWS-Global-Policies/enforce-mandatory-tags (advisory)
Result: true
Description:
This policy uses the Sentinel tfplan import to require that all EC2 instances have all mandatory tags.

## Policy 2: AWS-Global-Policies/restrict-ec2-instance-type (hard-mandatory)
Result: true
Description:
This policy uses the Sentinel tfplan/v2 import to require that all EC2 instances have instance types from an allowed list.

Test Policy Enforcement via CLI

  1. Configure your backend for Terraform Cloud and run terraform login.
  2. Change the instance_type in terraform.auto.tfvars to an unapproved value (e.g., "m5.large").
  3. Execute:
    terraform init
    terraform plan
    

This triggers a remote run with policy checks. Violations will block the plan.

The image shows a Terraform Cloud interface with a CLI-triggered run. The plan and cost estimation are completed, but the policy check has failed due to a restriction on EC2 instance types.

## Policy: AWS-Global-Policies/restrict-ec2-instance-type (hard-mandatory)
Result: false
Description:
aws_instance.clumsy_bird has instance_type with value m5.large that is not in the allowed list: [t2.micro, t2.small, t2.medium]

Error: Organization Policy Check hard failed.

Remediate and Re-Run

Update your terraform.auto.tfvars to a compliant instance type and commit:

# terraform.auto.tfvars
prefix         = "app"
project        = "clumsy-bird"
environment    = "development"
instance_type  = "t2.medium"
git add terraform.auto.tfvars
git commit -m "Set instance_type to t2.medium"
git push

Terraform Cloud will automatically start a new run and, if compliant, proceed to apply:

## Policy 2: AWS-Global-Policies/restrict-ec2-instance-type (hard-mandatory)
Result: true
Description:
This policy uses the Sentinel tfplan/v2 import to require that all EC2 instances have instance types from an allowed list.

Additional Resources

Terraform Public Registry – Policy Library (Beta): Terraform Public Registry Policy Library (Beta)
The image shows a webpage for "Policy Libraries" in beta, featuring Sentinel policies for Terraform. It includes filters for providers and categories, and lists policies for GCP and Azure with details like version and download count.

AWS Networking Policies in Terraform Guides: AWS Networking Sentinel Policies for Terraform Guides
The image shows a webpage for AWS Networking Sentinel Policies for Terraform by HashiCorp, detailing policy downloads and version information. It includes download statistics and links to the source and maintainer.

HashiCorp Terraform Guides Repository: HashiCorp Terraform Guides Repository
The image shows a GitHub repository page for "terraform-guides" by HashiCorp, displaying folders related to cloud governance policies like AWS, Azure, and GCP.

Sentinel Policy Updates History: Commit History
The image shows a list of files and their descriptions from a GitHub repository, detailing updates and changes made to various Sentinel policy files over the past few years.
The image shows a list of Sentinel policy files from a GitHub repository, each with a description of changes and the time since the last update.

In this guide, we covered how to store Sentinel policies as code, connect them to Terraform Cloud, and enforce them via both the UI and CLI. With Sentinel policies running automatically between plan and apply, you can enforce organizational standards for every infrastructure change.

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Lab Solution Migration to Terraform Cloud