terraform dataの使い方|data sourceの参照設計と依存の暗黙化
terraform data で検索すると、dataブロック(データソース)の話と terraform_data リソースの話が混ざって出てきます。実装で手が止まるのは前者、すでにあるVPCやAMIをコードから引き当てる側です。この記事では、dataブロックがrefreshで読まれる場合とapplyへ遅延する3条件、AWSでタグやフィルタから引き当てるときに0件・複数件へ振れる問題の潰し方、terraform_remote_state が root の output しか返さずstate全体の読み取り権限を伴う制約、依存グラフから外れて削除順序が壊れる経路を、HashiCorp公式ドキュメントに沿って整理します。参照をやめて変数に倒すべき条件も示します。
まとめ:data sourceは参照専用・依存は明示・remote stateは最後
dataブロックは読み取り専用の参照であって、リソースの管理ではありません。作成も破棄もしないため、引き当てた対象が消えても Terraform は面倒を見ません。ここを取り違えると、参照先が先に消えた瞬間に plan がエラーで止まります。
読み取りのタイミングは2段階です。計算不要な値だけを参照しているならrefreshフェーズで読まれ、計画時点で実際の値が手に入ります。逆に、そのプランで変更予定の管理リソース属性に依存していると読み取りがapplyへ遅れ、下流の差分がまとめて未確定になります。
参照手段には優先順位があります。同じ apply で作るリソースは直接参照、構成を分けてあるなら output と terraform_remote_state、Terraform の外にある値はパラメータストア。タグ文字列で引き当てる data source は、依存関係が Terraform から見えなくなるため最後の手段に回します。
dataブロックの構文と読み取りタイミング・planで値が確定する条件
まず、resource との責務の違いと、いつ値が確定するかを固定します。ここが曖昧なままだと、plan の出力が読めません。
resourceとdata sourceの責務の違いと参照の書式
構文は data "TYPE" "LABEL" で、参照は data.TYPE.LABEL.ATTRIBUTE の形式です。resource ブロックが作成・更新・破棄のライフサイクルを持つのに対し、dataブロックは既存の対象を読むだけで、state には読み取った結果のスナップショットが入ります。
実務上の差は destroy のときに出ます。terraform destroy を打っても data source が指すVPCやAMIは消えません。管理下に置きたいのか、参照するだけでよいのかという線引きが、そのままブロックの選択になります。IaCとは?Infrastructure as Codeの仕組み・メリットと導入判断を解説で扱う宣言的な構成管理の範囲に、参照専用の対象は含まれないと考えてください。
refreshで読む場合とapplyへ読み取りが遅延する3条件
公式ドキュメントは、planフェーズ中にクエリを試み、条件によってapplyフェーズへ遅延させる2段階の動作を示しています。遅延が起きるのは次の場合です。
- dataブロックの設定が、現在のプランで変更予定の管理リソース属性に直接依存している
- カスタム条件が、そうした変更予定のリソースに依存している
- 引数が、applyフェーズで計算される値を参照している
この3つに当たらず、計算不要な値への参照だけで構成されていれば、データソースはrefreshフェーズで読み込まれ、計画時点で実際の値が使えます。遅延した場合の代償は、その属性を参照する下流のリソースの差分がすべて (known after apply) になることです。plan を見ても何が変わるか判断できない状態になります。
count・for_each・postconditionをdataに付ける場面
count と for_each はdataブロックでも使え、data.NAME[KEY] で個別に参照できます。環境ごとに引き当てるサブネットが異なるときは、for_each でキー付きに読むほうがインデックスのずれを避けられます。インデックスとキーの同一性の違い、および dynamic ブロックとの担当範囲の切り分けはterraform dynamicブロックとcount・for_eachの使い分け|index事故の回避で整理しています。
引き当ての正しさを固定したいときは lifecycle の postcondition を付けます。公式は postcondition をデータソースの読み込み後に評価すると明記し、失敗時は処理を停止すると定めています。ここが check ブロックとの分かれ目です。check は plan または apply の最終ステップで走り、失敗しても警告を出して続行するため、引き当てミスをその場で止める用途には向きません。止めたい条件は postcondition、監視したいだけの条件は check、と役割を分けます。
data blockとterraform_dataリソースの二義性と読み分け
検索語としての terraform data は、性質のまったく異なる2つを指しています。先に読み分けの手掛かりを置きます。
検索語terraform dataが指す2つの対象と判別の手掛かり
1つはdataブロック、つまりデータソース。もう1つは terraform_data という名前の組み込みリソースで、こちらは data ではなく resource ブロックとして書きます。
判別はブロックの先頭語だけで付きます。data "aws_vpc" "selected" ならデータソース、resource "terraform_data" "example" なら組み込みリソース。参照式も前者は data.、後者は terraform_data. から始まります。名前が似ているだけで、機能上のつながりはありません。
terraform_dataがnull_resourceを置き換える1.4系の経緯
terraform_data は Terraform 1.4 で追加された組み込みリソースで、null provider を同梱して使っていた null_resource の代替にあたります。公式の説明は「標準的なリソースのライフサイクルを実装するが、それ以外のアクションは直接取らない」というもの。
引数は input と triggers_replace の2つです。input は state に値を保存し、triggers_replace は値が変わったときにリソースを置き換えます。属性は一意な文字列の id と、input から導出される output。用途はリソースのライフサイクルに乗せて値を保持する場合と、対応する実リソースが無い provisioner を起動する場合の2つに絞られ、既存リソースの参照には使いません。
AWSの既存リソースをdata sourceで引き当てる実装と精度
ここからが本題のデータソースです。AWSでの引き当ては、精度をどう担保するかで運用の手間が変わります。
IDのハードコードをdata sourceへ寄せる判断の起点
起点は「そのIDが環境ごとに違うか」の一点です。vpc-0a1b2c3d のような値を直書きすると、dev・stg・prod それぞれに別の値を持たせる必要が生じ、tfvars が肥大します。名前タグやCIDRから引き当てれば、コードは1本で済みます。
逆に、参照先が組織で1つしかなく年単位で変わらないなら、直書きのほうが plan は速く、読み手にも値が見えます。判断はこの2択で、途中はありません。既存のAWS環境にTerraformを後入れする局面では、この線引きを最初に引いておくと後戻りが減ります。既存構成の棚卸しから設計まで含めて相談したい場合は、インフラ構築(AWS・Google Cloud・Azure)の相談窓口をご利用ください。
data sourceのフィルタが0件や複数件に振れるときの検証手順
多くのAWSデータソースは、条件に合う対象が0件でも複数件でもエラーとして扱います。プロバイダごとの挙動はレジストリのドキュメントで確認してください。AMIのように複数世代が並ぶ対象では、所有者の指定と最新を選ぶ引数を併用しないと、apply のたびに引き当てが変わります。
タグ引きの精度は、タグの一意性がそのまま上限になります。Name タグの重複は運用の途中で必ず起きるため、フィルタは名前だけに頼らず、VPC IDや用途タグと組み合わせるのが前提。そのうえで postcondition に件数や属性の条件を書き、引き当てのずれを apply 前に落とします。0件エラーの原因が「まだ作っていない」のか「タグが変わった」のかは、メッセージだけでは切り分けられません。
同一構成内のリソースをdata sourceで引かない理由と代替
同じ apply で作るリソースをdataブロックで引くのは避けます。plan の時点でまだ存在しないため0件エラーになり、depends_on で逃げても読み取りがapplyへ遅延して差分が見えなくなるからです。同一構成内なら aws_vpc.main.id のように属性を直接参照すれば、依存関係も自動で張られます。
すでに手作業で作ってある対象を管理下に置きたいなら、参照ではなく取り込みです。判断の分かれ目は、そのリソースを今後 Terraform で変更するかどうか。変更するなら terraform importで既存リソースをコード化する手順|importブロックとCLIの使い分けの手順で state に載せ、読むだけならデータソースに留めます。
terraform_remote_stateで別構成のoutputを参照する制約
構成を分割すると、別ディレクトリで作った値を参照したくなります。その標準手段が terraform_remote_state ですが、取れる範囲と権限の制約が独特です。
backendとconfigの指定とrootのoutputのみという範囲
指定するのは backend(必須)と config(任意のobject)の2つです。config には参照先のバックエンド設定と同じ値、S3であればバケット名・キー・リージョンを渡します。取得結果は outputs というオブジェクトに入り、参照先の root モジュールの output がすべて含まれます。
制約は範囲です。公式は、公開されるのはリモートstateスナップショットの root レベルの output 値だけで、リソースのデータやネストしたモジュールの output にはアクセスできないと明記しています。参照させたい値は、参照先の root で明示的に output に出しておく必要があるということ。tfstate 自体の構造とバックエンド設定は Terraform stateとは?tfstateの構造とS3バックエンド・移動削除の安全手順で扱っています。
state全体の読み取り権限が付く制約とtfe_outputsの選択
公式ドキュメントには警告が置かれています。root モジュールの output を読めるだけの権限を持つユーザーやサーバーは、直接のネットワークリクエストによって常に state スナップショット全体にもアクセスできる、という趣旨です。terraform_remote_state が返す値が output だけであっても、権限の粒度は state 全体になります。
つまり、本番のstateを参照する構成を1つ増やすたびに、本番state全体の読み取り権限を持つ主体が1つ増えます。HCP Terraform や Terraform Enterprise を使っているなら、公式は tfe_outputs データソースを推奨しています。理由も明示されており、output を取得するのに workspace の state への完全なアクセスを必要としないためです。権限を分けたい環境では、この差が採用理由になります。
remote stateとパラメータストア・変数受け渡しの比較
構成をまたぐ値の受け渡しには、remote state 以外の選択肢もあります。判断軸は、参照できる範囲・必要な権限・Terraform の外との連携有無の3つです。
| 受け渡し手段 | 参照できる範囲 | 必要な権限 | 向く場面 |
|---|---|---|---|
| 同一構成内の直接参照 | リソース属性すべて | 追加なし | 同じapplyで作る資源 |
| terraform_remote_state | rootのoutputのみ | state全体の読み取り | 構成を分けた自社基盤 |
| tfe_outputs | workspaceのoutput | outputの取得のみ | HCP Terraform利用時 |
| パラメータストア等 | 登録した値のみ | パラメータの読み取り | Terraform外との連携 |
| 変数で受け渡し | 渡した値のみ | 追加なし | 値が実質固定のとき |
remote state を選ぶ前提として、参照先の output 設計が固まっている必要があります。参照される側のモジュールがどこまでを output として公開するかは、Terraform moduleの分割粒度とoutput設計|自作とRegistryの判断で扱う境界設計と同じ問題です。output を後から削ると参照側が壊れるため、公開する値は増やしすぎないほうが後が楽になります。
data sourceで依存が暗黙化する経路と明示依存で守る削除順序
データソースの本当の落とし穴は、書き方ではなく依存関係です。Terraform が依存を追えなくなる経路を先に潰します。
data sourceが依存グラフから外れる典型と削除順序の事故
タグ名やCIDRの文字列で引き当てると、Terraform から見えるのは「文字列を条件に検索した」という事実だけです。引き当てた対象を作った側のリソースが、同じ state にあっても別の state にあっても、依存関係としては結ばれません。
事故はリソースを消すときに出ます。共有VPCを廃止する構成を先に apply すると、参照している側は次の plan で0件エラー。順序が逆でも、削除待ちの対象を引き当てたまま apply が進み、存在しないIDを掴んだリソースが作られることがあります。文字列引きは、参照ではなく検索だと考えてください。
depends_onをdataに付けて差分が未確定へ化けるときの代償
この順序問題への公式の答えが depends_on です。データソースのクエリを、指定した依存関係の完了後まで遅延させます。ただし遅延先はapplyフェーズです。
その結果、plan の時点でデータソースの属性が確定せず、それを参照する下流のリソースがまとめて (known after apply) になります。レビューで差分を確認する運用を採っているなら、この代償は小さくありません。plan 出力のどこまでを許容してマージするかの判定は、terraform planの差分の読み方|init・apply・destroyの安全手順の基準に沿って決めます。depends_on は順序を守るための最終手段で、常用するものではありません。
参照手段の優先順位と、直参照からremote stateへの後退
優先順位を断定します。第1に、同じ構成内なら属性を直接参照する。第2に、構成を分けてあるなら参照先で output に出し、terraform_remote_state か tfe_outputs で受ける。第3に、Terraform の管理外にある値はパラメータストアなど外部のレジストリに置き、そこから読む。
タグやCIDRでの検索は、上の3つがどれも取れないときだけです。具体的には、他部署が手作業で管理していてコード化の予定が無い対象、あるいはAMIのように提供元が更新し続ける対象。この2条件のどちらにも当たらないのにタグ引きを選んでいるなら、その設計は見直します。依存を暗黙化させる代わりに得られるのは、output を1行書く手間の節約だけです。
data sourceを見送る条件と、変数へ倒す損益分岐の判断
参照を増やせば設定は減りますが、planは遅くなり依存は見えにくくなります。見送る条件を条件付きで決めておきます。
参照先が実質固定のときにdata sourceを見送る判断基準
見送る条件は2つです。参照先が組織で1つしかなく年単位で変わらないこと。そして環境の数が3つ以下であること。この両方を満たすなら、データソースを置かずに変数で受け渡します。tfvars に3行書くほうが、毎回のAPI呼び出しよりも速く、値の出所も明確です。
失敗パターンとして多いのは、方針として全参照をdata source化する設計です。dataブロックは refresh のたびにプロバイダAPIを呼ぶため、数十本を超えると plan の待ち時間が体感で変わり、大規模構成ではAPIのレート制限に触れることもあります。定数として扱ってよい値まで検索する必要はありません。変数と locals の割り当て基準は terraform variableとlocals・tfvarsの使い分け|型制約と機密値で整理しています。
機密値をdata sourceで引かずephemeralへ寄せる線引き
シークレットストアからパスワードやAPIキーをdata sourceで読むと、その値は state に平文で保存されます。データソースは読み取り結果を state に記録する仕組みだからです。ここは設計で回避します。
公式は ephemeral resource について、state ファイルにもプランファイルにも情報を保存しないと明記しています。一時的な認証情報や短命なトークンはこちらに寄せ、リソース側に渡す値は write-only 引数への対応をプロバイダのドキュメントで確認します。両方が使えない環境では、tfstate の暗号化とバケットのアクセス制御で守る前提に切り替えるしかありません。機密値をdata sourceで引く設計は、この2段階を検討したうえでの最後の選択にします。
よくある質問
terraform data に関して検索されることの多い5点に、公式ドキュメントの記述をもとに答えます。
terraform dataとterraform_dataは何が違いますか?
別物です。terraform data という検索語が指すのは通常 data ブロック(データソース)で、既存リソースを読み取って参照する仕組み。一方 terraform_data は Terraform 1.4 で追加された組み込みリソースの型名で、resource ブロックとして書きます。null provider を入れずに null_resource と同じことをするための置き換えで、既存リソースの参照機能はありません。判別はブロックの先頭語が data か resource かで付きます。
data sourceはいつ読み取られますか?plan時ですか?
条件次第です。計算不要な値だけを参照している場合はrefreshフェーズで読み込まれ、計画時点で実際の値が使えます。applyへ遅延するのは、dataブロックの設定が現在のプランで変更予定の管理リソース属性に直接依存する場合、カスタム条件がそうしたリソースに依存する場合、引数がapplyフェーズで計算される値を参照する場合の3つです。遅延すると、そのデータソースを参照する下流の差分が (known after apply) 表示になります。
data sourceで見つからないときエラーになりますか?
多くのプロバイダでは0件がエラーになり、条件に複数件が該当する場合もエラーとして扱われます。ただし挙動はデータソースごとに異なるため、レジストリの該当ページで確認してください。引き当てを確実にする手段としては、フィルタ条件をタグ名だけに頼らずVPC IDなどと組み合わせること、そして lifecycle の postcondition に期待する属性の条件を書いて apply 前に止めることの2つがあります。postcondition は失敗時に処理を停止します。
terraform_remote_stateとoutputはどちらを使うべきですか?
両方が必要です。output は参照される側が値を公開する仕組み、terraform_remote_state は参照する側がその公開値を読む仕組みで、対になっています。取得できるのは参照先の root モジュールの output のみ。ネストしたモジュールの output やリソースのデータは取得できません。なお root の output を読める権限は state スナップショット全体への到達を許すため、HCP Terraform では tfe_outputs のほうが権限を絞れます。
data sourceの結果をimportの代わりに使えますか?
用途が異なるため代わりにはなりません。データソースは読み取り専用で、引き当てた対象の設定を Terraform から変更できず、destroy の対象にもなりません。今後 Terraform で変更・破棄する予定があるなら import で state に載せます。読むだけで十分、あるいは他部署が管理していて手を出さない対象なら、データソースに留めるほうが安全です。
関連記事
- IaCとは?Infrastructure as Codeの仕組み・メリットと導入判断を解説:宣言的な構成管理の考え方と導入判断。
- terraform importで既存リソースをコード化する手順|importブロックとCLIの使い分け:参照ではなく管理下に置く場合の手順。
- Terraform stateとは?tfstateの構造とS3バックエンド・移動削除の安全手順:remote stateの前提となるstateの構造。
- Terraform moduleの分割粒度とoutput設計|自作とRegistryの判断:参照される側のoutput境界の設計。
- terraform variableとlocals・tfvarsの使い分け|型制約と機密値:参照を変数に倒すときの割り当て基準。