← All Posts
DevOps17 Jun 2026·14 min read

Terraform Ecosystem: Terragrunt, Terrascan & More

Srinivasa Rao Maganti — Lead Cloud & DevOps Trainer at CloudTechTrainings

Srinivasa Rao Maganti

Cloud Architect & Lead Trainer, CloudTechTrainings

#Terraform#Terragrunt#Terrascan#DevOps#Infrastructure as Code#IaC Security

Every team starts with Terraform and writes clean infrastructure code. Then the project grows: three environments, five engineers, a dozen modules — and suddenly state conflicts, security misconfigurations, and runaway cloud costs appear. Terraform is a foundation, not a complete quality system. This guide covers the six tools that fill those gaps and shows how to wire them into a CI/CD pipeline that enforces quality at every stage.

93%
of enterprises use or plan to use Terraform
500+
built-in security policies in Terrascan
38%
of cloud breaches trace back to IaC misconfig
5 sec
to catch a lint error vs days in production

The Gap: What Raw Terraform Does Not Give You

Terraform handles provisioning elegantly. It does not protect you from the things that cause production incidents:

  • Duplicated provider and backend blocks across every module directory — Terragrunt eliminates this
  • Publicly accessible storage, unencrypted disks, open firewall rules — Terrascan and Checkov catch these before apply
  • Wrong variable types, deprecated resource arguments, unused locals — tflint surfaces them in seconds
  • A terraform apply that triples your monthly cloud bill — Infracost shows the cost before you commit
  • Modules no-one outside the original author understands — terraform-docs keeps them documented automatically

1. Terragrunt — DRY Infrastructure at Scale

Terragrunt is a thin wrapper around Terraform that eliminates repetition across large codebases. Instead of copying the provider block and remote state configuration into every module directory, you define them once in a root terragrunt.hcl and every child module inherits them automatically. It also adds run-all commands that plan and apply multiple modules in the correct dependency order.

hcl
# root/terragrunt.hcl — defined once, inherited by every child module
remote_state {
  backend = "azurerm"
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
  config = {
    resource_group_name  = "rg-terraform-state"
    storage_account_name = "cttterraformstate"
    container_name       = "tfstate"
    key                  = "${path_relative_to_include()}/terraform.tfstate"
  }
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.100"
    }
  }
}
provider "azurerm" { features {} }
EOF
}
hcl
# environments/dev/networking/terragrunt.hcl — child module
include "root" {
  path = find_in_parent_folders()
}

dependency "resource_group" {
  config_path = "../resource-group"
}

inputs = {
  resource_group_name = dependency.resource_group.outputs.name
  location            = "East US"
  vnet_address_space  = ["10.0.0.0/16"]
}

Tip: run-all for multi-module environments

Use "terragrunt run-all plan" to plan every module in an environment in the correct dependency order. Terragrunt reads the dependency blocks, sequences operations automatically, and eliminates the manual ordering problem that plagues large Terraform monorepos.

2. tflint — Catch Errors Before terraform plan

tflint is a Terraform linter that catches the errors terraform validate misses: incorrect variable types, deprecated resource arguments, provider-specific rule violations like invalid Azure VM SKUs or region names, and unused declarations. It runs in seconds and should be the first check in any CI pipeline.

hcl
# .tflint.hcl — place at the root of your Terraform project
plugin "azurerm" {
  enabled = true
  version = "0.26.0"
  source  = "github.com/terraform-linters/tflint-ruleset-azurerm"
}

rule "terraform_unused_declarations" { enabled = true }
rule "terraform_deprecated_index"     { enabled = true }
rule "terraform_required_version"     { enabled = true }
rule "terraform_naming_convention" {
  enabled  = true
  variable { format = "snake_case" }
  resource { format = "snake_case" }
}
bash
# Initialise plugins then run the linter
tflint --init
tflint --recursive

# Example output
# [ERROR] resource "azurerm_virtual_machine" is deprecated.
#         Use "azurerm_linux_virtual_machine" instead.  main.tf:12
# [WARNING] Variable "vmSize" is not in snake_case format.  variables.tf:5
# [ERROR] "Standard_A0" is not a valid VM size for "size".  main.tf:28
  • Catches deprecated resource types before they cause plan failures
  • Provider-specific rules validate actual Azure VM sizes, region names, and SKUs against the live Azure API
  • Enforces naming conventions and code style rules across the whole codebase
  • Runs in under 10 seconds — fast enough to gate every single commit

3. Terrascan — Security Policy Scanning for IaC

Terrascan by Tenable scans Terraform code against 500+ built-in security policies mapped to CIS benchmarks, NIST, SOC 2, and PCI-DSS. It detects misconfigurations such as publicly accessible storage accounts, missing disk encryption on VMs, overly permissive firewall rules, and disabled diagnostic logging — all before any resource is provisioned.

bash
# Install Terrascan (macOS / Linux)
brew install terrascan

# Scan an Azure Terraform project
terrascan scan -i terraform -t azure --iac-dir ./infrastructure

