Terraform `external` プロバイダは「最後の切り札」だ。使いこなせば、IaCの限界を突破できる。
Terraformのコードを書いていて、「クラウドのAPIやSDKだけでは、どうしても取得できないメタデータがある」「既存のレガシーなDBやツールと連携してリソースを定義したい」と頭を抱えたことはないか?
多くのエンジニアはここで `null_resource` や `local-exec` に逃げる。だが、それは「状態を同期できない」という地獄への入り口だ。
今回は、Terraformの「最後の切り札」である `external` データソースを、現場の生産性を極限まで高めるための武器として解説する。
—
1. なぜ `external` なのか?:`null_resource` との決定的違い
まず、ここを履き違えてはいけない。
- `null_resource` / `local-exec`: 単なるコマンド実行。Terraformのステート(状態)を何も知らない。結果として、「冪等性」が崩壊し、リソースのドリフトを誘発する。
- `external` データソース: 外部スクリプトの出力をJSONとして受け取り、Terraformの変数として扱う。結果がステートに保存されるため、実行のたびにスクリプトが再実行されず、かつ出力の変化をTerraformが検知できる。
つまり、`external` を使えば、Terraformを「あらゆる外部システムを司るオーケストレーター」に昇華できる。
—
2. 実践:動的データをJSONで吸い上げる「神コード」
`external` のルールは簡単だ。「標準入力からJSONを受け取り、標準出力にJSONを返す」。これだけ守れば何でもできる。
構成例:AWS未対応の動的IPリストを動的に取得するスクリプト (`fetch_ips.sh`)
!/bin/bash
注意: エラー時は必ずstderrに出力すること。stdoutはJSON専用にする。
set -e
入力は標準入力からJSONで来る(今回は引数なしと想定)
処理内容: 外部のレガシーなIPホワイトリスト管理DBから最新IPを取得
IPS=$(curl -s https://legacy-api.internal/get-active-ips | jq -c .)
出力は必ず単一行のJSONであること
echo “{\”ips\”: \”$IPS\”, \”count\”: \”$(echo $IPS | jq ‘. | length’)\”}”
Terraform側の定義
data “external” “legacy_ips” {
program = [“bash”, “${path.module}/scripts/fetch_ips.sh”]
# スクリプトに引数を渡すことも可能(必要に応じて)
query = {
environment = var.env
}
}
取得したデータをリソースに反映
resource “aws_security_group_rule” “legacy_allow” {
type = “ingress”
cidr_blocks = jsondecode(data.external.legacy_ips.result.ips)
# …以下略
}
—
3. 現場で震えるほど役立つ「プロの作法」
① エラーハンドリングの鉄則
`external` で最も恐ろしいのは、スクリプトが異常終了した時にTerraformが中途半端な状態で止まることだ。
「JSON以外の出力はすべて stderr に回す」ことを徹底しろ。Terraformは `stderr` の内容をエラーメッセージとして表示してくれる。デバッグ効率が段違いになる。
② チーム開発で「スクリプトの依存」を解決する
スクリプトが依存する `jq` や `python` のバージョンがメンバー間でズレると、IaCは即死する。
`.tool-versions` (asdf) を使え。 これにより、プロジェクトルートに配置したスクリプトがどのランタイムを使うかをチーム全体で固定できる。
③ 隠れたキーボードショートカット(VS Code + Terraform)
- `Cmd + Shift + F`: Workspace全体検索。`external` を使った箇所を即座に特定する。
- `F12` (Go to Definition): 複雑な `external` スクリプトへ直接ジャンプできるよう、プロジェクト構造を整理しておくこと。
—
4. チームの生産性を底上げする「ベストプラクティス構成」
大規模プロジェクトでは、`external` スクリプトが散乱するとメンテナンス不能になる。以下のディレクトリ構成を強制しろ。
.
├── modules/
├── scripts/
│ ├── lib/ # 共通関数(ログ出力、JSON整形)
│ ├── fetch_ips.sh # 実行用スクリプト
│ └── validator.py # 入出力のスキーマ検証用
├── main.tf
└── providers.tf
【神プラグイン】
- `Terraform (HashiCorp)`: 基本。
- `Error Lens`: Terraformのバリデーションエラーをエディタ上で即座にハイライトする。これがないと仕事にならない。
—
5. 最後に:賢いエンジニアへの忠告
`external` は強力だが、「Terraformで完結できるなら、それに越したことはない」という原則を忘れてはならない。
`external` を使うのは、あくまで「Terraformのネイティブプロバイダが追いついていない領域」に限定せよ。
もしあなたが「あらゆるデータを `external` で取得したい」と考え始めたら、それは設計の敗北だ。だが、「どうしても必要な一点」のためにこの技を使うなら、あなたはチームのボトルネックを解消する真のテックリードになれる。
さあ、コードを開け。その場当たり的な運用を、今日で終わらせろ。