Post

The `tfpolicy` Block No One Reads That Controls Your Entire Cloud Governance

Uncover the `tfpolicy` block in HCP Terraform: a powerful HCL-based policy-as-code framework. Practical commands, expected outputs and a checklist inside.

The `tfpolicy` Block No One Reads That Controls Your Entire Cloud Governance

Your Sentinel policies are likely missing a critical, early-stage enforcement point. A new HCL block is now available in HCP Terraform that provides policy feedback before a plan is even generated, shifting governance further left than ever before. If you’re not using it, you’re letting non-compliant code get further than it should.

TL;DR: HCP Terraform’s new tfpolicy block lets you write policy-as-code directly in HCL, inside your Terraform configuration. This matters because it provides instant, pre-plan feedback, blocking non-compliant resource definitions before a plan is ever run. This post provides a complete guide to its syntax, a comparison with Sentinel, and a working example you can implement today.

What you’ll walk away with:

  • A clear mental model of the tfpolicy evaluation lifecycle.
  • The ability to write a policy that enforces AWS instance type restrictions.
  • A decision framework for when to use tfpolicy versus Sentinel.
  • A checklist for adopting this feature in your organization.

What Is the Terraform tfpolicy Block?

The tfpolicy block is a native HCL construct within HCP Terraform for defining governance policies directly alongside your infrastructure code. It allows you to declare rules that are evaluated before the terraform plan operation begins. If a policy check fails, the entire run is halted, providing immediate feedback to the developer without consuming planning resources.

This feature, currently in public beta, uses a subset of Terraform’s configuration language, making it instantly familiar. You define rule blocks that contain a boolean condition and a user-facing error_message. It’s designed for simple, static checks on resource attributes defined in the code.

Here’s the most basic structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# main.tf
terraform {
  cloud {
    organization = "your-org"
    workspaces {
      name = "your-workspace"
    }
  }
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

# The new policy block
tfpolicy "instance_type_is_approved" {
  rule "t2_micro_is_not_allowed" {
    # This condition evaluates against the configured resource attributes
    condition     = aws_instance.web.instance_type != "t2.micro"
    error_message = "Instance type t2.micro is forbidden. Please use t3.micro or larger."
  }
}

This simple block stops a run dead in its tracks if a developer tries to use the t2.micro instance type, providing a clear error message directly in the HCP Terraform UI.

The tfpolicy block is evaluated against the code itself, not the state file or a planned result. Think of it as a high-level linter with the power to block runs.

How Does tfpolicy Differ from Sentinel or OPA?

The tfpolicy block provides pre-plan validation using HCL, while Sentinel offers post-plan and pre-apply checks using its own policy language, and OPA provides a general-purpose engine using Rego. They are not mutually exclusive; tfpolicy is a new, earlier enforcement gate for simpler rules. It complements, rather than replaces, more powerful tools like Sentinel.

Here’s a breakdown of the key differences:

Feature tfpolicy (HCL) Sentinel OPA (Rego) Winner
Language HCL (subset) Sentinel Rego tfpolicy (for TF teams)
Evaluation Point Pre-plan Post-plan, Pre-apply Pre-plan (via external integrations) tfpolicy (fastest feedback)
Complexity Low (static checks on resource configs) High (complex logic, state access, external data) High (general-purpose logic) Sentinel (most powerful)
Data Sources None (config only) Plan data, state data, external HTTP endpoints Any JSON data Sentinel & OPA
Best For Simple, static rules like naming conventions, forbidden instance types, or required tags where immediate feedback is paramount. Complex rules requiring plan cost, state drift, or integration with external systems like a CMDB. A centralized, multi-tool policy strategy where Terraform is just one component. Varies by use case.

My recommendation: Use tfpolicy for the 80% of simple, “guardrail” policies. This provides the fastest possible feedback loop. Reserve Sentinel for the 20% of complex, multi-faceted policies that require access to the plan, the existing state file (which must be protected—see our guide on OpenTofu Encryption at Rest), or external data sources, as covered in our overview of Terraform Policy as Code.

Default to tfpolicy for any rule that can be expressed as a simple check against a resource’s configured attributes. Only escalate to Sentinel when you need to inspect the result of the plan.

What Is the tfpolicy Evaluation Lifecycle?

The tfpolicy block is evaluated by HCP Terraform as the very first step of a remote run, immediately after the configuration is uploaded and before the plan is initiated. This “pre-plan check” acts as an admission controller for the planning phase itself, ensuring that computationally expensive plans are only run on code that already meets basic compliance standards.

This diagram illustrates where it fits into the standard HCP Terraform workflow:

flowchart TD
    A["User commits main.tf<br/>with tfpolicy block"] --> B{HCP Terraform Run Triggered};
    B --> C["1. Pre-Plan Check:<br/>Evaluate all tfpolicy blocks"];
    C --> D{All policies pass?};
    D -- "Yes" --> E["2. Terraform Plan<br/>(Standard operation)"];
    D -- "No" --> F["Run Failed<br/>(Immediate failure)"];
    E --> G["3. Sentinel Policies<br/>(Post-plan check)"];
    G --> H["4. Manual Approval<br/>(If required)"];
    H --> I["5. Terraform Apply"];

As of HCP Terraform v2026.08, this feature is enabled by default for all organizations on the paid tiers. There is no extra configuration needed to enable the evaluation; simply adding the block to your code activates the check.

The key takeaway is that tfpolicy failures prevent a plan from ever being created, saving both time and compute credits on obviously non-compliant code.

How Do You Write a tfpolicy Rule to Block Instance Types?

You can write a tfpolicy rule by defining a tfpolicy block with a unique name, adding one or more rule blocks inside it, and specifying a condition that must evaluate to true for the policy to pass. This example demonstrates blocking an oversized, expensive EC2 instance type.

First, let’s start with a non-compliant resource configuration. Note the use of c5.24xlarge, which our policy will forbid.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# main.tf
terraform {
  cloud {
    organization = "your-org"
    workspaces {
      name = "prod-web-servers"
    }
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

resource "aws_instance" "web_app" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "c5.24xlarge" # This is non-compliant
  tags = {
    Name = "WebAppServer"
  }
}

Now, we’ll add the tfpolicy block to enforce our instance type restriction against this resource.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
--- a/main.tf
+++ b/main.tf
@@ -19,3 +19,16 @@
     Name = "WebAppServer"
   }
 }
