Terraform format, validate, and linting for red team operators
Learn how to keep Terraform code clean, consistent, and error-free using terraform fmt, terraform validate, tflint, and pre-commit hooks.
As we build and manage infrastructure using Terraform, maintaining clean, consistent, and error-free code becomes essential—not just for efficiency, but also for operational security and collaboration. In this post, I cover three tools that help maintain Terraform code quality: terraform fmt
, terraform validate
, and tflint
. Together, they ensure Terraform configurations are properly formatted, syntactically correct, and follow best practices. I also introduce pre-commit hooks to automate these checks.
Formatting with terraform fmt
Terraform provides a built-in formatter called terraform fmt
. This tool ensures all .tf
files follow canonical formatting, which is the standard way Terraform expects the code to be structured and styled. Canonical formatting removes unnecessary whitespace, aligns equal signs in arguments, and enforces indentation so that the configuration is easy to read and visually consistent across files and contributors.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.
To use terraform fmt
, navigate to the root of your Terraform project and run:
terraform fmt -recursive
The -recursive
flag ensures that even files in subdirectories are formatted, which is especially useful if you're using modules or structuring your infrastructure across multiple environments.
To check formatting without actually modifying the files use:
terraform fmt -check -recursive
This command will return a non-zero exit code if any file isn’t properly formatted, which can be used to block merges or raise alerts during code reviews.
Validating configuration with terraform validate
After formatting, it’s important to verify that the configuration is syntactically valid. The terraform validate
command checks the structure and internal consistency of Terraform files. It ensures that variables and resource blocks are defined properly, module paths are valid, and there are no typos in provider configurations.
For example:
terraform validate
This command checks whether the Terraform configuration is syntactically valid and internally consistent. For example, it verifies that all referenced variables and resources exist, that module paths are valid, and that provider settings are correct. However, it does not connect to cloud APIs or verify actual infrastructure.
In earlier posts, especially when working with modules and remote backends, even a small mistake—such as a misspelled module path or a missing variable—can break a deployment. terraform validate
helps catch such issues early, before running plan
or apply
.
Note:
terraform validate
is different fromvalidation
blocks that can be defined within avariable
block.terraform validate
is a command used to check your code as a whole, whilevalidation
blocks are part of input variable definitions that enforce rules about what values can be passed to a specific variable. Both are useful, but they serve different purposes.
Catching mistakes with tflint
While terraform fmt
and validate
ensure code style and syntax, they don’t catch semantic issues or deviations from best practices. This is where TFLint comes in. TFLint is a linter for Terraform that analyzes code for potential errors, performance issues, bad practices, security risks, and deviations from style guidelines. It supports a wide range of plugins, including provider-specific checks (like AWS, Azure, or GCP), making it a valuable tool in any Terraform workflow.
Install TFLint by following instructions from https://github.com/terraform-linters/tflint, and then simply run:
tflint
TFLint might highlight unused variables, deprecated syntax, incorrect attribute names, or even provider-specific warnings. For instance, in AWS-based red team infrastructure, it may warn if a security group allows overly broad inbound access or if an instance type is unsupported in a particular region.
To customize TFLint behavior, create a .tflint.hcl
file in your repo:
plugin "terraform" {
enabled = true
preset = "recommended"
}
plugin "aws" {
enabled = true
version = "0.39.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
To install the AWS plugin, run:
tflint --init
Automating with pre-commit hooks
Manually running formatters and linters can be tedious. Automating these tasks with pre-commit hooks ensures code quality checks happen automatically. A pre-commit hook is a script that runs automatically before a commit is made to a version control system like Git. This means when someone tries to save their changes to the repository, the hook will check the code before the commit is accepted.
Note: A "commit" here refers to saving a set of changes to a Git repository, not just saving a file locally. The hook will run when you use
git commit
.
The pre-commit framework allows defining hooks in a .pre-commit-config.yaml
file. A typical Terraform setup might look like
Pre-commit hooks are managed using the pre-commit framework. First, create a file named .pre-commit-config.yaml
in the root of your repository:
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.77.0
hooks:
- id: terraform_fmt
- id: terraform_validate
- repo: local
hooks:
- id: tflint
name: tflint
entry: tflint
language: system
types: [terraform]
Then, install and enable the hooks:
pip install pre-commit
pre-commit install
pre-commit run --all-files
Note: On Windows, run
pre-commit run --all-files
using Git Bash or WSL, as some hooks rely on Unix shell scripts and won’t work in Command Prompt or PowerShell.
After this setup, every time you run git commit
, the hooks will automatically:
Format the Terraform files (
terraform fmt
)Validate the configuration (
terraform validate
)Lint the code (
tflint
)
If any of these checks fail, the commit will be blocked until the issues are fixed. This ensures that no broken or inconsistent Terraform code gets pushed to the shared repository.
Why this matters in red team operations
Catch misconfigurations (like wrong variable names or missing modules) before they cause issues mid-operation.
When multiple operators work on infrastructure, formatting and linting prevent code conflicts and confusion.
Linting tools can detect risky patterns (like overly permissive security groups) that might increase detection.
Clean, validated code is easier to audit and troubleshoot when things go wrong.
Infrastructure is part of tradecraft—keeping it clean and consistent is just as important as writing secure implants or crafting payloads.
TL;DR
- terraform fmt automatically formats Terraform code to follow canonical style.
- terraform validate checks the configuration for syntax errors and internal consistency.
- tflint acts as a linter to detect potential issues, enforce best practices, and catch provider-specific problems.
- Pre-commit hooks automate these checks before every Git commit to maintain clean and reliable infrastructure code.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.