TFLint
TFLint = third-party linter ที่ตรวจ best practices + provider-specific issues ที่
terraform validateตรวจไม่เจอ
ทำไมต้องใช้ TFLint?
terraform validate แค่เช็ค syntax — TFLint ตรวจลึกกว่า:
✅ Provider-specific issues:
- AWS instance type ไม่มีจริง (
t999.large) - AMI ID ผิด format
- IAM action ที่ deprecated
✅ Best practices:
- Variable ไม่มี description
- Module source ไม่ pin version
- Hard-coded credentials
✅ Naming conventions:
- Resource name ที่ไม่ตรง pattern
ติดตั้ง
# macOS
brew install tflint
# Linux / macOS (script)
curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash
# Windows
choco install tflint
ตรวจ:
tflint --version
ใช้งานพื้นฐาน
# ใน folder ที่มี .tf
tflint
ถ้าไม่มี issue → exit 0 มี issue → list ทุก issue + exit non-zero
Recursive
tflint --recursive
# หรือ
tflint --chdir=./modules/vpc
ตั้งค่า: .tflint.hcl
ใช้ไฟล์นี้ตั้งค่า rules + plugins:
.tflint.hcl
plugin "terraform" {
enabled = true
preset = "recommended"
}
plugin "aws" {
enabled = true
version = "0.32.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
# Disable rule บาง
rule "terraform_required_version" {
enabled = false
}
# Custom rule
rule "terraform_naming_convention" {
enabled = true
format = "snake_case"
}
Init Plugins
ต้อง init ก่อนใช้:
tflint --init
→ download plugins จาก GitHub
ตัวอย่าง Issues ที่ TFLint จับ
Issue 1: Variable ไม่มี description
variable "region" {
type = string
default = "us-east-1"
# ขาด description
}
$ tflint
1 issue(s) found:
Warning: `region` variable has no description (terraform_documented_variables)
Issue 2: Module source ไม่ pin version
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
# ขาด version!
}
Warning: Module source "terraform-aws-modules/vpc/aws" is not pinned (terraform_module_pinned_source)
Issue 3: AWS Instance Type ผิด
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t999.gigamax" # ← ไม่มีจริง
}
Error: "t999.gigamax" is an invalid value as instance_type (aws_instance_invalid_type)
Issue 4: Hard-coded ARN
resource "aws_iam_role_policy_attachment" "lambda" {
role = "MyLambdaRole" # ← string ตรงๆ ไม่ดี
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
Built-in Rules
มี ~50 rules แบ่งเป็น:
| Category | ตัวอย่าง |
|---|---|
| Documented | variables, outputs ต้องมี description |
| Pinned Source | module source ต้อง pin version |
| Required Version | terraform block มี required_version |
| Naming | snake_case enforcement |
| Standard Module Structure | main.tf, variables.tf, outputs.tf |
| Unused | declared แต่ไม่ใช้ |
ดูครบที่ tflint rules
Provider Plugins
ติดตั้ง plugin เพื่อ rule เฉพาะ provider:
.tflint.hcl
plugin "aws" {
enabled = true
version = "0.32.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
plugin "google" {
enabled = true
version = "0.30.0"
source = "github.com/terraform-linters/tflint-ruleset-google"
}
plugin "azurerm" {
enabled = true
version = "0.27.0"
source = "github.com/terraform-linters/tflint-ruleset-azurerm"
}
แล้วรัน:
tflint --init
Rule ที่ดีให้ Enable
.tflint.hcl
plugin "terraform" {
enabled = true
preset = "recommended"
}
plugin "aws" {
enabled = true
version = "0.32.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
# Required
rule "terraform_required_version" { enabled = true }
rule "terraform_required_providers" { enabled = true }
# Documentation
rule "terraform_documented_variables" { enabled = true }
rule "terraform_documented_outputs" { enabled = true }
# Naming
rule "terraform_naming_convention" {
enabled = true
format = "snake_case"
}
# Modules
rule "terraform_module_pinned_source" { enabled = true }
rule "terraform_module_version" { enabled = true }
# Cleanup
rule "terraform_unused_declarations" { enabled = true }
rule "terraform_deprecated_interpolation" { enabled = true }
# Provider versions
rule "terraform_required_providers" { enabled = true }
CI/CD
GitHub Actions
.github/workflows/lint.yml
- name: Setup TFLint
uses: terraform-linters/setup-tflint@v4
with:
tflint_version: v0.53.0
- name: Init TFLint
run: tflint --init
- name: Run TFLint
run: tflint --recursive --format compact
GitLab CI
tflint:
image: ghcr.io/terraform-linters/tflint:v0.53.0
script:
- tflint --init
- tflint --recursive
Ignore Issue
# tflint-ignore: aws_instance_invalid_type
resource "aws_instance" "test" {
instance_type = "t999.test" # intentional for testing
}
หรือ ignore ทั้งไฟล์:
# tflint-ignore-file: terraform_naming_convention
Output Formats
tflint --format default # human-readable (default)
tflint --format json # JSON for CI
tflint --format checkstyle # Jenkins compatible
tflint --format compact # one issue per line
tflint --format sarif # SARIF (GitHub Code Scanning)
SARIF + GitHub Code Scanning
- name: Run TFLint
run: tflint --format sarif --recursive > tflint.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: tflint.sarif
→ Issues ปรากฏใน GitHub Security tab
รวมกับ Other Tools
Workflow ที่แนะนำ
# 1. Format
terraform fmt -check -recursive
# 2. Validate
terraform validate
# 3. Lint (TFLint)
tflint --init
tflint --recursive
# 4. Security scan
checkov -d .
# 5. Plan
terraform plan
สรุป
- TFLint = third-party linter — ลึกกว่า
terraform validate - ตรวจ provider-specific issues + best practices + naming
- ติดตั้ง plugin ตาม cloud provider (
aws,google,azurerm) - ตั้งค่าใน
.tflint.hcl - รวมเข้า CI/CD + editor
ต่อไป → Section 8: Deployment