リソースが、リスト/マップによって駆動される可変数の同一のネストされたブロック(例:イングレスルール)を必要とする。
`dynamic`ブロックを使用し、その`for_each`でコレクションを反復処理します。`content {}`内でブロックイテレータ(デフォルト名 = ブロックラベル)を介して各要素を参照します。
理由: 動的ブロックは、コピー&ペーストなしで繰り返されるネストされたブロックを生成します。イテレータは、生成された各ブロックをそのソース要素にバインドします。
最終確認:2026年5月
TF-PRO 試験で問われるアーキテクチャパターンのスキャン可能なリファレンス。上から順に読むか、セクションへジャンプ。
リソースが、リスト/マップによって駆動される可変数の同一のネストされたブロック(例:イングレスルール)を必要とする。
`dynamic`ブロックを使用し、その`for_each`でコレクションを反復処理します。`content {}`内でブロックイテレータ(デフォルト名 = ブロックラベル)を介して各要素を参照します。
理由: 動的ブロックは、コピー&ペーストなしで繰り返されるネストされたブロックを生成します。イテレータは、生成された各ブロックをそのソース要素にバインドします。
オブジェクトのマップ内のエントリごとに1つのリソースを作成する。再順序付けによって置換が強制されないように、キーは安定している。
`for_each = var.objects`(マップ)を設定します。安定したキーには`each.key`を、フィールドには`each.value.<attr>`を使用します。`count`はここでは避けてください — インデックスシフトがチャーンを引き起こします。
理由: マップキーは状態における安定したIDです。リストインデックスは位置に基づき、要素の追加/削除時にシフトします。
複数のインスタンスに対して`count`と`for_each`のどちらを使用するかを決定する。
インスタンスが明確なID(セット/マップ)を持つ場合は`for_each`を使用し、N個の同一で順序に依存しないコピーの場合のみ`count`を使用します。増加/減少する可能性のあるものには`for_each`を優先します。
理由: `for_each`はキー(resource["key"])でアドレス指定し、`count`はインデックス(resource[0])でアドレス指定するため、挿入/削除時に再シャッフルされます。
入力変数が一部の属性がオプションであり、デフォルト値を必要とするオブジェクトである。
`object({ name = string, size = optional(number, 10) })`として型を定義します。`optional(type, default)`は、呼び出し元が属性を省略した場合にデフォルト値を提供します。
理由: デフォルト値を持つ`optional()`は、呼び出し元を簡潔に保ちつつ、ダウンストリームで具体的な値を保証します — あらゆる場所でのnull処理が不要になります。
適用前にリソースに関する前提条件を検証するか、適用後に結果を保証する。
`lifecycle { precondition { ... } }`を使用して作成/更新前の入力をアサートし、`postcondition`を使用してその後の出力をアサートします。両方とも`condition`と`error_message`を取ります。
理由: カスタム条件は、壊れた適用や混乱を招くダウンストリームエラーを生成するのではなく、明確なメッセージで迅速に失敗します。
別のリソースまたは属性が変更されるたびに、リソースを再作成する必要がある。
`lifecycle { replace_triggered_by = [aws_x.y.id] }`を追加します。参照された値が変更されると、Terraformはこのリソースの置換を強制します。
理由: 置換の依存関係を宣言的に表現し、関連する変更ごとに手動で`-replace`を実行するのを回避します。
リソースを置換すると、新しいリソースが作成される前に古いリソースが破棄されるため、ダウンタイムが発生する。
`lifecycle { create_before_destroy = true }`を設定し、Terraformが最初に置換プロビジョニングを行い、次に古いものを破棄するようにします。一意の名前/ハードな競合がないことを確認してください。
理由: ゼロダウンタイムの置換。ただし、両方が一時的に存在する間は、名前の衝突とクォータ制限に注意してください。
無効な入力値(例:dev/stage/prodではない環境)を早期に拒否する。
変数に`validation { condition = contains(["dev","stage","prod"], var.env), error_message = "..." }`ブロックを追加します。
理由: プロバイダ呼び出しの奥深くで失敗するのではなく、計画時に読みやすいメッセージで不正な入力を検出します。
存在しない可能性のある値を、計画をクラッシュさせることなく参照する。
エラー発生時にフォールバックするには`try(local.maybe.value, "default")`を使用し、式が成功するかどうかのブール値を取得するには`can(expr)`を使用します。
理由: オプション/可変形状のデータを適切に処理します。欠落したキーに対する「Error: Unsupported attribute」を回避します。
リストをマップに変換するか、リソース引数のコレクションをフィルタリング/整形する。
`for`式を使用します: `{ for u in var.users : u.name => u.role if u.active }`(マップ)または`[for x in list : upper(x)]`(リスト)。
理由: `for`式はデータを再整形する慣用的な方法です。`if`句はフィルタリングを行い、`k => v`形式はマップを構築します。
変数または出力に、plan/applyの出力に表示すべきではない秘密情報が含まれている。
変数を`sensitive = true`とマークします(出力も同様)。TerraformはCLI出力でそれを編集しますが、状態にはまだ保存されています。
理由: ログ/CI出力での偶発的な情報漏洩を防ぎます。状態自体は引き続き保護される必要があります(暗号化されたバックエンド、アクセス制御)。
1つの設定内で2つのリージョン/アカウントのリソースを管理する。
エイリアス付きプロバイダ(`provider "aws" { alias = "west" region = "us-west-2" }`)を宣言し、リソースに`provider = aws.west`を設定するか、モジュールに渡します。
理由: エイリアスを使用すると、1つの設定で複数のプロバイダインスタンスをターゲットにできます。モジュールは`providers`引数を介して明示的にそれらを受け取ります。
(参照によって表現されていない)隠れた依存関係が順序の問題を引き起こす。
`depends_on = [aws_iam_role_policy.x]`を追加して順序を強制します。属性参照による暗黙的な依存関係を優先し、控えめに使用してください。
理由: 明示的な`depends_on`は、グラフが推測できない依存関係を処理しますが、過度に使用すると保守的で遅い計画が作成されます。
構造化された変数を持つテンプレートから設定ファイル/ユーザーデータをレンダリングする。
`templatefile("${path.module}/tpl.tftpl", { items = local.items })`を使用します。テンプレートは`%{ for }` / `${}`の補間を使用します。
理由: `templatefile`はレンダリングを純粋に計画時に行い(非推奨のテンプレートプロバイダとは異なり)、ループ/条件分岐をサポートします。
単一の`for_each`に供給するために、すべての(サブネット、ルール)の組み合わせのフラットなリストを構築する。
クロスプロダクトには`setproduct(var.subnets, var.rules)`を使用し、ネストされたリストを1つにまとめるには`flatten([for ...])`を使用します。
理由: これらの関数は、ネストされたデータを`for_each`が必要とするフラットで一意にキー付け可能なコレクションに変換します。
レジストリモジュールが変更され、次回の`init`時に予期せずインフラストラクチャが変更される。
`version = "~> 4.2"`でピン留めします(レジストリモジュールのみ)。Gitソースの場合、`?ref=v4.2.0`タグをピン留めします。意図的にピンを移動するには`terraform init -upgrade`を実行します。
理由: ピン留めされていないモジュールは最新版に自動的に更新されますが、ピン留めすることでアップグレードを意図的かつレビュー可能にします。
ルートモジュールが、子モジュールの奥深くで生成された値を必要とする。
子で`output`として公開し、`module.child.output_name`として参照します。出力されていない値は呼び出し元からアクセスできません。
理由: モジュールはカプセル化されています。出力は、データがモジュール境界を上方向に超える唯一の方法です。
マップからチーム/環境ごとに同じモジュールを1回インスタンス化する。
モジュールブロックに`for_each`を設定します: `module "env" { for_each = var.envs; source = "./env"; name = each.key }`。`module.env["prod"]`として参照します。
理由: モジュールでの`for_each`は、ブロックをコピー&ペーストすることなくパターンをスケールさせます。キーは安定したアドレスを提供します。
子モジュールが、デフォルトではない(エイリアスされた)プロバイダでリソースを作成する必要がある。
プロバイダを明示的に渡します: `module "x" { providers = { aws = aws.west } }`。子は`required_providers`内で`configuration_aliases`を使用してプロバイダを宣言します。
理由: モジュールはエイリアスされたプロバイダを暗黙的に継承しません。プロバイダマップは親のエイリアスを子に接続します。
リソースの名前変更やモジュールへの移動は、通常、そのリソースを破棄し再作成する。
`moved { from = aws_instance.old; to = module.compute.aws_instance.new }`ブロックを追加します。Terraformは破棄することなくステートアドレスを更新します。
理由: `moved`ブロックは、手動の`terraform state mv`を置き換え、コード内でのリファクタリングを安全かつレビュー可能にします。
モノリシックなモジュールが扱いにくくなり、ネットワーキング、コンピューティング、データに関する懸念が混在している。
焦点を絞った子モジュールに分解し、それらをルートで構成し、あるモジュールの出力を次のモジュールの入力として渡します。モジュールは単一の目的を維持します。
理由: コンポジションは再利用性とテスト容易性を向上させます。厳密にスコープされたモジュールは、独立してバージョン管理および進化します。
利用者が共有モジュールに無効な入力の組み合わせを渡す。
モジュール内に`validation`ブロックと`precondition`を追加して契約を強制し、`description`で入力を文書化します。
理由: モジュールは自身の契約を所有します。内部で検証することで、1つのルート設定だけでなく、すべての呼び出し元を保護します。
深くネストされたモジュールは、データの流れやプロバイダの受け渡しを追跡しにくくする。
ネストを浅く(1〜2レベル)保ちます。プロバイダと主要な入力を各レベルで明示的に渡し、深い暗黙的な継承に依存することを避けます。
理由: 浅いツリーは推論が容易です。深いネストは、プロバイダの受け渡しと出力の配管の複雑さを増幅させます。
再利用可能なモジュールをプライベートレジストリに公開し、呼び出し元を壊すことなく進化させる。
セマンティックバージョン(`v1.2.0`)でリリースにタグを付けます。入力/出力の破壊的な変更はメジャーバージョンを上げます。呼び出し元は`~>`制約でピン留めします。
理由: セマンティックバージョン管理により、消費者は修正/機能を安全に採用し、意図的に破壊的変更を選択できます。
指定された成熟度レベルのモジュールをどこから取得するかを選択する。
リポジトリ内モジュールにはローカルパス(`./modules/x`)、共有されているが未公開のモジュールにはGit(`git::...?ref=tag`)、バージョン管理/公開されたモジュールにはレジストリ(`namespace/name/provider`)を使用します。
理由: ソースタイプは共有スコープに一致します。`version`引数と制約解決をサポートするのはレジストリソースのみです。
モジュール出力がルートによって消費される秘密情報を含んでいる。
モジュール出力を`sensitive = true`とマークします。非機密コンテキストでそれを消費すると、同様に機密として扱われるまでエラーが発生します。
理由: 機密性はモジュール境界を越えて伝播し、ルート出力での偶発的な情報漏洩を防ぎます。
既存の`count`ベースのリソースセットを、インスタンスを破棄することなく`for_each`に移行する必要がある。
各`resource[0]`インデックスを新しい`resource["key"]`アドレスにマッピングする`moved`ブロックを追加し、その後`for_each`に切り替えます。
理由: `moved`ブロックは、状態のキーを位置指定からIDアドレス指定に再マッピングし、破棄/再作成を回避します。
設定でリソースの名前を変更しました。計画では古いリソースを破棄して新しいリソースを作成しようとしています。
設定では`moved`ブロックを優先します。アドホックなCLI修正には、既存のオブジェクトを再指定するために`terraform state mv aws_x.old aws_x.new`を使用します。
理由: どちらもステートアドレスを更新するため、Terraformは既存のオブジェクトを名前変更されたリソースとして認識します — 破棄は発生しません。
既存の手動で作成されたリソースをTerraform管理下に置く。
`import { to = aws_x.y; id = "i-123" }`ブロックを追加し、`terraform plan -generate-config-out=gen.tf`を実行して設定をスケルトン化し、その後調整して適用します。
理由: 設定駆動型インポートは、古い命令型`terraform import`とは異なり、レビュー可能であり、開始設定を生成します。
Terraformでのリソース管理を停止するが、クラウド上ではそのまま実行し続ける。
`terraform state rm aws_x.y`を実行します。Terraformはそのオブジェクトを忘れ、破棄されません。再作成計画を避けるために、その設定も削除します。
理由: `state rm`は削除せずにデタッチします — リソースを別のツール/チームに引き渡す場合に便利です。
状態をローカルバックエンドからS3(またはHCP Terraform)に移行する。
`backend`/`cloud`ブロックを追加/置換し、`terraform init`を実行します — Terraformは変更を検出し、既存の状態を新しいバックエンドに移行するかどうかを尋ねます。
理由: `init`がコピーを調整します。はいと答えることで、空から始めるのではなく、状態が安全に移行されます。
2人のエンジニアが同じリモートステートに対して同時に`apply`を実行する。
ロックをサポートするバックエンド(S3+DynamoDB、HCP Terraformなど)を使用します。Terraformは操作ごとにロックを取得します。2回目の実行は待機するかエラーになります。
理由: ロックは、状態を破損させる可能性のある同時書き込みを防ぎます。安易に無効にしないでください。
クラッシュした`apply`が古いロックを残し、すべての実行がブロックされている。
実際に実行中の操作がないことを確認し、`terraform force-unlock <LOCK_ID>`を実行します。エラーメッセージからIDを使用してください。
理由: `force-unlock`は孤立したロックをクリアします。実際の操作が実行中にこれを行うと、状態が破損するリスクがあります。
変更を提案することなく、設定/状態と実際のインフラストラクチャとの間のドリフトを検出する。
`terraform plan -refresh-only`を実行します(または状態を更新するために`apply -refresh-only`)。これはリソースの変更を計画することなく、差異を報告します。
理由: ドリフト検出と変更計画を分離します — 和解を決定する前に、クラウドで何が変更されたかを確認できます。
リソースが誤動作しており、設定を編集せずに再作成したい。
`terraform apply -replace="aws_instance.web"`を実行します。これは非推奨の`terraform taint`の現代的な代替手段です。
理由: `-replace`は、次の`apply`で1つのリソースを破棄して再作成することを強制し、CLIで宣言的に行います。
`—target`を日常的に使用して適用を高速化したい衝動に駆られている。
`-target`はエラーからの回復や外科的修正の場合にのみ使用してください。通常のワークフローとしては避けてください — 部分的な適用を生成し、依存関係をスキップする可能性があります。
理由: 日常的なターゲット指定は依存関係の問題を隠し、不完全な状態をもたらします。HashiCorpはこれを例外的なツールとして文書化しています。
プロバイダが名前空間を移動し(例: hashicorp/awsからフォークへ)、状態が古いアドレスを参照している。
`terraform state replace-provider registry.terraform.io/hashicorp/aws registry.example.com/org/aws`を実行します。
理由: 状態内のプロバイダ参照を書き換え、`init`/`plan`がリソースを再作成することなく新しいソースを解決できるようにします。
ある構成が、別の構成/ワークスペースによって生成された出力を必要とする。
`terraform_remote_state`データソース(またはHCP Terraformの実行出力)を使用して、別の状態の出力を読み取り専用で読み取ります。
理由: リソースを重複させることなく、状態の境界を越えて値を共有します。エクスポートされた出力のみが読み取り可能です。
バックエンド設定(バケット、キー)が環境ごとに異なり、ハードコードすべきではない。
`backend`ブロックからそれらを外し、`init`時に渡します: `terraform init -backend-config=prod.hcl`(または`-backend-config="key=..."`)。
理由: 部分的な設定により、1つの設定を複数の環境で再利用できるようにしつつ、`init`時に環境固有のバックエンド値を供給します。
1つの構成からdev/stage/prod用に個別の状態が必要である。
軽量な分離にはCLIワークスペース(`terraform workspace new prod`)を使用し、より強力な分離には個別のルート構成/HCPワークスペースを使用します。
理由: 各ワークスペースは独自の状態を持ちます。`terraform.workspace`を参照して命名/サイズを変更します。強力な分離のためには、異なるバックエンド/ワークスペースを推奨します。
HCP Terraformワークスペース変数に長期間有効なクラウドキーを保存するのを避ける。
動的プロバイダ資格情報を構成します。HCP TerraformはOIDC/ワークロードIDを使用して、実行ごとにAWS/Azure/GCP/Vaultから短期間有効な資格情報を取得します。
理由: 静的な秘密情報を排除します。資格情報はジャストインタイムで生成され、有効期限が切れるため、影響範囲を縮小します。
同じ変数(プロバイダ設定、タグ)が多くのワークスペースで必要とされている。
変数セットを定義し、それをプロジェクトまたは選択されたワークスペースに適用します。ワークスペースレベルの変数は、変数セットの値を上書きします。
理由: 変数セットは共有設定の重複を避けます。優先順位(ワークスペース > セット)により、必要に応じてワークスペースが上書きできます。
すべての実行でガードレール(パブリックS3なし、必須タグ)を強制する。
SentinelまたはOPAポリシーセットをアタッチします。強制レベルを設定します:アドバイザリ(警告)、ソフト強制(許可があれば上書き)、またはハード強制(ブロック)。
理由: コードとしてのポリシーは実行を一元的にゲートします。強制レベルは、厳密さと運用上の柔軟性のバランスを取ります。
外部チェック(コスト見積もり、セキュリティスキャン)を実行パイプラインに統合する。
ステージ(pre-plan、post-plan、pre-apply)で実行タスクを構成します。HCP Terraformは外部サービスを呼び出し、その結果に基づいて実行をゲートします。
理由: 実行タスクは、カスタムCIの配管なしで、サードパーティのチェックでパイプラインを拡張します。
ワークスペースの実行がどのようにトリガーされるかを選択する。
VCS駆動(コミット/PRが計画をトリガー)、CLI駆動(リモートに対する`terraform plan/apply`)、またはAPI駆動(アップロードされた構成)。チームのワークフローごとに選択します。
理由: VCS駆動はGitOpsに適しています。CLI駆動はローカルでの反復作業に適しています。API駆動はカスタムパイプラインに適しています。これらはワークスペースごとに相互排他的です。
チームにステージングワークスペースへの書き込みアクセス権を与え、本番環境へは読み取り専用アクセス権を与える。
組織/プロジェクト/ワークスペースレベルで権限をスコープします:プロジェクトまたはワークスペースごとにチームアクセス(読み取り/計画/書き込み/管理者)を割り当てます。プロジェクトのグループ化を使用して大規模に管理します。
理由: きめ細かくスコープされた権限は最小特権を強制します。プロジェクトレベルの付与は、ワークスペースごとの管理を削減します。
ネットワークワークスペースの適用が、依存するアプリケーションワークスペースで実行を自動的にキューに入れるべきである。
実行トリガーを構成します。ダウンストリームワークスペースはアップストリームを購読し、正常な適用はダウンストリーム実行をキューに入れます。
理由: 実行トリガーは依存するワークスペースを連鎖させ、共有インフラストラクチャの変更が順序どおりに伝播するようにします。
Terraformを使わないユーザーが、フォームを通じて標準化されたインフラストラクチャをプロビジョニングできるようにする。
プライベートレジストリにノーコードモジュールを公開します。ユーザーはUIを通じてそれをインスタンス化し、入力のみを提供します — HCLのオーサリングは不要です。
理由: ノーコードモジュールは、セルフサービスプロビジョニングを民主化しつつ、基盤となる設定をガバナンス下でバージョン管理された状態に保ちます。
組織全体で検証済みのモジュールとプロバイダを共有する。
HCP Terraformプライベートレジストリに公開します。利用者はバージョン制約付きで`app.terraform.io/org/name/provider`を参照します。
理由: プライベートレジストリは、内部モジュールの発見、バージョン管理、ガバナンスを一元化します。
数十のワークスペースをチーム/アプリケーションごとに整理し、権限と変数セットを設定する。
ワークスペースをプロジェクトにグループ化し、プロジェクトレベルでチーム権限と変数セットを適用します。
理由: プロジェクトはガバナンスをスケールさせます — ワークスペースごとではなく、プロジェクトごとにアクセスと共有設定を管理します。
本番環境が設定された状態からドリフトした際に継続的に検出する。
ワークスペースでヘルスアセスメント(ドリフト検出/継続的検証)を有効にします。HCP Terraformは定期的に更新を行い、ドリフトと失敗したアサーションを報告します。
理由: 自動評価は、適用間のドリフトと壊れた事後条件をインシデント発生前に明らかにします。
HCP Terraformが、パブリックイングレスのないプライベートネットワーク内のインフラストラクチャに到達する必要がある。
プライベートネットワークにHCP Terraformエージェントをデプロイし、ワークスペースをエージェントプールに割り当てます。実行はエージェントを介して行われます。
理由: エージェントを使用すると、HCP Terraformはプライベート/エアギャップ環境を公開することなく操作できます。
不正な適用によって状態が破損し、復旧が必要である。
HCP Terraformはバージョン管理された状態を保持します。ワークスペースUI/APIから以前の状態バージョンにロールバックし、再計画します。
理由: 組み込みの状態バージョン管理は、バックエンドのスナップショットを自分で管理することなく回復ポイントを提供します。