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 validate
和 terraform 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 代码的规范化、合规化和高效交付提供坚实支撑。