1.6.6.1. tflint
tflint is an extensible, plugin-based static analysis tool (Linter) for Terraform code, designed to help developers and platform teams improve the quality, security, and consistency of Terraform configurations in Infrastructure as Code (IaC) practices. Through multiple plugin mechanisms, tflint supports linting rules for mainstream cloud platforms (such as AWS, Azure, GCP) as well as the Terraform language itself, enabling the discovery of configuration errors, potential risks, and non-standard usage. It provides an automated foundation for teams to enforce governance policies, best practices, and compliance checks.
In large-scale Terraform module governance scenarios, tflint acts as a "gatekeeper": it automatically detects common configuration errors (such as unused variables, deprecated resource usage, missing tags on resources, etc.), enforces naming and structural conventions, identifies security and cost risks in time, thereby significantly reducing code review burden, improving delivery efficiency, and reducing the probability of production incidents.
1.6.6.1.1. Key Features and Scenarios
The design of tflint fully considers flexibility and extensibility. Its core features include:
- Multi-cloud support and rich rule plugins:
tflintsupports specialized rules for major public cloud resources like AWS, Azure, and GCP through plugin mechanisms, automatically validates instance types, resource attributes, default values, etc. It can not only detect syntax-level issues but also perform deep validation based on actual cloud service constraints. - Terraform language rules: Built-in support for Terraform language specification checks, including identifying deprecated syntax, unused declarations, variable assignment issues, etc., helping teams maintain clean and maintainable code.
- Custom extension capabilities: Users can extend rules through custom plugins or Rego Policy files to implement enterprise-specific compliance requirements or organizational best practices.
- Enforcement of naming conventions and best practices: Through rule plugins and configurations,
tflintcan enforce resource naming, variable naming, and other conventions, effectively supporting standardized governance in large-scale multi-team collaboration. - Integration with CI/CD and development toolchain:
tflintsupports execution in various environments including local development, GitHub Actions, Docker containers, etc., facilitating governance implementation in automated processes such as PR checks and continuous integration pipelines.
tflint is particularly suitable for the following scenarios:
- Standardization and compliance governance of enterprise-level infrastructure code
- Quality assurance of Terraform code in multi-team, multi-project collaboration
- Automated code review and "Shift Left" security best practices
- Preventive validation of cloud platform resource configuration and cost risk control
1.6.6.1.2. Is Terraform's Built-in Validation Not Enough?
With the popularization of Infrastructure as Code and the widespread application of Terraform in cloud-native infrastructure management, organizations face multiple challenges including module reuse, team collaboration, and compliance management. Although Terraform itself has built-in validation mechanisms such as terraform validate and terraform plan, they primarily focus on syntax and basic semantic levels, making it difficult to cover the complex rules and best practice constraints required for enterprise-level governance.
tflint complements the shortcomings of official tools. It can:
- Automatically expose errors and non-standard usage early in code writing, reducing later rework costs
- Unify team code style and structure, improving module reusability and maintainability
- Automatically detect resource types, parameter validity, variable usage, and other business rules, preventing production incidents
- Support custom enterprise-internal rules, effectively supporting compliance and security requirements implementation
In short, tflint is like golangci-lint, helping us locate code that is syntactically correct but may cause other problems or has been marked as deprecated.
1.6.6.1.3. How to Use tflint
1.6.6.1.3.1. Installation
tflint supports multi-platform installation. Common methods are as follows:
- Linux:
curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash
- macOS:
brew install tflint
- Windows:
choco install tflint
- Docker Container:
docker run --rm -v $(pwd):/data -t ghcr.io/terraform-linters/tflint
Additionally, tflint also supports automated integration through GitHub Actions:
name: Lint
on:
push:
branches: [ master ]
pull_request:
jobs:
tflint:
runs-on: $
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
name: Checkout source code
...
- uses: terraform-linters/setup-tflint@v4
name: Setup TFLint
with:
tflint_version: v0.52.0
- name: Show version
run: tflint --version
- name: Init TFLint
run: tflint --init
env:
# https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md#avoiding-rate-limiting
GITHUB_TOKEN: $
- name: Run TFLint
run: tflint -f compact
1.6.6.1.3.2. Quick Start
Initialize configuration file
Create a .tflint.hcl file in the project root directory to define required plugins and rules. For example:
plugin "terraform" {
enabled = true
preset = "recommended"
}
For cloud platforms, you can combine with corresponding plugins:
plugin "aws" {
enabled = true
version = "0.19.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
Install plugins
tflint --init
Similar to Terraform, tflint also implements a plugin mechanism using HashiCorp's go-plugin. The source in the plugin "aws" section above indicates where to download the plugin. Therefore, similar to Terraform, before running the tflint command, you need to first run tflint --init to download the plugins.
Code inspection
Execute directly in the project root directory:
tflint
tflint will scan all Terraform code in the current directory and output all discovered issues. It supports rich command-line parameters to customize behavior, such as recursive scanning, multiple output formats (json, junit, sarif, etc.), specifying configuration files, auto-fixing certain issues, etc.
Integrate into CI/CD
You can integrate tflint into development and deployment pipelines through official GitHub Actions, Makefile, shell scripts, or Docker containers to ensure that every code change is subject to automated checks.
1.6.6.1.3.3. Advanced Usage
- Support for enabling/disabling rules, plugin customization, variable file specification, multi-directory recursive scanning, etc.
- You can view detailed logs through environment variable
TFLINT_LOG=debugto assist with debugging and troubleshooting.
1.6.6.1.4. Calling tflint in AVM
AVM provides the following script:
#!/usr/bin/env bash
set_tflint_config() {
local env_var=$1
local override_file=$2
local default_url=$3
local download_file=$4
local merged_file=$5
# Always download the file from GitHub
curl -H 'Cache-Control: no-cache, no-store' -sSL "$default_url" -o "$download_file"
# Check if the override file exists
if [ -f "$override_file" ]; then
# If it does, merge the override file and the downloaded file
hclmerge -1 "$override_file" -2 "$download_file" -d "$merged_file"
# Set the environment variable to the path of the merged file
export $env_var="$merged_file"
else
# If it doesn't, set the environment variable to the path of the downloaded file
export $env_var="$download_file"
fi
}
set_tflint_config "TFLINT_CONFIG" "avm.tflint.override.hcl" "https://raw.githubusercontent.com/Azure/tfmod-scaffold/main/avm.tflint.hcl" "avm.tflint.hcl" "avm.tflint.merged.hcl"
set_tflint_config "TFLINT_MODULE_CONFIG" "avm.tflint_module.override.hcl" "https://raw.githubusercontent.com/Azure/tfmod-scaffold/main/avm.tflint_module.hcl" "avm.tflint_module.hcl" "avm.tflint_module.merged.hcl"
set_tflint_config "TFLINT_EXAMPLE_CONFIG" "avm.tflint_example.override.hcl" "https://raw.githubusercontent.com/Azure/tfmod-scaffold/main/avm.tflint_example.hcl" "avm.tflint_example.hcl" "avm.tflint_example.merged.hcl"
configPathRoot=$(pwd)/$TFLINT_CONFIG
configPathModule=$(pwd)/$TFLINT_MODULE_CONFIG
configPathExample=$(pwd)/$TFLINT_EXAMPLE_CONFIG
run_tflint () {
local dir=$1
local config=$2
local moduleType=$3
local currentDir=$(pwd)
cd $dir
echo "==> Running tflint for $moduleType $dir"
tflint --init --config=$config
tflint --config=$config --minimum-failure-severity=warning
local result=$?
cd $currentDir
if [ $result -ne 0 ]; then
echo "------------------------------------------------"
echo ""
echo "The $moduleType $dir contains terraform blocks that do not comply with tflint requirements."
echo ""
return 1
fi
return 0
}
set -eo pipefail
echo "==> Copy module to temp dir..."
RND="$RANDOM"
TMPDIR="/tmp/avmtester$RND"
cp -r . "$TMPDIR"
cd "$TMPDIR"
# clean up terraform files
find -type d -name .terraform -print0 | xargs -0 rm -rf
find -type f -name .terraform.lock.hcl -print0 | xargs -0 rm -rf
find -type f -name 'terraform.tfstate*' -print0 | xargs -0 rm -rf
set +eo pipefail
has_error=false
echo "==> Checking that root module complies with tflint requirements..."
run_tflint . $configPathRoot "root module"
result=$?
if [ $result -ne 0 ]; then
has_error=true
fi
echo "==> Checking that sub modules comply with tflint requirements..."
if [ ! -d "modules" ]; then
echo "===> No modules folder, skip lint module code"
else
cd modules
dirs=$(find . -maxdepth 1 -mindepth 1 -type d)
for d in $dirs; do
run_tflint $d $configPathModule "sub module"
result=$?
if [ $result -ne 0 ]; then
has_error=true
fi
done
cd ..
fi
echo "==> Checking that examples comply with tflint requirements..."
if [ ! -d "examples" ]; then
echo "===> No examples folder, skip lint example code"
else
cd examples
dirs=$(find . -maxdepth 1 -mindepth 1 -type d)
for d in $dirs; do
run_tflint $d $configPathExample "example"
result=$?
if [ $result -ne 0 ]; then
has_error=true
fi
done
cd ..
fi
if ${has_error}; then
echo "------------------------------------------------"
echo ""
echo "The preceding files contain terraform blocks that do not comply with tflint requirements."
echo ""
exit 1
fi
exit 0
It's important to note that AVM checks three types of Terraform code with tflint: module code, examples code, and sub-module modules code. Different checking strategies can be specified for these three types of code. For example, we believe that examples code does not need to enforce all output blocks declaring a description. AVM provides a default avm.tflint_example.hcl which defines:
rule "terraform_documented_outputs" {
enabled = false
}
If module maintainers want to make some adjustments based on the default rule configuration, for example, if we want to allow output blocks in the current module code without declaring a description (this is strongly discouraged), we can add a file named avm.tflint.override.hcl in the current module repository containing the terraform_documented_outputs block declared above. The AVM CI pipeline will merge the configuration in this override.hcl file into the default configuration when running (the script uses the tool hclmerge).
1.6.6.1.5. Summary
tflint is an indispensable automated tool for large-scale Terraform module governance. It combines a flexible plugin extension mechanism, rich rule sets, and highly customizable checking capabilities, significantly improving the quality, security, and team collaboration efficiency of infrastructure code. Whether for single projects or enterprise-level multi-team governance, tflint provides solid support for standardization, compliance, and efficient delivery of Terraform code.