# JSON output for CI reporting and dashboards
terrascan scan -i terraform -t azure -o json > terrascan-report.json

# Fail the pipeline on any HIGH severity finding
terrascan scan -i terraform -t azure --severity HIGH
yaml
# Sample Terrascan output (abbreviated)
Violations:
  - rule_name: "azureStorageAccountBlobPublicAccessDisabled"
    description: "Ensure blob public access is disabled on storage accounts"
    severity: "HIGH"
    resource: "azurerm_storage_account.main"
    file: "storage.tf"
    line: 14
    reference_id: "AC_AZURE_0389"

  - rule_name: "azureVMDiskEncryptionEnabled"
    description: "Ensure Azure VM data disks use Azure Disk Encryption"
    severity: "MEDIUM"
    resource: "azurerm_linux_virtual_machine.app"
    file: "compute.tf"
    line: 31

Warning: Most common Terrascan findings on Azure

Public blob access enabled on Storage Accounts, missing disk encryption on VMs, Network Security Groups with inbound 0.0.0.0/0 on ports 22 or 3389, Key Vault soft delete disabled, and Activity Log profiles missing. All of these are caught before terraform apply runs.

4. Checkov — Policy-as-Code with Custom Rules

Checkov by Bridgecrew scans Terraform, ARM templates, Kubernetes manifests, Dockerfiles, and CI/CD pipelines from a single tool. Its key strength over Terrascan is custom policies — you write checks in Python or YAML to enforce your organisation's specific standards alongside 1,000+ built-in rules.

bash
# Install Checkov
pip install checkov

# Scan a Terraform directory
checkov -d ./infrastructure --framework terraform

# Show only failures (suppress passed checks)
checkov -d . --framework terraform --compact --quiet

# Enforce a specific compliance standard
checkov -d . --framework terraform --check CIS_AZURE_2.0
yaml
# .checkov-custom/require_tags.yaml — enforce mandatory tags on all resources
metadata:
  name: "require-mandatory-tags"
  id: "CKV_CUSTOM_1"
  category: "GENERAL_SECURITY"

scope:
  provider: azurerm

definition:
  and:
    - cond_type: "attribute"
      resource_types:
        - "azurerm_resource_group"
        - "azurerm_storage_account"
      attribute: "tags.environment"
      operator: "exists"
    - cond_type: "attribute"
      resource_types:
        - "azurerm_resource_group"
      attribute: "tags.cost_center"
      operator: "exists"

Tip: Checkov vs Terrascan — run both

They have overlapping but distinct rule sets. Checkov's custom YAML policies are ideal for enforcing organisation-specific tagging, naming conventions, and compliance standards. Terrascan has stronger CIS benchmark coverage and cleaner SARIF output for GitHub Code Scanning. Running both in CI takes under 2 minutes and gives broader coverage than either alone.

5. Infracost — Know the Cost Before You Apply

Infracost analyses your Terraform plan and estimates the monthly cloud cost before a single resource is created. Integrated into a pull request pipeline, it automatically posts a cost diff comment showing exactly how much a change adds or saves — turning cost awareness into a standard part of code review instead of a surprise at month-end billing.

bash
# Install Infracost and authenticate (free API key from infracost.io)
brew install infracost
infracost auth login

# Full cost breakdown for the Terraform project
infracost breakdown --path ./infrastructure

# Cost difference versus the main branch
infracost diff \
  --path ./infrastructure \
  --compare-to /tmp/infracost-main.json

# Sample output
# Monthly cost will increase by $847 (+312%)
#   + azurerm_linux_virtual_machine.app   $234/month
#   + azurerm_mssql_database.prod         $613/month
#   ~ azurerm_storage_account.main        $0 (no change)

Info: Automatic cost comment on every pull request

Add the Infracost GitHub Action to your workflow and every PR gets a posted comment showing the monthly cost impact before review. Engineers see cost implications at code review time, not when the bill arrives at the end of the month.

6. terraform-docs — Auto-Generate Module Documentation

terraform-docs reads your Terraform variables, outputs, and resources and generates clean Markdown documentation automatically. Combined with a pre-commit hook, it keeps the module README in sync with the code without any manual effort — every input variable and output is always documented.

yaml
# .terraform-docs.yml — place at the root of the module
formatter: "markdown table"

sections:
  show:
    - inputs
    - outputs
    - resources
    - providers

output:
  file: "README.md"
  mode: inject        # inserts between <!-- BEGIN_TF_DOCS --> markers
  template: |-
    # Module: {{ .Module.Name }}

    {{ .Content }}
yaml
# .pre-commit-config.yaml — keeps README.md in sync on every commit
repos:
  - repo: https://github.com/terraform-docs/terraform-docs
    rev: v0.18.0
    hooks:
      - id: terraform-docs-go
        args: ["--output-file", "README.md", "."]

Wiring Everything Into a CI/CD Quality Gate

