Run Policies with Sentinel

Run policies and sentinel in Terraform Cloud — Terraform foundations.

Focus: run policies and sentinel in terraform cloud

Sponsored

You've been there: a teammate pushes a Terraform change that opens port 22 to the world, or creates an S3 bucket with public access. The plan passes, the apply runs, and suddenly your security team is on your back. If you've ever wished you could enforce rules before infrastructure is deployed, run policies and Sentinel in Terraform Cloud are exactly the guardrails you need. This lesson shows you how to add policy-as-code to your Terraform Cloud workspace, so you can catch risky configurations at plan time—not after an incident.

The problem this lesson solves

Terraform is powerful, and with that power comes risk. Without guardrails, anyone with write access to your Terraform Cloud workspace can deploy infrastructure that violates security, compliance, or cost standards. Code reviews help, but they're manual, slow, and error-prone. What you need is a way to automatically enforce rules every time a plan is run, before anything is applied.

This is where run policies come in. Run policies are policies that are evaluated at specific points during a Terraform Cloud run—typically after the plan and before the apply. If a policy fails, the run is blocked (unless an admin overrides it). This means you can prevent bad infrastructure from ever being created, but you can also use policies to enforce tagging standards, cost limits, or allowed regions.

But wait—what about policy-as-code tools like OPA or Checkov? They're great, but Sentinel is natively integrated into Terraform Cloud, which makes it the easiest way to get started if you're already using Terraform Cloud. And since Sentinel is a domain-specific language that's read like a security rule, it's approachable even for developers who aren't policy experts.

Core concept / mental model

Think of run policies as security guards at the gates of your infrastructure. They stand between the plan and the apply, checking every change against your written rules. If the changes pass, the gate opens. If they fail, the gate stays shut, and the run is blocked.

Sentinel is the language you use to write those rules. It's a policy-as-code language that's designed to be readable and expressive. You write rules that describe what you allow or deny. For example, you might allow instances of a certain size, or deny security groups that are open to the world.

Let's break down the key terms you'll encounter:

  • Run policy: A policy that is evaluated during a run. In Terraform Cloud, you attach run policies to workspaces or policy sets.
  • Policy set: A collection of policies that are evaluated together. You can attach a policy set to many workspaces.
  • Policy evaluation: The process of running the Sentinel rules against the data from the plan (or apply).
  • Hard mandatory vs. soft mandatory: In Terraform Cloud, policies can be set to hard mandatory (the run is blocked until an admin overrides) or soft mandatory (the run is blocked but can be overridden by anyone with manage-policies permission).

A quick analogy: think of Sentinel as a spellchecker for your infrastructure. It doesn't rewrite your code, but it flags mistakes before you publish.

How it works step by step

Here's the flow of a Terraform Cloud run when you have run policies enabled:

  1. You push a change to your VCS, or trigger a run in Terraform Cloud.
  2. Terraform plans the change and generates a plan file.
  3. The plan is sent to the policy engine, which evaluates any attached run policies.
  4. The policy engine produces a result: pass, fail, or advisory.
  5. If all policies pass, the run proceeds to the apply stage.
  6. If any policy fails, the run is blocked, and you see the failure in the run UI.
  7. An authorized user can override a policy failure (if the policy is set to soft mandatory), or the code must be fixed and the run re-run.

This flow is what makes run policies so powerful—they're evaluated in the plan phase, so you catch issues before any infrastructure is changed. No more rolling back failed applies.

Where do policies live?

Policies are stored in a repository, typically as .sentinel files. You can create a policy set that points to that repository, and then attach the policy set to one or more workspaces. This is the same pattern you use for Terraform modules—code in a repo, shared across workspaces.

Sentinel language basics

Sentinel syntax is simple. Here's a minimal policy that denies all resources (we'll build on it later):

# deny_all.sentinel
import "tfplan"

main = rule {
    all tfplan.resources as _, resources {
        all resources as _, resource {
            false
        }
    }
}

Don't worry about the details yet. Just note the main = rule block, which is the entry point that returns a boolean.

Hands-on walkthrough

Let's put this into practice. We'll create a simple policy that denies EC2 instances of a certain size, attach it to a workspace, and see it block a run.

Prerequisites

  • A Terraform Cloud account (free tier works)
  • Terraform CLI installed
  • A VCS provider connected (like GitHub) or you can use the API to upload config versions

Step 1: Create a policy repository

Create a new repo, and add a directory called policies. Inside it, create a file called deny-large-instances.sentinel:

# deny-large-instances.sentinel
import "tfplan"

large_types = ["m5.4xlarge", "m5.8xlarge", "m5.12xlarge"]

main = rule {
    all tfplan.resources as _, resources {
        all resources as _, resource {
            not resource.applied is large_types    }
    }
}

This policy checks every planned resource and denies any EC2 instance whose type is in the large_types list. For simplicity, we're checking the applied attribute—you'll learn more about accessing data in the Sentinel documentation.

Step 2: Create a policy set in Terraform Cloud

  1. Log into Terraform Cloud and go to Settings > Policy Sets.
  2. Click Create policy set.
  3. Select Connect to VCS and choose your repo.
  4. Set the Policy path to policies (the directory we created).
  5. Choose Hard mandatory for the enforcement level.
  6. Attach it to a workspace you want to protect.

Step 3: Run a plan that violates the policy

Now create a Terraform configuration that uses a large instance type:

# main.tf
provider "aws" {
  region = "us-east-1"
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "m5.4xlarge"
  tags = {
    Name = "web"
  }
}

