Skip to main content

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ตัวอย่าง
Documentedvariables, outputs ต้องมี description
Pinned Sourcemodule source ต้อง pin version
Required Versionterraform block มี required_version
Namingsnake_case enforcement
Standard Module Structuremain.tf, variables.tf, outputs.tf
Unuseddeclared แต่ไม่ใช้

ดูครบที่ 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