Introduction

Terraform has become the standard for infrastructure as code, but managing Terraform at scale requires additional tools. Terragrunt reduces configuration duplication. Terratest enables automated infrastructure testing. Tfsec scans configurations for security issues. Infracost provides cost estimates before deployment. This article covers each tool with practical examples.

Terraform Tools: Terragrunt, terratest, tfsec, Infracost

Terragrunt

A thin wrapper that keeps Terraform configurations DRY:

terragrunt.hcl (root configuration)

remote_state {

backend = "s3"

config = {

bucket = "my-company-terraform-state"

key = "${path_relative_to_include()}/terraform.tfstate"

region = "us-east-1"

encrypt = true

dynamodb_table = "terraform-locks"

}

}

generate "provider" {

path = "provider.tf"

if_exists = "overwrite_terragrunt"

contents = <

provider "aws" {

region = local.aws_region

default_tags {

tags = {

Environment = local.environment

ManagedBy = "terragrunt"

}

}

}

EOF

}

locals {

aws_region = "us-east-1"

environment = reverse(split("/", get_terragrunt_dir()))[1]

}

dev/vpc/terragrunt.hcl

terraform {

source = "../../modules/vpc"

}

include "root" {

path = find_in_parent_folders()

}

inputs = {

vpc_name = "dev-vpc"

cidr_block = "10.0.0.0/16"

enable_nat = true

enable_vpn = false

private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]

public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]

}

Apply all modules in dependency order

terragrunt run-all apply

Plan only changed modules

terragrunt run-all plan

Output dependency graph

terragrunt graph | dot -Tpng > graph.png

Validate all configurations

terragrunt run-all validate

Destroy with confirmation

terragrunt run-all destroy

Terratest

Go library for writing automated infrastructure tests:

package test

import (

"testing"

"github.com/gruntwork-io/terratest/modules/terraform"

"github.com/gruntwork-io/terratest/modules/aws"

"github.com/stretchr/testify/assert"

)

func TestVPCDeployment(t *testing.T) {

terraformOptions := &terraform.Options;{

TerraformDir: "../examples/vpc",

Vars: map[string]interface{}{

"vpc_name": "test-vpc",

"cidr_block": "10.0.0.0/16",

},

NoColor: true,

}

// Clean up at the end

defer terraform.Destroy(t, terraformOptions)

// Deploy infrastructure

terraform.InitAndApply(t, terraformOptions)

// Verify outputs

vpcID := terraform.Output(t, terraformOptions, "vpc_id")

assert.NotEmpty(t, vpcID)

// Verify the VPC actually exists in AWS

vpc := aws.GetVpcById(t, vpcID, "us-east-1")

assert.Equal(t, "10.0.0.0/16", vpc.CidrBlock)

// Verify subnets were created

subnets := aws.GetSubnetsForVpc(t, vpcID, "us-east-1")

assert.Len(t, subnets, 4)

// Verify security group rules

sgID := terraform.Output(t, terraformOptions, "web_sg_id")

sgRules := aws.GetSecurityGroupRules(t, sgID, "us-east-1")

assert.GreaterOrEqual(t, len(sgRules), 2)

}

tfsec (now Trivy)

Security scanning for Terraform configurations:

Install tfsec

brew install tfsec

Or use Trivy which includes tfsec rules

brew install trivy

Scan Terraform files

tfsec .

tfsec ./environments/production

tfsec --no-color --format json > scan-results.json

In CI

tfsec --soft-fail # Don't fail CI, just report

Trivy equivalent

trivy config --severity HIGH,CRITICAL .

Bad configuration that tfsec catches

resource "aws_s3_bucket" "data" {

bucket = "my-data-bucket"

acl = "public-read" # tfsec: aws-s3-no-public-read-acl

}

resource "aws_security_group" "web" {

ingress {

from_port = 22

to_port = 22

protocol = "tcp"

cidr_blocks = ["0.0.0.0/0"] # tfsec: aws-vpc-no-public-ingress-sgr

}

}

Fixed configuration

resource "aws_s3_bucket" "data" {

bucket = "my-data-bucket"

acl = "private"

}

resource "aws_security_group" "web" {

ingress {

from_port = 22

to_port = 22

protocol = "tcp"

cidr_blocks = ["10.0.0.0/8"] # Restricted to internal network

}

}

Infracost

Cost estimation for Terraform projects:

Install

brew install infracost

infracost auth login

Generate cost estimate for current state

infracost breakdown --path .

Compare with previous state

infracost diff --path . --compare-to previous-cost.json

Output in different formats

infracost breakdown --path . --format json

infracost breakdown --path . --format html --out-file cost-report.html

In CI

infracost diff --path . --show-skipped

.infracost.yml — usage estimates

version: 0.1

projects:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- path: ./environments/production

usage:

aws_instance.web:

monthly_cpu_credit_hrs: 100

monthly_hrs: 730

aws_lambda.function:

monthly_requests: 1000000

request_duration_ms: 500

aws_s3_bucket.data:

storage_gb: 500

monthly_tier_1_requests: 10000

Other Essential Tools

pre-commit hooks for Terraform:

.pre-commit-config.yaml

repos:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- repo: https://github.com/antonbabenko/pre-commit-terraform

rev: v1.96.0

hooks:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- id: terraform_fmt

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- id: terraform_validate

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- id: terraform_tflint

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- id: terraform_trivy

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- id: terraform_docs

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\- id: checkov

Comparison

| Tool | Purpose | Essential For |

|------|---------|---------------|

| Terragrunt | DRY configuration | Multi-environment, multi-module projects |

| Terratest | Infrastructure testing | Automated validation of deployments |

| tfsec/Trivy | Security scanning | Catching misconfigurations before deploy |

| Infracost | Cost estimation | Budget planning and cost awareness |

| pre-commit | Code quality | Consistent formatting and validation |

Recommendations

  • Multi-environment IaC : Use Terragrunt to eliminate configuration duplication across environments.

  • Production safety : Use Terratest to write automated tests that verify infrastructure after deployment.

  • Security compliance : Run tfsec or Trivy in CI pipelines to catch misconfigurations before merge.

  • Cost awareness : Use Infracost in PR pipelines to show cost implications of infrastructure changes.

  • Code quality : Set up pre-commit hooks for terraform fmt, validate, tflint, and docs.

The ideal Terraform workflow combines all these tools: Terragrunt for structure, pre-commit for quality, tfssec for security, Infracost for cost awareness, and Terratest for deployment validation.