terraform applyを実行してから書き間違いに気づいた」「チームで開発していると、インデントや命名規則がバラバラになってPRの差分がノイズだらけになる」こういった問題を放置すると、Terraformコードのレビューコストが静かに積み上がっていきます。この記事では、Terraformのコード品質を静的チェックで自動化する3つのツール(terraform fmt・terraform validate・tflint)の役割と使い分けを解説し、pre-commitフックへの組み込みとGitHub Actions CIへの統合手順をステップごとに説明します。動作確認環境はRocky Linux 9.4 / Ubuntu 24.04 LTSです。
この記事のポイント
・tflint / terraform fmt / validateは「規約違反・構文・書式」をそれぞれ担当する
・実行順序はfmt → validate → tflintの順が鉄則
・pre-commitフックに登録するとコミット前にチェックが自動実行される
・GitHub Actionsに組み込むとPRレビュー時にチェック結果が可視化される
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜterraform applyの前に静的チェックが必要なのか
Terraformのコード品質チェックを「applyが通ればよい」という運用にしていると、フィードバックサイクルが極端に遅くなります。applyにはプロバイダーの認証・初期化、リソースの依存関係の解決、tfstateの更新といったステップがあり、単純なタイポでも数十秒~数分待ってからエラーが出ることになります。1. applyを起点にしたフィードバックサイクルの問題
例えば変数の参照ミス(var.region_nameをvar.reagion_nameとタイポした場合)は、terraform validateであれば即座に検出できます。しかしチェックをかけずにapplyすると、プロバイダーの初期化が完了した後にエラーが出るため、無駄な待ち時間が発生します。自分のPCでの手元テストで「とりあえずapplyして確認する」習慣が染みつくと、CIに組み込んだ際も同じアプローチを取りがちです。その結果、CI実行時間が長くなり、PRごとのフィードバックが返ってくるまでの待機時間が伸びていきます。
静的チェックを最初に挟むことで、apply可能なコードかどうかをAPIコールなしに判定できます。認証情報が不要なため、ローカル開発環境でもCI環境でも同じコマンドが使えるのも利点です。
2. チーム開発でコード品質が崩れやすい理由
複数のエンジニアが同じTerraformリポジトリで作業する場合、各自のエディタ設定によってインデント幅や引用符の種類がバラバラになりやすいです。VSCodeでTabキーを使う人とスペース4つを使う人が混在すると、コードの差分が本質的な変更ではなくフォーマットの差分になります。また、tflintを使わないと「構文は正しいが廃止予定のインスタンスタイプを使っている」「required_versionが未定義でプロバイダーバージョンが固定されていない」といった問題はコードレビューで見落とされがちです。レビュアーがプロバイダーの廃止スケジュールをすべて把握していることを前提にしないためにも、ツールによる自動チェックは有効です。
3つのツールの役割と実行順序を設計する
terraform fmt・terraform validate・tflintの3ツールは、それぞれ独立した問題領域をカバーしています。役割を正確に理解することで、どの順番で実行すべきかの設計判断が明確になります。1. terraform fmt — HCLフォーマットの自動修正
terraform fmtはHCL(HashiCorp Configuration Language)のフォーマットを公式スタイルに揃えるコマンドです。インデントの深さ、引用符の統一(ダブルクォートへの統一)、属性のアライメントを自動修正します。# フォーマット修正(差分を表示しながら上書き) $ terraform fmt # 変更があるファイル名だけ表示(修正はしない) $ terraform fmt --check main.tf variables.tf # 終了コードで確認(0=変更なし、1=変更あり) $ echo $? 1 # サブディレクトリも含めて再帰的に実行 $ terraform fmt -recursive
--checkフラグはファイルを修正せずに差分の有無だけを返します。CIではこのフラグを使い、フォーマットが崩れているコミットをブロックするのが一般的なパターンです。2. terraform validate — 構文とプロバイダースキーマの整合性チェック
terraform validateはHCLの構文が正しいかどうか、および参照しているリソース・変数・出力が定義されているかをチェックします。実際にAPIを呼び出さないため、AWSの認証情報がなくても実行できます。ただしterraform initによるプロバイダーの初期化が完了していることが前提です。以下はRocky Linux 9.4環境でterraform validateを実行したときの出力例です。リソース参照のタイポを検出しています。
$ terraform validate ╷ │ Error: Reference to undeclared resource │ │ on main.tf line 15, in resource "aws_instance" "web": │ 15: subnet_id = aws_vpc.main.id │ │ A managed resource "aws_vpc" "main" has not been declared in this module. ╵ $ echo $? 1
validateで検出されないのは「構文は正しいが意図しない設定」です。たとえば
instance_type = "t2.micro"は構文的に正しいため、validateではスルーされます。この種の問題はtflintが担当します。3. tflint — ベストプラクティス違反の検出
tflintは、構文チェックを超えて「実務上問題のある書き方」を検出するLinterです。デフォルトで有効なルールセットに加え、AWSやGCPなどクラウドプロバイダー固有のルールをプラグインで追加できます。tflintが検出する問題の代表例は以下の通りです。
・廃止予定のインスタンスタイプ:t2系は旧世代(t3系への移行推奨)
・required_versionの未設定:Terraformバージョン固定なしでチーム開発すると挙動が変わるリスクがある
・プロバイダーのバージョン制約なし:required_providersにversionを指定しないとリリースのたびに動作が変わりうる
・廃止された属性:将来のプロバイダーバージョンで削除予定の属性を使っている
以下は実際の出力例です(Rocky Linux 9.4・tflint v0.54.0・tflint-ruleset-aws v0.34.0)。
$ tflint 3 issue(s) found: Warning: Missing version constraint for provider "aws" in "required_providers" (terraform_required_providers) on main.tf line 1: 1: terraform { Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.9.1/docs/rules/terraform_required_providers.md Warning: "t2.micro" is previous generation instance type. (aws_instance_previous_type) on main.tf line 10: 10: instance_type = "t2.micro" Reference: https://github.com/terraform-linters/tflint-ruleset-aws/blob/v0.34.0/docs/rules/aws_instance_previous_type.md Warning: terraform "required_version" attribute is required (terraform_required_version) on main.tf line 1: 1: terraform {
4. fmt → validate → tflintの順序が正しい理由
3つのツールはterraform fmt → terraform validate → tflintの順序で実行するのが正しい設計です。フォーマットが崩れたままのファイルはコードとして読みにくく、後続のチェックで誤検知が出ることもあります。まずfmtでフォーマットを揃え、次にvalidateで構文とリソース参照の整合性を確認し、最後にtflintでベストプラクティス準拠を確かめる順序は「問題を早い段階から解消する」原則に沿っています。
また、terraform validateはプロバイダーの初期化(terraform init)が必要で、tflintはtflint --initで独自にプラグインを取得します。この2つは独立しているため、validateとtflintを並列実行するオプションもありますが、シンプルな構成では直列実行で十分です。
tflintのインストールと.tflint.hclの設定
1. インストール手順(Rocky Linux 9.4 / Ubuntu 24.04 LTS)
tflintはシングルバイナリで配布されており、パッケージマネージャを使わずにインストールできます。# Rocky Linux 9.4 / Ubuntu 24.04 LTS どちらも同じ手順 $ TFLINT_VERSION="0.54.0" $ curl -sLo tflint.zip \ "https://github.com/terraform-linters/tflint/releases/download/v${TFLINT_VERSION}/tflint_linux_amd64.zip" $ unzip tflint.zip -d /tmp/tflint $ sudo mv /tmp/tflint/tflint /usr/local/bin/ $ sudo chmod +x /usr/local/bin/tflint # バージョン確認 $ tflint --version TFLint version 0.54.0 + ruleset.terraform (0.9.1-bundled)
# 公式インストールスクリプト(curl経由) $ curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash
2. .tflint.hclの基本設定とAWSプラグインの有効化
tflintは実行ディレクトリ(またはホームディレクトリ)の.tflint.hclで設定を読み込みます。Terraformのリポジトリルートに配置するのが一般的です。# .tflint.hcl(リポジトリルートに配置) config { # プラグインの保存先(デフォルト: ~/.tflint.d/plugins) plugin_dir = ".tflint.d/plugins" } # Terraform基本ルールセット(バンドル済み) plugin "terraform" { enabled = true version = "0.9.1" source = "github.com/terraform-linters/tflint-ruleset-terraform" # 推奨ルールを一括有効化 preset = "recommended" } # AWSプロバイダー固有のルールセット plugin "aws" { enabled = true version = "0.34.0" source = "github.com/terraform-linters/tflint-ruleset-aws" }
preset = "recommended"を指定すると、recommended設定のルール(required_version・required_providersのバージョン制約など)が一括で有効になります。個別ルールを細かくオン・オフしたい場合はruleブロックを追加します。# 特定ルールを無効化する例(.tflint.hclに追記) rule "terraform_required_version" { enabled = false }
3. tflint --initでプラグインを取得する
.tflint.hclを配置したら、tflint --initでプラグインをダウンロードします。初回のみ必要な操作です。$ tflint --init Installing "terraform" plugin... Installed "terraform" (source: github.com/terraform-linters/tflint-ruleset-terraform, version: 0.9.1) Installing "aws" plugin... Installed "aws" (source: github.com/terraform-linters/tflint-ruleset-aws, version: 0.34.0) # インストール確認 $ ls .tflint.d/plugins/ github.com
tflint --initをワークフローのステップとして実行し、プラグインディレクトリをキャッシュすることで実行時間を短縮できます。
>> Terraform実践セミナーの詳細はこちら
pre-commitフックへの組み込み手順
pre-commitは、Gitのコミット前フック(.git/hooks/pre-commit)を一元管理するフレームワークです。複数のチェックツールを.pre-commit-config.yamlで設定し、git commitを実行するたびに自動でチェックが走ります。1. pre-commitフレームワークのインストール
# pipでインストール(Python 3.8以上が必要) $ pip install pre-commit # バージョン確認 $ pre-commit --version pre-commit 3.7.1 # または pipx を使う(グローバルインストール時に推奨) $ pipx install pre-commit
2. .pre-commit-config.yamlの設定
リポジトリルートに.pre-commit-config.yamlを配置します。ここでは3ツールに絞った最小構成を示します。# .pre-commit-config.yaml repos: - repo: https://github.com/antonbabenko/pre-commit-terraform rev: v1.96.1 hooks: # terraform fmt --check(フォーマットチェック) - id: terraform_fmt # terraform validate(構文・スキーマチェック) - id: terraform_validate # tflint(ベストプラクティスチェック) - id: terraform_tflint args: - --args=--config=__GIT_WORKING_DIR__/.tflint.hcl
pre-commit-terraformはterraform関連フックをまとめたコミュニティリポジトリです。revにはGitHubリリースのタグを指定します。使用するTerraformバージョンとの互換性を定期的に確認することを推奨します。フックをインストールします。
# .git/hooks/pre-commitとして登録 $ pre-commit install pre-commit installed at .git/hooks/pre-commit # 全ファイルに対して手動で試し実行 $ pre-commit run --all-files
3. コミット前の動作確認
実際にコミットを試みて、フォーマットが崩れたファイルや構文エラーがある場合にブロックされることを確認します。$ git add main.tf $ git commit -m "add ec2 instance" terraform_fmt...........................................................Failed - hook id: terraform_fmt - exit code: 1 Files were modified by this hook. Additional output: main.tf # terraform_fmt がファイルを自動修正したためコミットはブロックされた # 修正後のファイルを再ステージしてコミットする $ git add main.tf $ git commit -m "add ec2 instance" terraform_fmt...........................................................Passed terraform_validate......................................................Passed terraform_tflint........................................................Passed [main 3f2a1b4] add ec2 instance
git addしてから再度コミットする手順になります。この挙動に違和感がある場合は、git add -pで差分を確認する習慣をつけると見通しがよくなります。GitHub Actions CIへの組み込み手順
pre-commitはローカルのチェックですが、GitHub ActionsによるCIに組み込むことで「フックを無効化してコミットした場合」「他のブランチからのマージ」も含めてチェックを強制できます。1. チェック専用ジョブの設計方針
コード品質チェックはterraform plan・applyと分離した独立ジョブとして設計します。チェックジョブはAWSの認証情報を必要としないため(terraform validateはinitが必要ですが認証なしで実行できます)、セキュリティリスクが低く、PRのたびに高速に実行できます。・トリガー:pull_requestイベント(opened・synchronize)
・認証:不要(チェックのみ)
・pathsフィルター:.tfファイルに変更がないPRではワークフローをスキップ
2. ワークフローYAMLの全体構成
# .github/workflows/terraform-lint.yml name: Terraform Lint on: pull_request: branches: - main paths: - '**.tf' - '**.tfvars' - '.tflint.hcl' jobs: terraform-lint: name: Terraform Code Quality Check runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Terraform uses: hashicorp/setup-terraform@v3 with: terraform_version: "1.9.8" - name: Terraform Init run: terraform init -backend=false - name: Terraform Format Check run: terraform fmt --check -recursive - name: Terraform Validate run: terraform validate - name: Setup TFLint uses: terraform-linters/setup-tflint@v4 with: tflint_version: v0.54.0 - name: TFLint Init run: tflint --init - name: TFLint Run run: tflint --format=compact
terraform init -backend=falseはバックエンドの初期化をスキップしてプロバイダーのスキーマだけをダウンロードします。S3バックエンドの認証なしにvalidateを実行するための定番の設定です。pathsフィルターを設定することで、.tfファイルに変更がないPR(ドキュメントや設定ファイルのみの変更)ではワークフローが起動しないようにできます。不要なCI実行を減らし、コストと待ち時間を削減できます。PRがこのワークフローをトリガーすると、GitHub ActionsのUIのChecksタブにチェック結果が表示されます。フォーマットエラーや構文エラーがある場合は該当ステップで失敗し、マージをブロックします(Branch protection rulesと組み合わせた場合)。
よくあるエラーと対処法
「Failed to initialize plugins」エラー(tflint --init)
$ tflint --init Failed to initialize plugins; Diagnostics: ... plugin "aws" is not installed
・プロキシ環境:GitHubへの通信がブロックされている場合はHTTPSプロキシを設定する(
export HTTPS_PROXY=http://proxy.example.com:3128)・バージョン不一致:.tflint.hclのpluginバージョンが存在しないタグを指定している。GitHubのリリースページで有効なタグを確認する
・plugin_dirの権限:plugin_dirで指定したディレクトリへの書き込み権限がない。先にディレクトリを作成する(
mkdir -p .tflint.d/plugins)terraform validate「Could not load plugin」エラー
$ terraform validate ╷ │ Error: Could not load plugin │ │ Plugin reinitialization required. Please run "terraform init". │ │ Plugins are external binaries that Terraform uses to access and │ manipulate resources. The configuration's requirements have changed │ since the last "terraform init" ran. ╵
.terraform/ディレクトリが存在しない状態でvalidateを実行した際に発生します。terraform init -backend=falseを先に実行することで解決します。CIではvalidateステップの前にinitステップを必ず配置してください。pre-commitフックがスキップされるケース
以下のケースではpre-commitフックが動作しません。・
git commit --no-verifyを使った場合:フックを意図的にスキップするオプションです。緊急時のみ使い、通常の運用では使わないようにチームで合意することを推奨します・GUIクライアントでのコミット:一部のGUIツールはフックを実行しないデフォルト設定になっている場合があります。使用ツールの設定を確認してください
・pre-commit installを実行していない端末:新しいメンバーがリポジトリをクローンした際に
pre-commit installを実行しないとフックが登録されません。READMEにセットアップ手順として明記するか、Makefileにmake setupコマンドとして組み込む方法が有効ですCIで全員のコードにチェックをかけることで、pre-commitを設定していない端末からのコミットもブロックできます。pre-commitはローカルでの早期発見、CIはチーム全体への強制、という二段構えが推奨パターンです。
まとめ — 3ツールのチェック範囲と役割一覧
| ツール | チェック範囲 | 認証不要か | 自動修正 |
|---|---|---|---|
| terraform fmt | HCLフォーマット(インデント・引用符・配置) | 不要 | あり(--checkなしの場合) |
| terraform validate | HCL構文・リソース参照・変数定義の整合性 | 不要(terraform init必要) | なし |
| tflint | ベストプラクティス違反・廃止予定属性・プロバイダー固有ルール | 不要(tflint --init必要) | なし |
>> Terraform実践セミナーの詳細はこちら
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 前のページへ:Terraformのuser_dataとcloud-initでEC2を初期設定する方法|provisionerを避けるサーバー初期化設計
- この記事の属するカテゴリ:Terraformへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます