TrademarkTrademark
Features
Documentation

Terraform Checks: Reliability and Compliance

Automated Terraform checks enforce policy, prevent drift, and boost reliability & compliance—see how to make it effortless.
Sebastian StadilJune 6, 2025Updated March 31, 2026
Terraform Checks: Reliability and Compliance
Key takeaways
  • Terraform check blocks are a native feature for defining custom HCL assertions that verify infrastructure assumptions continuously, not just at provisioning.
  • Check blocks are evaluated at the end of every terraform plan and apply, and failed assertions issue non-blocking warnings rather than errors that halt operations.
  • Unlike resource preconditions and postconditions, check blocks can assert conditions across multiple resources or external systems for end-to-end, system-level validation.
  • A complete validation strategy layers check blocks with tools like terraform validate, TFLint, Checkov or TFSec, and policy-as-code engines such as OPA or HashiCorp Sentinel.
  • Because check warnings are non-blocking, stricter enforcement at scale often requires a management platform like Scalr to centralize policy definition and visibility.

Infrastructure as Code makes deployments fast and repeatable, but it doesn't tell you whether what you deployed is actually correct, secure, and compliant. That's a separate problem, and it's the one validation tools solve. This post looks at how Terraform's native check blocks fit into that picture, alongside the linters, scanners, and policy engines you'd pair them with.

1. The Evolution of IaC Validation

Catching misconfigurations and compliance gaps before they ship is the whole point of validation. Terraform's tooling for this has grown up in stages:

  • Initial Stages: Focused on syntax validation (terraform validate).
  • Growing Sophistication: Emergence of linters for provider-specific checks.
  • Security & Compliance Focus: Development of dedicated scanning tools and policy-as-code frameworks.
  • Native Advancements: Introduction of Terraform check blocks for in-configuration assertions.

The trend is to validate earlier, and to keep validating after deployment rather than only at provisioning time.

2. Introducing Terraform check Blocks

A check block is a native Terraform feature for writing custom assertions about your infrastructure. The point is to verify your assumptions on an ongoing basis, not only when resources are first provisioned.

Core Purpose and Benefits

  • Decoupled from Resource Lifecycles: check blocks can assert conditions across multiple resources or external systems, unlike resource-specific custom conditions. This allows for end-to-end, system-level validation.
  • Using the Terraform Language (HCL): Define assertions using familiar HCL syntax, lowering the learning curve.
  • Enabling Ongoing Infrastructure Verification: Executed with every terraform plan and terraform apply, providing continuous feedback. This is further enhanced by features like HCP Terraform's health assessments for scheduled checks.
  • Non-Blocking Operations: Failed assertions issue warnings, not errors that halt operations. Operators get the feedback and decide what to do with it. The flip side is that a warning can't stop a bad change on its own, so teams that need hard enforcement across many environments usually add a management platform on top.

Anatomy of a check Block

A check block has a local name and contains one or more assert blocks.

check "descriptive_local_name" {
  # One or more assert blocks
  assert {
    condition     = # boolean expression
    error_message = # string displayed if condition is false
  }
}
  • **condition**: A boolean expression. If true, the assertion passes. If false, it fails.
  • error_message: A clear message explaining the failure, supporting interpolation for dynamic values.

Practical Examples

Example 1: Validating TLS Certificate Status

Ensure an AWS ACM certificate is in the ISSUED state.

resource "aws_acm_certificate" "cert" {
  domain_name       = "myapp.example.com"
  validation_method = "DNS"
  # ... other configurations
}
 
check "certificate_is_issued" {
  assert {
    condition     = aws_acm_certificate.cert.status == "ISSUED"
    error_message = "The certificate for ${aws_acm_certificate.cert.domain_name} is not ISSUED. Current status: ${aws_acm_certificate.cert.status}."
  }
}

Example 2: Verifying Service Endpoint Responsiveness

Use a scoped http data source to check if a service endpoint returns a 200 OK status.

resource "aws_lb" "app_lb" {
  # ... load balancer configuration ...
  name = "my-app-lb"
}
 
check "service_endpoint_health" {
  # Scoped data source, only visible within this check block
  data "http" "health_check" {
    url = "https://${aws_lb.app_lb.dns_name}/health"
    # In production, ensure you have valid certificates and set insecure = false
    # For this example, we might use insecure if it's an internal or test endpoint
    insecure = true 
    
    # Ensure this data source is queried only after the LB is available
    depends_on = [aws_lb.app_lb] 
  }
 
  assert {
    condition     = data.http.health_check.status_code == 200
    error_message = "Service endpoint at ${data.http.health_check.url} did not return HTTP 200. Status: ${data.http.health_check.status_code}."
  }
}

Note on Scoped data Sources: Data sources defined inside a check block are "scoped" to that block. If a provider error occurs during data retrieval (e.g., network issue), it's masked as a warning, aligning with the non-blocking nature of check blocks. The depends_on meta-argument is crucial for ensuring data sources are queried only after dependent resources are created/updated.

