IaCのテストは「全部やる」ものではなく、コストと価値のバランスで段を選ぶものです。速くて安い検査を下に厚く、遅くて高い統合テストを上に薄く。テストピラミッドの発想をIaCに翻訳し、CIのどの段でどれを回すかを整理します。
「IaCにテストは要るのか」という問いは、もう終わっています。数百行のTerraformが本番のネットワークやIAMを一発で書き換える以上、テストなしでapplyを押すのは、コンパイルせずに本番デプロイするのに近い。問題は「やるか否か」ではなく「どこまでやるか」です。本稿では、海外で確立したテストピラミッドの発想をIaCに翻訳し、静的解析・plan検証・統合テストをCIのどの段で回すか、コストと価値のバランスとして整理します。
01IaCのテストピラミッド — 下に厚く、上に薄く
アプリケーションのテストピラミッド(下から単体・結合・E2E)は、IaCにもそのまま効きます。下ほど「速く・安く・数多く」、上ほど「遅く・高く・少なく」。IaCの場合、この軸は「実インフラを作るか否か」とほぼ一致します。fmtやlintは秒で終わりゼロコスト、plan検証はクラウドAPIを叩くが破壊はしない、統合テストは実際にリソースを立てて壊すため分単位で課金が発生します。
- 第1層(静的):
terraform fmt/validate、tflint、checkov。コードを見るだけ。数秒。 - 第2層(plan検証):
terraform planのdiffをpolicy(OPA/Conftest等)で検査。クラウドを読むが変更しない。 - 第3層(統合):
terraform testのapplyモードやTerratestで実リソースを立て、検証し、破棄。
02第1層 — fmt / validate は「ゼロコストの門番」
最下層はTerraform同梱の2つから始めます。terraform fmt -check はフォーマットの揺れをCIで弾き、レビューを差分の本質だけに集中させます。terraform validate は構文と内部整合(未定義変数、型不一致、必須引数の欠落など)を、クラウドに接続せずにチェックします。どちらも数秒・課金ゼロ・依存なしで、入れない理由がありません。
ただしvalidateは「文法的に正しいか」しか見ません。「そのインスタンスタイプがそのリージョンに存在するか」「非推奨の書き方をしていないか」までは踏み込まないため、次のlintが必要になります。
03第1層 — 静的解析:tflint(品質)とcheckov(セキュリティ)は役割が違う
ここで混同されがちなのがtflintとcheckovです。両者は補完関係で、片方では足りません。
tflintはリンターです。terraform validateより踏み込み、プロバイダ固有の誤り(存在しないインスタンスタイプ、非推奨構文、未使用の変数宣言など)をapply前に検出します。Terraform言語ルールはTFLint本体に同梱され、AWSルールセットだけでも700以上のルールが提供されます。.tflint.hclでpreset = "recommended"を指定すれば推奨ルールに絞れます。
checkovはセキュリティ・コンプライアンススキャナです。「公開S3バケット」「暗号化されていないボリューム」「過剰なIAM権限」といった設定ミスを、AWS/Azure/GCP向けに1,000以上の組み込みポリシーで検査します(公式Quick Start参照)。導入はcheckov -d . のように一行です。CIS/PCI-DSS等のフレームワーク準拠チェックも持ちます。
--checkで重大なものから段階導入し、正当な例外は行内のskipコメントに理由付きで記録するのが現実的です。「なぜ無視したか」が残らない抑制は、半年後の監査で必ず問題になります。04第2層 — plan検証:diffそのものを検査対象にする
静的解析はコードを見ますが、plan検証は「これから何が起きるか」を見ます。ここがIaCテストの独自性です。terraform plan -out=tfplan.binary でバイナリplanを生成し、terraform show -json tfplan.binary > tfplan.json で機械可読なJSONに変換します。このJSONにはresource_changes(全変更)やchange.actions(create/update/delete)が含まれ、「実際に適用されるとどう変わるか」がモジュールやデフォルト値も解決済みの形で入っています。
これをOpen Policy Agent(OPA)とそのCLIラッパーconftestでRegoポリシーにかけます。コードのHCLではなくplanのJSONを見るため、「モジュール経由で最終的にどうなるか」を検査できるのが強みです。OPA公式のTerraform例では、削除・作成・変更を重み付けした「blast_radius(影響半径)」スコアを計算し、閾値を超える危険なplanや、IAMを変更するplanを自動で拒否する例が示されています。
05第2〜3層 — terraform test:HCLで書く公式テストフレームワーク
Terraform 1.6以降、terraform testという公式のテストフレームワークが同梱されました(公式ドキュメント)。新しい言語を覚える必要はなく、.tftest.hclファイルにHCLでrunブロックとassertブロックを書きます。ポイントはrunブロックのcommandで、ピラミッドの層を切り替えられることです。
command = plan:実インフラを作らず、planの結果に対してアサーションを評価する。単体テスト相当で速い。command = apply(デフォルト):実際にリソースを立て、生成されたインフラを検証し、テスト後に自動で破棄する。統合テスト相当。
さらにTerraform 1.7ではプロバイダのモックが導入され、実クラウドに接続せずにより詳細な単体テストが書けるようになりました。OpenTofuでも同等のtofu testが提供され、.tftest.hcl/.tofutest.hclを実行します(OpenTofu公式)。「テスト用に別言語(Go)を持ち込みたくない」チームには、この公式フレームワークが第一候補になります。
06第3層 — Terratest:実インフラを立てて本当に動くか確かめる
より踏み込んだ検証、たとえば「立てたWebサーバに実際にHTTPリクエストが通るか」「SSHでログインできるか」まで確かめたい場合は、Gruntwork社のTerratestが定番です(公式ドキュメント)。Goで_test.goを書き、①実IaCツールで実環境にデプロイ→②HTTP/API/SSH等で振る舞いを検証→③最後に破棄、という流れを回します。Gruntwork自身が30万行超のIaCライブラリを保守するために生まれたツールで、実運用の重みがあります。
deferによる破棄を必ず入れ、失敗時にリソースが残り続けないようにします。全モジュールに統合テストを課すとCIが遅く高くなりすぎるので、共有・再利用されるモジュールに限定するのが現実解です。マルチアカウント環境での分離設計はマルチアカウント統制の考え方と合わせて設計してください。07CIのどの段で何を回すか — 速い順に、落ちるなら早く
ツールが揃ったら、CIパイプラインに「速い順」で並べます。原則はfail fast。安くて速い検査を前段に置き、そこで落ちれば高い統合テストまで進ませない。これがコストと待ち時間を最小化します。
- プッシュ/PR時(毎回・数秒〜数十秒):
fmt -check→validate→tflint→checkov。ここまでは実クラウドに触れない。 - PR時(数十秒〜数分):
planを生成し、diffをPRにコメント表示 + OPA/Conftestでpolicy検査。terraform testのplan/mockモードもここ。 - マージ前/夜間(数分〜): サンドボックスでの
terraform test(apply)やTerratest。対象は共有モジュールに限定。 - マージ後: 本番
apply。ここは環境昇格やState管理の設計と密接なので、別稿で扱います。
plan結果をPRに可視化してレビュー材料にする運用は、AWSも新しいTerraform Test Frameworkと組み合わせて推奨しています(AWS DevOpsブログ)。State運用や環境昇格そのものは、IaCパイプライン設計の別テーマとして切り出して検討するのが整理しやすいです。
08コストと価値のバランス — 「全部やる」は正解ではない
最後に、SIer/エンタープライズの現場でいちばん効く話をします。テストは投資であり、青天井にやれば赤字になります。第1層(静的)は限界コストほぼゼロなので全リポジトリで必須。第2層(plan検証・policy)は、組織の禁止事項(公開バケット禁止、特定リージョン外禁止、IAM変更は要承認など)をコード化する価値が高く、統制の中核になります。ここまでは投資対効果が明確です。
迷うのは第3層です。統合テストは最も高価で、維持コスト(壊れやすいテストのメンテ)も無視できません。「全モジュールに統合テスト」を掲げると、たいてい形骸化します。影響範囲が広い共有基盤モジュールに絞り、それ以外はplan検証+policyで止める。この線引きこそがテスト戦略の本体です。DevOpsの成熟度を測るなら、テストの本数ではなく変更のリードタイムや変更失敗率で見るべきで、その観点はDORAとDeveloper Experienceで整理しています。なお具体的なバージョン挙動や課金は変わりうるため、導入前に公式ドキュメントで要確認としてください。
—まとめ
IaCのテストは「やるか否か」ではなく「どこまでやるか」です。fmt/validate/tflint/checkovの静的層を全リポジトリで厚く敷き、plan検証+OPA/Conftestで組織の禁止事項をコード化し、統合テスト(terraform testのapplyやTerratest)は共有モジュールに絞る。テストピラミッドの発想でCIに「速い順・fail fast」に並べれば、待ち時間もコストも抑えつつ事故の大半を止められます。「全部やる」ではなく、現場の制約に合わせた賢い線引きを。
—参考(一次情報)
- Tests - Configuration Language | Terraform | HashiCorp Developer
- Command: test | OpenTofu
- Terraform | Open Policy Agent
- Quick Start | Checkov
- tflint-ruleset-aws | GitHub (terraform-linters)
- Documentation | Terratest (Gruntwork)
- Terraform CI/CD and testing on AWS with the new Terraform Test Framework | AWS DevOps Blog