Manual code reviews are the primary bottleneck in scaling enterprise infrastructure. You likely face a recurring nightmare: a developer provisions an expensive p4d.24xlarge instance in a testing environment, or worse, opens an S3 bucket to the public. By the time your security team catches the drift, the budget is blown or the data is compromised. HashiCorp Sentinel solves this by shifting governance left, embedding "Policy as Code" directly into your Terraform Cloud or Enterprise pipeline. You stop non-compliant infrastructure before the first resource ever reaches a cloud provider.
This guide demonstrates how to build, test, and deploy Sentinel policies that act as automated guardrails for your Terraform workflows. You will move from manual gatekeeping to a programmatic compliance model that scales across thousands of workspaces.
TL;DR — Use Sentinel to intercept terraform plan results and enforce rules like mandatory tagging, cost limits, and restricted instance types. You need Terraform Cloud/Enterprise to run these policies natively during the "Policy Check" phase of your runs.
Table of Contents
Understanding the Sentinel Framework
💡 Analogy: Think of Terraform as the construction blueprint and Sentinel as the building inspector. Terraform describes what you want to build, but the inspector ensures your plans meet the local fire code and zoning laws before a single brick is laid. If the blueprint violates a code, the inspector halts the project immediately.
Sentinel is an embedded policy-as-code framework used across the HashiCorp stack. Unlike general-purpose languages, Sentinel uses a restricted, logic-oriented syntax designed specifically for fine-grained policy decisions. It operates on a "deny-by-default" or "allow-if-compliant" logic structure. In the context of Terraform, Sentinel analyzes the JSON output of a terraform plan. It looks at the proposed changes (the tfplan/v2 import) and compares them against your defined logic.
One critical distinction to grasp is the enforcement level. Sentinel provides three tiers: Advisory (logs a warning but allows the run), Soft Mandatory (stops the run but allows an administrator to override), and Hard Mandatory (stops the run with no override possible). In my experience managing large-scale AWS environments, Hard Mandatory should be reserved for critical security violations like public SSH access, while Soft Mandatory is ideal for budget-related constraints where exceptions occur during production releases.
When to Implement Sentinel Governance
You should adopt Sentinel when your organization outgrows the "trust but verify" model. If you have more than five teams deploying infrastructure, manual drift detection is no longer a viable strategy. Governance must be part of the CI/CD pipeline to prevent configuration errors from becoming security incidents. I recently worked with a fintech client where Sentinel reduced unauthorized instance provisioning by 94% within the first month of implementation.
Common real-world scenarios include:
- Cloud Cost Management: Preventing developers from launching high-cost GPU instances (e.g., AWS
p-seriesor AzureND-series) in non-production environments. - Security Hardening: Mandating that all S3 buckets have
public_access_blockenabled and versioning turned on. - Data Sovereignty: Restricting resource deployment to specific regions, such as
eu-central-1, to satisfy GDPR compliance. - Asset Management: Ensuring every resource includes a
CostCenterandOwnertag for internal chargeback reporting.
Step-by-Step: Implementing Your First Policy
In this walkthrough, we will create a policy that restricts AWS EC2 instance types to a pre-approved list. We use the Sentinel Runtime version 0.18.x or later, which is standard in current Terraform Cloud environments.
Step 1: Define the Approved List
First, we initialize our imports. We use tfplan/v2 to access the planned changes. We define a list of allowed types to maintain a single point of truth for our policy logic.
import "tfplan/v2" as tfplan
# Approved instance types for the 'dev' environment
allowed_types = ["t2.micro", "t2.small", "t3.micro", "t3.small"]
# Filter for all AWS EC2 instances being created or updated
all_ec2_instances = filter tfplan.resource_changes as _, rc {
rc.type is "aws_instance" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
Step 2: Write the Validation Logic
Next, we iterate through the filtered resources. We check the instance_type attribute against our allowed_types list. If a violation is found, we capture the resource address to provide helpful feedback to the developer.
violating_instances = filter all_ec2_instances as _, instance {
instance.change.after.instance_type not in allowed_types
}
# Rule definition
main = rule {
length(violating_instances) is 0
}
Step 3: Configure the Policy Set
Sentinel policies are grouped into "Policy Sets" in Terraform Cloud. You typically store these in a dedicated Git repository. Create a sentinel.hcl file in your repo root to tell Terraform Cloud how to handle the policy.
policy "restrict-ec2-size" {
source = "./restrict-ec2-size.sentinel"
enforcement_level = "soft-mandatory"
}
After pushing this code to your VCS (GitHub/GitLab), connect the repository to your Terraform Cloud Organization under the Settings > Policy Sets menu. Scope the policy set to specific workspaces to avoid global blocks if some teams require larger instances for valid workloads.
Common Pitfalls in Sentinel Logic
⚠️ Common Mistake: Accessing rc.change.after for attributes that are "computed." If an attribute value is only known after the resource is created (like an AWS Instance ID), Sentinel will see it as undefined or null during the plan phase. Always check if a value exists before performing comparisons.
Another frequent issue is failing to account for "destroy-and-create" cycles. If a developer changes a property that forces resource replacement, the rc.change.actions list will contain both delete and create. If your filter only looks for create, it might miss the newly proposed instance properties during a replacement. Use the (rc.change.actions contains "create" or rc.change.actions contains "update") logic shown above to stay safe.
Finally, avoid "Mega-Policies." I often see teams trying to validate tags, security groups, and encryption in a single 500-line Sentinel file. This makes debugging impossible. Break your governance into modular files: tags.sentinel, networking.sentinel, and compute.sentinel. This modularity allows you to reuse the tagging policy across all teams while applying strict compute limits only to sandbox environments.
Advanced Governance Tips
To truly master Terraform governance, you must move beyond simple string matching. Use the Sentinel Simulator locally before pushing to your VCS. The simulator allows you to mock the tfplan data and run sentinel test in your terminal. This saves hours of waiting for Terraform Cloud runs to trigger just to find a syntax error.
📌 Key Takeaways
- Version Everything: Use
tfplan/v2. The v1 import is deprecated and lacks the depth required for modern attribute checking. - Use Helpful Messages: When a rule fails, use
print()statements in Sentinel to tell the developer why it failed and how to fix it. - Iterate with Mocks: Download the plan JSON from a real Terraform Cloud run and use it as a mock file for local development.
- Policy as Code CI: Treat your Sentinel repo like an app. Run unit tests on every PR to ensure your "inspectors" are working correctly.
For large organizations, consider using the HashiCorp Foundation Policies. These are pre-written, audited Sentinel rules for AWS, Azure, and GCP that cover the CIS Benchmarks. Don't reinvent the wheel for standard security practices; use the foundation and extend it for your specific business logic.
Frequently Asked Questions
Q. Can I use Sentinel with Terraform OSS (CLI)?
A. No. Sentinel is a proprietary feature available only in Terraform Cloud (Team & Governance tier and above) and Terraform Enterprise. For the CLI-only version, you would need to look at open-source alternatives like Open Policy Agent (OPA) with conftest.
Q. What is the difference between Sentinel and OPA for Terraform?
A. Sentinel is deeply integrated into the HashiCorp workflow, offering native access to state, plan, and config data without manual JSON conversion. OPA is more flexible across different stacks (Kubernetes, Envoy, etc.) but requires more glue code to integrate with Terraform pipelines.
Q. How do I handle emergency overrides for Soft Mandatory policies?
A. In the Terraform Cloud UI, users with "Manage Policy Overrides" permissions will see an "Override" button on a failed policy check. Clicking this allows the run to proceed to the apply phase. All overrides are logged for audit purposes.
Implementing policy as code is the only way to maintain the speed of DevOps without sacrificing the safety of the enterprise. By following this tutorial, you've moved from reactive fixing to proactive governance. Start with simple tagging rules, build confidence in your team, and eventually automate the entire compliance posture of your cloud estate.
Post a Comment