1.6.6.1. tflint

tflint 是一个可扩展的、插件化的 Terraform 代码静态分析工具(Linter),旨在帮助开发者和平台团队在基础设施即代码(IaC)实践中提升 Terraform 配置的质量、安全性和一致性。tflint 通过多种插件机制,支持主流云平台(如 AWS、Azure、GCP)以及 Terraform 语言本身的规则检查,能够发现配置中的错误、潜在风险与不规范用法,并为团队实施治理策略、最佳实践和合规性检查提供了自动化基础。

在大规模 Terraform 模块治理场景中,tflint 起到了“守门员”的作用:它能自动侦测常见配置错误(比如变量未使用、资源弃用用法、未为资源配置 tags 等),强制执行命名与结构规范,及时发现安全与成本风险,从而显著降低代码审查负担、提升交付效率、减少生产事故的概率。

1.6.6.1.1. 主要功能与场景

tflint 的设计充分考虑了灵活性与可扩展性,其核心特性包括:

  • 多云支持与丰富规则插件tflint 通过插件机制支持 AWS、Azure、GCP 等主流公有云资源的专属规则,自动校验如实例类型、资源属性、默认值等,不仅能检测语法层面的问题,还能结合云服务实际约束做深度校验。
  • Terraform 语言规则:内置支持 Terraform 语言本身的规范检查,包括识别废弃语法、未使用声明、变量赋值问题等,帮助团队维持代码整洁和可维护性。
  • 自定义扩展能力:用户可通过自定义插件或 Rego Policy 文件扩展规则,实现企业内部特殊合规要求或组织最佳实践落地。
  • 命名约定与最佳实践强制:通过规则插件和配置,tflint 可强制资源命名、变量命名等约定,有效支撑大规模多人协作下的标准化治理。
  • 与 CI/CD 和开发工具链集成tflint 支持在本地开发、GitHub Actions、Docker 容器等多种环境运行,便于在 PR 检查、持续集成流水线等自动化流程中实施治理。

tflint 特别适合以下场景:

  • 企业级基础设施代码的规范化与合规治理
  • 多团队、多项目协作下的 Terraform 代码质量保障
  • 自动化代码审查与“Shift Left”安全最佳实践
  • 云平台资源配置的预防性校验与成本风险控制

1.6.6.1.2. Terraform 自身的检查不够用吗?

随着基础设施即代码的普及和 Terraform 在云原生基础设施管理中的广泛应用,组织面临着模块复用、团队协作、合规性管理等多重挑战。Terraform 本身虽然有 terraform validateterraform plan 等内建检查机制,但它们主要聚焦于语法和基础语义层面,难以覆盖企业级治理所需的复杂规则和最佳实践约束。

tflint 补足了官方工具的不足,它能够:

  • 在代码编写早期自动暴露错误和不规范用法,减少后期返工成本
  • 统一团队代码风格和结构,提升模块可复用性与可维护性
  • 自动检测资源类型、参数合法性、变量使用等业务规则,防止生产事故
  • 支持自定义企业内部规则,有效支撑合规和安全要求落地

一言以蔽之,tflint 就类似 golangci-lint,可以帮助我们定位那些语法上正确,但可能引发其他问题,或是已被标记为废弃语法的代码。

1.6.6.1.3. tflint 的使用方法

1.6.6.1.3.1. 安装

tflint 支持多平台安装,常用方式如下:

  • Linux
curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash
  • macOS
brew install tflint
  • Windows
choco install tflint
  • Docker 容器
docker run --rm -v $(pwd):/data -t ghcr.io/terraform-linters/tflint

此外,tflint 还支持通过 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. 快速上手

初始化配置文件

项目根目录下新建 .tflint.hcl,定义所需插件及规则。例如:

plugin "terraform" {
  enabled = true
  preset  = "recommended"
}

对于云平台,可以结合对应插件:

plugin "aws" {
  enabled = true
  version = "0.19.0"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}

插件安装

tflint --init

与 Terraform 类似,tflint 也使用了 HashiCorp 的 go-plugin 实现了插件机制,上面例子中的 plugin "aws" 中的 source 就指示了去哪里下载插件,所以和 Terraform 类似的,在运行 tflint 命令之前,也要先运行 tflint --init 下载插件。

代码检查

直接在项目根目录执行:

tflint

tflint 会扫描当前目录下的所有 Terraform 代码,并输出所有发现的问题。支持丰富的命令行参数定制行为,如递归扫描、多种输出格式(json、junit、sarif 等)、指定配置文件、自动修复部分问题等。

集成到 CI/CD

可通过官方 GitHub Actions、Makefile、Shell 脚本或 Docker 容器,将 tflint 集成到开发与部署流水线,确保每一次代码变更都经过自动化检查。

1.6.6.1.3.3. 进阶用法

  • 支持规则启用/禁用、插件自定义、变量文件指定、多目录递归扫描等。
  • 可通过环境变量 TFLINT_LOG=debug 查看详细日志,辅助调试与排查。

1.6.6.1.4. AVM 中调用 tflint

AVM 中提供了如下脚本:

#!/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

这里面要注意的是,AVM 中 tflint 检查了三种 Terraform 代码:模块代码、examples 代码以及子模块 modules 代码。这三种代码是可以指定不同的检查策略的,例如,我们认为 examples 代码中不需要强制所有 output 块都必须声明 description,AVM 默认提供了一个 avm.tflint_example.hcl,其中定义了:

rule "terraform_documented_outputs" {
  enabled = false
}

如果模块维护者希望在默认规则配置的基础上做一些调整,比如,我们希望当前模块代码也可以允许 output 块不声明 description(非常不推荐这么做),那么可以在当前模块仓库里添加名为 avm.tflint.override.hcl 的文件,内含上面声明的 terraform_documented_outputs 块,AVM CI 流水线会在运行时将这种 override.hcl 文件中的配置合并到默认配置中去(脚本中使用了工具 hclmerge)。

1.6.6.1.5. 总结

tflint 是大规模 Terraform 模块治理不可或缺的自动化工具。它结合了灵活的插件扩展机制、丰富的规则集与高度可定制的检查能力,能显著提升基础设施代码的质量、安全性和团队协作效率。无论是单一项目还是企业级多团队治理,tflint 都能为 Terraform 代码的规范化、合规化和高效交付提供坚实支撑。

results matching ""

    No results matching ""