Execution Flow and Behavior

  • Evaluation Point: check blocks are evaluated at the end of terraform plan and terraform apply.
  • "Known After Apply": If a check's condition depends on attributes unknown until after apply (e.g., a new VM's IP), Terraform issues a warning that the result is "known after apply." The actual outcome is reported post-apply.
  • Outcomes: Passing checks are recorded in the state file. Failing checks produce warnings in the CLI output with the error_message.

HCP Terraform Plus Edition enhances this with "health assessments," automating check block evaluations and providing notifications, which is a step towards proactive governance.

3. Terraform check Blocks vs. Other Native Validation

Terraform has several native validation mechanisms, and they don't overlap as much as you might expect. Here's how check blocks line up against the others:

Feature Scope of Validation Execution Point Behavior on Failure Typical Use Cases Provider Interaction
terraform validate Static config files (syntax, schema) CLI command (before plan/apply) Error & Halt Syntax checking, basic type validation No
Input Variable Validation Individual input variable values During variable processing (before plan) Error & Halt Ensuring variable format/constraints (regex, length) No
Resource precondition State/attributes for a single resource Before resource operation (create/update/delete) Error & Halt Gatekeeping resource changes Yes (resource data)
Resource postcondition Outcome of a single resource operation After resource operation (create/update/delete) Error & Halt Verifying immediate result of a resource change Yes (resource data)
check Block Entire config, inter-resource relations, external systems End of plan/apply; HCP Health Assessments Warning & Continue Ongoing health checks, operational states, integrations, compliance assertions Via scoped data sources

Each row has a job it's suited to. check blocks trade enforcement for breadth: they warn rather than block, but they can look across resources and external systems in a way the other mechanisms can't. When you need a change actually stopped, you reach for policy-driven enforcement instead.

4. The Broader Terraform Validation Ecosystem

Native features only go so far. Most teams pair them with a few external tools:

  • terraform validate: The foundational static analysis check.
  • TFLint: A linter for best practices, potential bugs, and provider-specific issues (e.g., invalid instance types) that validate might miss.
  • Checkov / TFSec: Static analysis tools for security misconfigurations and compliance violations against standards like CIS Benchmarks, HIPAA, PCI-DSS.
  • Open Policy Agent (OPA) / HashiCorp Sentinel: Policy-as-code frameworks for advanced, customizable governance. OPA uses Rego, while Sentinel is integrated into HCP Terraform and Terraform Enterprise, offering fine-grained policy enforcement.

The tools themselves are capable. The hard part is wiring them into every pipeline and keeping them applied the same way across dozens of projects and teams. That's where an automation and management platform like Scalr helps: it gives you one place to define policy, enforce it, and see what's passing or failing, instead of configuring each tool per workspace.

5. Strategic Implementation: Best Practices

  • Ideal Use Cases for check Blocks:
    • Verifying operational states (e.g., database accessible, web server responding).
    • Checking integrations (e.g., load balancer targets are healthy).
    • Validating external dependencies via data sources.
    • Confirming runtime assumptions.
  • Develop a Layered Validation Strategy:
    1. Local Development: terraform fmt, validate, IDE integration, pre-commit hooks with linters/scanners.
    2. CI/CD Pipeline: Static analysis (TFLint, Checkov), policy enforcement (OPA/Sentinel), plan review (including check warnings), apply review.
    3. Continuous Monitoring: HCP Terraform health assessments or custom solutions for ongoing check block evaluation.
  • Craft Effective and Maintainable Assertions:
    • Write clear, actionable error_messages.
    • Keep conditions focused.
    • Test check blocks thoroughly.
    • Document and version control check blocks with your IaC.
  • Integrate into CI/CD Pipelines: Automate every validation step so it runs the same way each time. Pipeline logic can act on check block warnings, for example pausing for review or firing an alert. A platform with built-in execution environments takes most of the manual wiring off your plate here.

6. Towards Proactive and Reliable Infrastructure

check blocks are a solid addition to the validation toolkit. They give you an HCL-native way to assert things about your infrastructure's state, and they run with every plan and apply without any extra machinery.

They aren't the whole story, though. A real validation strategy combines native Terraform features with linters, security scanners, and a policy-as-code engine, and it treats those checks as code you keep refining as you learn what actually breaks in production.

At scale the harder problem isn't picking the tools. It's governance: applying policy the same way everywhere, seeing across all your environments at once, and not drowning in the upkeep of the validation pipelines themselves. An IaC management platform exists to handle that layer, so a multi-tool validation strategy stays consistent instead of fragmenting per team.

Concretely, that visibility takes the form of fleet-level reporting. Scalr is a drop-in Terraform Cloud alternative, and its reports treat drift, stale workspaces, and resource, module, and provider inventories as queryable objects across the whole fleet. A platform team can see where a check warning is going unaddressed and step in, instead of discovering it workspace by workspace.

About the author
Sebastian StadilCEO at Scalr
Sebastian Stadil is the CEO of Scalr with 15+ years of DevOps experience. He started with AWS in 2004 and advised early Microsoft Azure and Google Cloud.