The real power of these tools is in combination — each stage catches a different class of problem. Here is a complete GitHub Actions workflow that runs the full quality gate on every pull request touching the infrastructure directory:

yaml
# .github/workflows/terraform-quality.yml
name: Terraform Quality Gate

on:
  pull_request:
    paths: ["infrastructure/**"]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 1. Format — fail if any .tf file is not formatted
      - name: Terraform Format Check
        run: terraform fmt -check -recursive ./infrastructure

      # 2. Lint — catch type errors, deprecated args, naming violations
      - name: Setup tflint
        uses: terraform-linters/setup-tflint@v4
      - name: Run tflint
        run: |
          tflint --init
          tflint --recursive ./infrastructure

      # 3. Security scan — fail on HIGH severity findings
      - name: Terrascan
        uses: tenable/terrascan-action@main
        with:
          iac_type: terraform
          iac_dir: infrastructure
          policy_type: azure
          only_warn: false

      # 4. Policy compliance — includes custom organisation rules
      - name: Checkov
        uses: bridgecrewio/checkov-action@master
        with:
          directory: infrastructure
          framework: terraform
          external_checks_dir: .checkov-custom
          soft_fail: false

      # 5. Cost estimation — posts a diff comment on the PR
      - name: Setup Infracost
        uses: infracost/actions/setup@v3
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}
      - name: Post cost diff to PR
        run: |
          infracost breakdown \
            --path ./infrastructure \
            --format json \
            --out-file /tmp/infracost.json
          infracost comment github \
            --path /tmp/infracost.json \
            --repo $GITHUB_REPOSITORY \
            --pull-request ${{ github.event.pull_request.number }} \
            --github-token ${{ secrets.GITHUB_TOKEN }}

Tool Comparison at a Glance

ToolPurposeWhen It RunsWhat It CatchesFree?
TerragruntDRY wrapper + orchestrationLocal + CI deployState conflicts, code duplicationYes
tflintTerraform lintingPre-commit + CIType errors, deprecated args, namingYes
TerrascanSecurity policy scanningCI — before planCIS / NIST / PCI misconfigsYes
CheckovPolicy-as-code complianceCI — before planCompliance + custom org rulesYes (OSS)
InfracostCloud cost estimationCI — after planUnexpected cost increasesFree tier
terraform-docsAuto documentationPre-commit hookUndocumented modules / variablesYes

Quality Gates in the Right Order

A mature Terraform workflow runs these checks in layers — each stage builds on the last and fails fast before reaching the expensive operations:

  1. 1terraform fmt — enforces consistent code style, runs in under a second
  2. 2tflint — catches syntax and provider-specific errors before any cloud API call
  3. 3terraform validate — verifies the configuration is internally consistent
  4. 4Terrascan + Checkov — security and compliance gate, blocks HIGH findings before plan
  5. 5terraform plan — generates the execution plan (Infracost analyses this output)
  6. 6Infracost — posts cost diff to the PR; optionally blocks if the monthly delta exceeds a threshold
  7. 7Manual code review — engineer approves with full security and cost context visible
  8. 8terraform apply — only runs after every gate passes and the PR is approved

Note: Shift-left IaC quality

The goal is to fail fast and cheap. A tflint error caught in 5 seconds costs nothing to fix. A misconfigured Security Group discovered in a production security audit costs days of remediation and potential data exposure. Every tool in this list exists to move that feedback as early as possible.

Learn the Full Stack in Our DevOps Programme

Our DevOps course covers the complete Terraform workflow end-to-end: writing HCL, managing remote state in Azure Blob Storage, structuring Terragrunt modules, and running a full quality pipeline with tflint, Terrascan, Checkov, and Infracost inside Azure Pipelines and GitHub Actions. You finish with a working multi-environment Terragrunt project that mirrors real enterprise setups — not a toy hello-world example.

See the full curriculum on the DevOps course page, or benchmark yourself first with the free Terraform TF-003 mock exam.

Official documentation

Prove Your Terraform Skills

Ready to Start Your Cloud Journey?

Live batches Mon–Sat — Azure 9–10 AM IST (starts 3 august 2026) · AWS 10:30–11:45 AM IST (starts 31 august 2026). Hands-on labs, exam prep, and community support.

Join Free Demo →WhatsApp Us

Keep Reading

DevOps

DevOps Training in Hyderabad — Live Online Course

Looking for DevOps training in Hyderabad? This guide covers what a DevOps engineering course covers, which tools you'll learn, target certifications (TF-003, AZ-400, CKA), and how to choose the right program.

25 Jun 2026·8 min read
Read →
DevOps

DevOps in 2026: 6 Trends Reshaping Enterprise IT

Platform engineering, AI-augmented pipelines, GitOps at scale, supply chain security, FinOps integration, and OpenTelemetry — the DevOps landscape has shifted from CI/CD basics to enterprise-grade platform thinking. Here is what businesses are actually demanding from their DevOps engineers in 2026.

22 Jun 2026·14 min read
Read →