TFLintは、Terraformのコードをterraform applyの前に検査するプラガブルな静的解析ツール(Terraform用のリンター)です。terraform validateが通してしまうプロバイダ固有の誤り、たとえば存在しないEC2インスタンスタイプの指定や、非推奨構文・未使用宣言を指摘します。この記事では2026年8月1日時点の最新版v0.64.0を前提に、多くの人がつまずくHomebrewでの導入、.tflint.hclの書き方、AWS・Azure・Googleのルールセット、公式アクションによるCI組み込み、カスタムルールの実装手段までを、公式リポジトリの一次情報だけで組み立てて解説します。
まとめ:TFLint導入で先に押さえる5点
- macOSでのインストールは
brew install tflintでは解決せず、公式tap経由のbrew install terraform-linters/tap/tflintが正解 - CIの合否判定に使う終了コードは、問題検出が2・内部エラーが1という別扱い(取り違えるとプラグイン取得の失敗を見逃す)
- 検査ロジックの所在はすべてプラグイン側。Terraform言語向けはバイナリ同梱、AWS・Azure・Googleは
.tflint.hclへの宣言とtflint --initが必要 - 独自ルールの実装手段は、Goによるプラグイン開発かOPAルールセットでのRegoポリシー記述の二択(設定ファイルでは書けない)
- 最新版はv0.64.0(2026年7月17日公開)、対応Terraformはv1.0以降
実務でつまずくのは上の2点に集中します。以降、それぞれの根拠と設定例を公式ドキュメントの記述に沿って示します。
TFLintの検査範囲とterraform validate・fmtとの違い
Terraform標準のコマンドと守備範囲が重なりそうに見えますが、実際には検出できる問題が分かれています。
| ツール | 検査対象 | 代表的な指摘 | プロバイダ仕様の知識 |
|---|---|---|---|
| terraform fmt | 書式 | インデント・属性の整列 | 持たない |
| terraform validate | 構文と型の整合 | 未定義変数、型不一致 | 持たない |
| TFLint | プロバイダ仕様と規約 | 無効なインスタンスタイプ/非推奨構文 | プラグインが持つ |
TFLintはこのほかに、使われていない変数やデータソースの宣言も指摘します。AWSルールセット(tflint-ruleset-aws)の公式READMEが挙げる例が違いを端的に示しています。instance_type = "t1.2xlarge"というAWSに存在しないタイプを書いても、Terraformの言語仕様としては正しいためterraform validateもterraform planも素通りし、applyで初めて失敗します。この「言語としては正しいがプロバイダとしては誤り」の層をCIで潰すのがTFLintの役割です。
TFLint本体はフレームワークにすぎず、ルールを1つも持ちません。同じ発想の姉妹ツールとして、CloudFormationテンプレートを対象にしたCloudFormation Linter(cfn-lint)、GitHub Actionsのワークフローを対象にしたactionlintがあり、IaCとCI定義の両方を静的解析でカバーする構成が組めます。
TFLintのインストール手順(macOS・Windows・Linux・Docker)
Homebrewでの導入とbrew install tflintが通らない理由
先に結論を書きます。Homebrew公式のformulae一覧にtflintは登録されていません。2026年8月1日時点でhomebrew-coreリポジトリにtflintのFormulaファイルは存在せず、素のbrew install tflintはパッケージを解決できずに失敗します。配布は開発元が管理するtap側で、しかもFormulaではなくCaskです。
brew install terraform-linters/tap/tflint
tapのREADMEが案内しているとおり、tapを先に登録しておけば短い名前でも解決できます。
brew tap terraform-linters/tap
brew install tflint
tapのCask定義はv0.64.0を指しており、中身は公式リリースのtflint_darwin_arm64.zipなどをそのまま配置するだけなので、バイナリ自体は手動インストールと変わりません。Caskならではの利点が1つあり、インストール後のpostflightでcom.apple.quarantine拡張属性を削除するため、zipを手で展開したときに出るGatekeeperの警告を踏まずに済みます。なおCaskはmacOS専用の仕組みなので、Homebrew on Linuxではこの手順を使えません。
WinGet・バイナリ直接取得・go installでの導入
Windowsは、WinGetのパッケージIDが公開されています。
winget install -e --id TerraformLinters.tflint
Linuxやコンテナイメージのビルドでは、リリースアーカイブを取得して検証してから配置します。公式が推奨する検証手段はGitHub CLIのArtifact Attestationで、以前案内されていたCosignはREADME上でDeprecated(非推奨)と明記されました。
curl -sSLO https://github.com/terraform-linters/tflint/releases/latest/download/tflint_linux_amd64.zip
curl -sSLO https://github.com/terraform-linters/tflint/releases/latest/download/checksums.txt
gh attestation verify checksums.txt -R terraform-linters/tflint
sha256sum --ignore-missing -c checksums.txt
unzip tflint_linux_amd64.zip
sudo install -c -v tflint /usr/local/bin/
Goツールチェーンがある環境なら、ソースからの導入も選べます。
go install github.com/terraform-linters/tflint@latest
Dockerイメージでの実行とプラグイン取得の同時実行
ホストを汚さずに試すならコンテナが早道です。イメージはGitHub Container Registryにあります。
docker run --rm -v $(pwd):/data -t ghcr.io/terraform-linters/tflint
ここで詰まりやすいのがプラグインの取得です。イメージのエントリポイントがtflintそのものなので、tflint --initと本実行を続けて走らせられません。公式ドキュメントはエントリポイントをシェルへ差し替える回避策を案内しています。
docker run --rm -v $(pwd):/data -t --entrypoint /bin/sh ghcr.io/terraform-linters/tflint -c "tflint --init && tflint"
.tflint.hclの探索順と設定できる項目
設定ファイルの読み込み優先順位とconfigブロック
TFLintは6段階の優先順位で設定ファイルを探し、最初に見つかった1つだけを使います。--configオプションでの明示が最優先で、次に環境変数TFLINT_CONFIG_FILE、続いてカレントディレクトリの./.tflint.hclと./.tflint.json、最後にホームディレクトリの~/.tflint.hclと~/.tflint.jsonという順です。拡張子でHCLとJSONを判別する仕様で、JSON版はTerraformの.tf.jsonと同じHCL互換JSON構文になります。設定の骨格は次のようになります。
tflint {
required_version = ">= 0.50"
}
config {
format = "compact"
plugin_dir = "~/.tflint.d/plugins"
call_module_type = "local"
force = false
disabled_by_default = false
}
plugin "aws" {
enabled = true
version = "0.48.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
rule "aws_instance_invalid_type" {
enabled = false
}
formatはdefault・json・checkstyle・junit・compact・sarifの6種類です。ただし--recursiveで走らせる場合、この項目は設定ファイル側が無視されフラグでの指定が必須になります。call_module_typeはall・local・noneから選び、既定はlocalです。ignore_moduleで特定のモジュールソースを検査対象から外し、varfileやvariablesでTerraform変数を与えられます。
もう1つ、再帰実行での落とし穴があります。--chdirや--recursiveを使うと設定ファイルのパスが各モジュールディレクトリ基準で解決されるため、リポジトリ直下の設定を全ディレクトリへ効かせたいなら絶対パスで渡します。
tflint --recursive --config "$(pwd)/.tflint.hcl"
pluginブロックとバイナリ同梱のTerraformルールセット
Terraform言語そのものに対するルール群であるtflint-ruleset-terraform(最新v0.15.0)は、TFLintのバイナリに組み込まれた「バンドルプラグイン」です。宣言しなくても有効で、既定のプリセットはrecommendedが適用されます。挙動を変えたいときだけ明示します。
plugin "terraform" {
enabled = true
preset = "recommended"
}
プリセットにはrecommendedとallがあり、バンドル利用時の既定はrecommended、プラグインとして単体導入した場合の既定はallと異なります。ルール数を増やしたい場合はallを明示してください。
version属性には注意点が2つあります。先頭に「v」を付けてはならず、>= 0.3のようなバージョン制約も使えません。固定値のみです。また署名検証の挙動をsignature属性で制御でき、auto・attestation・pgp・noneが指定できます。既定のautoはattestationを優先し、無ければPGPへフォールバックします。
ruleブロックとtflint-ignoreによる個別抑制
ルール単位の無効化はruleブロック、行単位の抑制はコメントアノテーションで行います。
resource "aws_instance" "foo" {
ami = "ami-0ff8a91507f77f867"
# 新しすぎてTFLintがまだ認識していないため一時的に除外
# tflint-ignore: aws_instance_invalid_type
instance_type = "t10.2xlarge"
}
カンマ区切りで複数ルールを、allキーワードで全ルールを抑制できます。ファイル全体を除外するtflint-ignore-fileもありますが、こちらはファイル先頭にしか書けず、リソースブロックの内側に置くとエラーになります。
抑制には明確な限界があります。アノテーションで消せるのは「issues」だけで、パースできないモジュールから出る「errors」は抑制できません。さらにルール側がignorable = falseを設定していると、アノテーションを書いても効きません。組織として絶対に外させたくないルールがあるなら、この設定で運用者側の抑制を封じられます。
AWS・Azure・Googleのルールセット導入
クラウド固有の検査は、それぞれ独立したルールセットプラグインとして配布されています。2026年8月1日時点の最新版は次のとおりです。
| プラグイン名 | 最新版 | 公開日 |
|---|---|---|
| aws | 0.48.0 | 2026-06-29 |
| azurerm | 0.32.0 | 2026-04-25 |
| 0.39.0 | 2026-03-21 |
いずれもsourceはgithub.com/terraform-linters/tflint-ruleset-<プラグイン名>の形式です。AWSルールセットは700を超えるルールを持ちますが、すべてが既定で有効ではありません。命名規則やベストプラクティス系のルールは手動で有効化する必要があり、導入しただけでは主に「applyで落ちる誤り」の検出にとどまります。動作要件はTFLint v0.46以降です。
導入は設定ファイルへの宣言と初期化コマンドの2手順です。
tflint --init
この--initはリリースメタデータを取得するためにGitHub APIを呼びます。既定では未認証リクエストのため、IPアドレスあたり毎時60回の制限にかかります。GitHub Actionsのような共有環境では他テナントと枠を共有するため、実行頻度に関係なくレート制限に当たり得ます。GITHUB_TOKEN環境変数を設定して認証リクエストにするのが対策です。バージョン固定値を手で上げ続けるのが負担なら、RenovateによるTerraform依存の自動更新がTFLintプラグインのマネージャにも対応しています。
CLI実行と終了コード・自動修正
検査範囲を絞る5オプションと6種類の出力フォーマット
TFLintが既定で見るのはカレントディレクトリのモジュールだけで、サブディレクトリは--recursiveを付けない限り対象外です。モノレポで環境別ディレクトリを切っている構成では、この既定のままだとルート直下しか検査されません。
よく使うのは検査範囲と出力形式の制御です。--chdir=DIRで作業ディレクトリを切り替え、--recursiveで各ディレクトリを再帰的に処理します。再帰実行のワーカー数は既定でCPU数となり、--max-workers=Nで絞れます。ランナーごとの並列を切りたい場合は--no-parallel-runnersを使います。
ルールの取捨選択には--enable-rule、--disable-rule、そして他の既定ルールをすべて無効化して指定ルールだけを走らせる--onlyがあります。差分ファイルだけを対象にしたい場合は--filterにファイル名やglobを渡します。
CIで使う終了コードと失敗レベルの制御
CIへ組み込むうえで最も重要なのが終了コードの意味です。ソースコード上の定義は0から順に割り当てられており、0が正常終了、1が内部エラー、2が問題検出です。
| 終了コード | 意味 | CIでの扱い |
|---|---|---|
| 0 | 問題なし | 成功 |
| 1 | TFLint自体のエラー | 設定不備・プラグイン取得失敗を疑う |
| 2 | 問題を検出 | コード修正が必要 |
1と2を「どちらも失敗」とまとめて扱うと、プラグイン取得に失敗しているだけの状態をコード品質の問題として報告し続けることになります。切り分けるようにしてください。導入初期で既存コードの指摘が大量に出る場合は、--forceで問題検出時も終了コード0を返せます。段階的に締めるなら--minimum-failure-severityでerror・warning・noticeのいずれかを閾値に設定し、まずerrorだけを失敗扱いにする運用が現実的です。静的解析が拾えるのは書き方の問題までで、変数の組み合わせによって出来上がる構成が変わるかどうかは、planかapplyを実際に走らせないと分かりません。この領域はterraform testの書き方|unit/integrationの分け方とCIコストで扱うテストフレームワークが受け持ちます。
–fixによる自動修正の適用範囲
一部のルールは自動修正に対応しており、出力に[Fixable]と表示されます。--fixを付けて実行すると該当箇所が修正され、表示は[Fixed]に変わります。
tflint --fix
ただし自動修正はすべての指摘に効くわけではなく、ルール側が対応している必要があります。もう1つ、公式ドキュメントは副作用を警告しています。修正が適用されるとファイル全体が整形されるため、指摘と無関係な行まで差分に入ります。レビューしやすさを保つなら、フォーマット目的の実行とロジック修正のコミットは分けたほうが安全です。
GitHub Actionsへの組み込み(setup-tflint v6)
開発元が公式アクションを提供しているCIサービスはGitHub Actionsだけです。そのsetup-tflintの最新はv6.3.0(2026年6月30日公開)で、公式Usageに沿った構成は次のようになります。
name: Lint
on: [push, pull_request]
jobs:
tflint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: terraform-linters/setup-tflint@v6
with:
tflint_version: v0.64.0
cache: true
- name: Init TFLint
run: tflint --init
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Run TFLint
run: tflint -f compact
cache: trueはプラグインディレクトリをキャッシュし、キーはtflint_config_path(既定は.tflint.hcl)に一致するファイルのハッシュから生成されます。モノレポで設定ファイルが複数ある場合はglobパターンを渡せます。バージョンをワークフローに直書きしたくないならtflint_version_fileがあり、asdfやmiseの.tool-versions、または単一バージョンだけを書いたファイルを読ませられます。この入力はtflint_versionが未指定またはlatestのときだけ参照される点に注意してください。
実行結果を後続ステップで扱いたい場合はtflint_wrapper: trueを指定すると、stdout・stderr・exitcodeがアクションの出力として取り出せます。プルリクエストへのコメント投稿などはこの出力を使って組み立てます。
カスタムルールの実装手段はGoプラグインかRegoポリシー
ここは誤解が広まっている部分なので、はっきり書きます。.tflint.hclではカスタムルールを作れません。設定ファイルでできるのは既存ルールの有効化・無効化とパラメータ調整までで、新しい検査ロジックを定義する構文は存在しません。独自のチェックを追加する手段は2つです。
1つ目はtflint-plugin-sdkを使ってGoでルールセットプラグインを実装する方法です。表現力に上限がなく、既存のawsルールセットなどと同じ仕組みで配布できます。反面、Goのコードとリリースパイプラインを自前で保守することになります。
2つ目がOPAルールセット(tflint-ruleset-opa、最新v0.11.0・2026年7月20日公開)で、Regoでポリシーを書く方法です。ポリシーファイルは~/.tflint.d/policiesまたは./.tflint.d/policiesに置きます。
plugin "opa" {
enabled = true
version = "0.11.0"
source = "github.com/terraform-linters/tflint-ruleset-opa"
}
選び方の判断はシンプルです。「S3バケット名は example-com- で始める」といった組織ルールを数本適用したいだけなら、Goプラグインを立ち上げる価値はありません。Regoで書くべきです。ただしOPAルールセットは公式が実験的(experimental)と明示し、破壊的変更が頻繁に入ると警告しています。プラグインのバージョンは必ず固定し、更新時はポリシーの動作確認を前提に組んでください。Regoの記法自体はOPA 1.0でRego v1への移行が入っているため、書き始める前にどちらの構文を使うか決めておくと手戻りが減ります。
MPL 2.0とBUSL 1.1の二重ライセンスが効いてくる場面
再配布を伴う案件では、最初に確認すべき点があります。TFLintは単一ライセンスではありません。
公式READMEのLicense節は、プロジェクトの大部分はMPL 2.0だがterraformパッケージ内の一部ファイルはBUSL 1.1であり、そのため実行形式(リリースバイナリ)は両方のライセンスに拘束されると明記しています。Terraform本体がBUSLへ移行した際、そのterraformパッケージのコードを取り込んでいるTFLintが条件をそのまま引き継いだ形です。
実務上の切り分けはこうなります。自社のCIパイプラインでTFLintを実行してコードを検査するだけなら、通常の利用であり気にする必要はありません。問題になるのは、自社製品やSaaSにTFLintのバイナリを同梱して顧客へ提供する構成です。この場合はMPL 2.0だけを見て判断すると誤ります。BUSL側の条件を確認せずに製品組み込みを進めるべきではありません。ライセンス条件そのものを避けたい場合は、Terraform互換のフォークという選択肢も含めてOpenTofuとTerraformのライセンス差から検討したほうが、後戻りが少なく済みます。
よくある質問
brew install tflint が「No available formula」で失敗します
homebrew-coreにtflintのFormulaが登録されていないためです(2026年8月1日時点)。公式は開発元のtapでCaskとして配布しているので、brew install terraform-linters/tap/tflintを使ってください。tapのREADMEにあるとおり、brew tap terraform-linters/tapを先に実行しておけば、以降はbrew install tflintでも解決できます。CaskはmacOS専用の配布形式なので、Linux環境ではリリースアーカイブの直接取得かgo install、あるいはコンテナイメージを選んでください。
terraform validate があれば TFLint は不要ですか
役割が違うため代替になりません。terraform validateが見るのは構文と型の整合までで、プロバイダ固有の仕様は対象外です。存在しないインスタンスタイプのような「言語としては正しいがAWSでは無効」な記述は、TFLintにAWSルールセットを導入して初めて検出できます。逆に、TFLint本体だけを入れても標準で有効なのはTerraform言語向けのバンドルルールセットだけなので、クラウド固有の誤りは拾えません。両者は排他ではなく、CIでは併用するのが前提の構成になります。
setup-tflint でバージョンを固定するにはどう書きますか
terraform-linters/setup-tflint@v6のwithにtflint_version: v0.64.0のように明示します。ワークフローへ直書きせず他のツールとまとめて管理したい場合はtflint_version_fileが使え、asdfやmiseの.tool-versions、または単一バージョンだけを書いたファイルを読ませられます。ただしこの入力が参照されるのはtflint_versionが未指定かlatestのときだけで、明示的なバージョンを書くとそちらが優先されます。アクション自体も@v6のようにメジャータグで固定しておくと、破壊的変更を踏みにくくなります。
TFLintの最新バージョンはどれですか
2026年8月1日時点でv0.64.0(2026年7月17日公開)です。リリース間隔が短いため、常に最新を追う場合はGitHubのリリースページを確認してください。見落としやすいのは、ルールセットプラグインのバージョンが本体とは独立して上がる点です。.tflint.hclのversion属性はバージョン制約を書けず固定値しか受け付けないため、手作業で追い続けると必ず取り残されます。RenovateがTFLintプラグインの更新に対応しているので、既存の依存更新の仕組みに乗せてしまうのが現実的です。
Azureのルールセットはありますか
tflint-ruleset-azurerm(最新v0.32.0・2026年4月25日公開)が公式に提供されています。.tflint.hclにplugin "azurerm"ブロックを追加し、sourceへgithub.com/terraform-linters/tflint-ruleset-azurermを指定してtflint --initを実行すれば導入できます。AWS・Google向けも手順は同じで、複数クラウドを1つのリポジトリで扱う場合はpluginブロックを並べて宣言すれば同時に有効化できます。ただしプラグインが増えるほど--init時のGitHub API呼び出しも増えるため、GITHUB_TOKENの設定を忘れないでください。