+
+tfpolicy "enforce_approved_instance_types" {
+  assert {
+    # The condition must be true for the policy to pass
+    condition = contains([
+      "t3.micro",
+      "t3.small",
+      "m5.large"
+      ], aws_instance.web_app.instance_type)
+
+    error_message = "aws_instance.web_app uses instance type ${aws_instance.web_app.instance_type}, which is not in the approved list."
+  }
+}

When this configuration is pushed to HCP Terraform, the run will fail immediately during the “Policy Check” step. The UI will display our custom error message, giving the developer clear, actionable feedback.

Click to see the expected HCP Terraform run output
1
2
3
4
5
6
7
8
9
10
11
Policy Check

Failed

tfpolicy "enforce_approved_instance_types"

  assert

    aws_instance.web_app uses instance type c5.24xlarge, which is not in the approved list.

Evaluation of the "tfpolicy" block "enforce_approved_instance_types" failed.

Here is a quick checklist for getting started:

  • Identify a simple, high-value policy (e.g., required tags, naming conventions).
  • Add a tfpolicy block to the root module of a non-critical workspace.
  • Use an assert block to define the condition and error message.
  • Write a clear, actionable error_message.
  • Commit the code and observe the “Policy Check” step in the HCP Terraform run.

Use the assert block within tfpolicy for more complex conditions, and the simpler rule block for basic true/false checks.

Bottom Line

The tfpolicy block is a powerful addition for any team using HCP Terraform that wants faster, cheaper, and more developer-friendly governance. It is not a replacement for Sentinel but a complementary tool that handles the simplest 80% of policies at the earliest possible stage. Start by converting your most common static validation rules from Sentinel into tfpolicy blocks to immediately improve the feedback loop for your developers.

Next, we’ll explore how to make these policies more dynamic by using check blocks and integrating them with module outputs for cross-cutting validation.

FAQ

Can I use tfpolicy with open-source Terraform or only HCP Terraform?

The tfpolicy block is a feature exclusive to HashiCorp’s Terraform Cloud and Terraform Enterprise (HCP Terraform). It is evaluated server-side during a remote run and is not available in open-source Terraform CLI runs.

Does the tfpolicy block support variables or locals?

Yes, you can reference local values and input variables within the condition of a tfpolicy rule. This allows you to centralize your policy logic, for example by defining a local map of approved instance types and referencing it in your policy.

How do you disable a tfpolicy rule temporarily?

To temporarily disable a rule, you can comment out the tfpolicy block or the specific rule or assert block within it using HCL’s # or /* ... */ comment syntax. There is no special “disabled” attribute for the block itself.

What is the difference between rule and assert in a tfpolicy block?

A rule block is the simplest construct, containing a single condition that must be true. An assert block is a more flexible construct, often used inside check blocks, that can support more complex logic and iteration, making it suitable for applying a single policy to many resources.

Does tfpolicy increase my HCP Terraform bill?

No, policy checks themselves do not consume credits or directly increase your bill. In fact, by failing runs early before a plan is generated, tfpolicy can save you money by preventing unnecessary compute consumption for non-compliant code.

Part of the series: tf-policy-hcl

  1. The `tfpolicy` Block No One Reads That Controls Your Entire Cloud Governance (you are here)
  2. Why Your `tfpolicy` `deny` Rule Is Silently Failing in Production (And How to Debug It)
  3. Manual Policy Reviews vs. Automated `tfpolicy` Guardrails: Accelerate Compliance by 90%

🚀 Ready to get hands-on? Spin up an interactive AI or Kubernetes Sandbox at Aicademy Labs for free.

This post is licensed under CC BY 4.0 by the author.