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: tflint supports 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, tflint can 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: tflint supports 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=debug to 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.

results matching ""

    No results matching ""