Push this to your VCS. Terraform Cloud will start a run. When the plan finishes, the policy evaluation will run, and you'll see the failure in the run UI:

Policy check: denied

Sentinel policies:

  deny-large-instances.sentinel (hard mandatory)
    Result: false

Resources:

  aws_instance.web
    instance_type: m5.4xlarge (denied)

The run is blocked. Now you know the change violates policy, and you can fix it.

Step 4: Fix and re-run

Change the instance type to something allowed, like t3.micro, and push again. This time the policy passes, and the apply proceeds.

Compare options / when to choose what

Run policies in Terraform Cloud are not the only way to enforce policy-as-code. Here's a comparison to help you decide what to use:

Tool Where it runs Integration Language Best for
Terraform Cloud Run Policies Inside Terraform Cloud Native, automatic on every run Sentinel Team already on Terraform Cloud, needs zero-friction enforcement
OPA (Open Policy Agent) Self-hosted or cloud Via Terraform external provider or custom tooling Rego Teams with multi-cloud policy needs outside Terraform
Checkov / tfsec CI/CD pipeline Pre-commit or CI step YAML, Python-based Static analysis before runs, catching mistakes earlier

When to choose run policies: if you're already using Terraform Cloud and you want to enforce rules in the same place where plans happen. You get immediate visibility in the run UI, and you don't need to set up external services or change your CI pipeline.

When to choose alternatives: if you need policy enforcement across multiple tools (not just Terraform), or if you want to catch issues earlier in the development cycle (like in a CI pre-check).

Sentinel vs. other policy languages — Sentinel is proprietary to HashiCorp, but it's designed to be simple and readable. If you want a CNCF-standard, open-source option, OPA with Rego is more general-purpose but has a steeper learning curve.

Troubleshooting & edge cases

Even with run policies, things can go wrong. Here are common issues and how to fix them:

Policy doesn't run — If your policy set isn't attached to the workspace, or the policy path is wrong, the run won't evaluate policies. Double-check the policy set's VCS connection and the path. Also confirm that the workspace has the policy set attached.

Policy fails on everything — This usually means the Sentinel rule is too restrictive or the data access is wrong. For instance, in our example, if the applied attribute doesn't exist, the rule might evaluate as false. Use the plan output to debug: you can print values in Sentinel for debugging (but remove them before production).

Soft mandatory vs. hard mandatory confusion — If a policy is hard mandatory, only workspace admins can override. If soft, any user with manage-policies can override. Make sure you set the right level: hard for security, soft for recommendations.

Policy set not found — If you attach a policy set to a workspace but the policy set is in a different organization, it won't apply. Keep policy sets in the same org as the workspaces.

Token permissions — When you run a plan via CLI, make sure your user has manage-policies permission in Terraform Cloud; otherwise, policy evaluation may be skipped or errors appear.

Performance — Overly complex policies can slow down runs. Keep policies focused on specific rules, and avoid iterating over massive numbers of resources if you can help it.

What you learned & what's next

You now understand how run policies and Sentinel in Terraform Cloud can protect your infrastructure. Specifically, you learned:

  • How run policies fit into the Terraform Cloud run lifecycle (plan → policy → apply).
  • The Sentinel language basics for writing a policy.
  • How to create a policy set, attach it to a workspace, and see a policy block a problematic run.
  • How to compare run policies with other policy-as-code tools.
  • Troubleshooting tips for common policy issues.

You're now ready to move to the next lesson in the track, where you'll dive deeper into policy-as-code best practices and how to write more sophisticated Sentinel policies, including using the tfplan import to inspect changes in detail. Keep this lesson in mind—it's the foundation for everything you'll do with governance in Terraform Cloud.

Practice recap

Now that you've built your first policy, try extending the deny-large-instances.sentinel to also deny any security group that allows port 22 from anywhere. Push the change, run a plan, and verify the run is blocked. Then change the policy to soft mandatory and override it to see the difference in workflow.

Common mistakes

  • Forgetting to attach the policy set to the workspace—policies never run and you don't notice until something goes wrong.
  • Using the wrong policy path in the VCS setup (e.g., policies/ vs policies), leading to no policies found.
  • Setting all policies to hard mandatory, blocking every run until an admin intervenes—use soft mandatory for cost or style recommendations.
  • Assuming Sentinel syntax works like Python—it uses all/any expressions, not loops, and the main = rule block is required.

Variations

  1. Use the tfplan import to inspect resources and their attributes, not just the applied values.
  2. Implement a policy-as-code pipeline with OPA and the external provider if you need multi-tool policy enforcement.
  3. Use static analysis tools like Checkov in your CI to catch issues even before a Terraform Cloud run starts.

Real-world use cases

  • Enforce that all EC2 instances have a valid environment tag (e.g., prod, dev) to meet compliance standards.
  • Block the use of overly permissive security group rules (e.g., port 22 open to 0.0.0.0/0) to prevent security breaches.
  • Limit allowed AWS regions to a set of approved ones, preventing accidental deployment to ungoverned regions.

Key takeaways

  • Run policies are evaluated between plan and apply in Terraform Cloud, blocking infra changes that violate rules.
  • Sentinel is a readable policy language—use it to write simple, focused rules.
  • Policy sets group policies and attach to workspaces, just like modules are shared across code.
  • Choose hard mandatory for security, soft mandatory for governance you want to allow overrides.
  • Debug policy failures by inspecting the plan output and the policy UI details.
  • Policy-as-code is a necessary guardrail, not an afterthought, for team-based Terraform workflows.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.