terraform import のやり方 — import ブロックで既存リソースをコードに取り込む
コンソールで急いで作った S3 バケットがあり、これからは Terraform で管理したいとします。リソースブロックをコードに書いて apply すればよいでしょうか。いいえ、うまくいきません。Terraform は自分の state にないリソースを「知らないもの」として扱うため(Terraform 基礎 #5)、同じ名前のバケットをもう 1 つ作ろうとして名前の衝突で失敗します。必要なのは「すでに存在するあのリソースが、このコードだ」と教える手順で、それが import です。この記事は、現行標準である import ブロック(Terraform 1.5 以上)基準の実践手順です。
手順の要約 #
- import ブロックを書きます(対象アドレス + import ID)
terraform plan -generate-config-out=generated.tfでコードの下書きを生成します- 下書きを整えてリソースブロックを確定します
- plan が「1 to import, 0 to change」になるまでコードを実際に合わせます
- apply 後に import ブロックを削除します
ステップ 1: import ブロックと ID #
import {
to = aws_s3_bucket.legacy
id = "my-console-made-bucket"
}to はこのリソースが持つことになる Terraform 上のアドレス、id は実際のリソースを特定する識別子です。ここでいちばんつまずきやすいのが id の形式です。リソースタイプごとに違うからです。S3 バケットはバケット名、EC2 インスタンスはインスタンス ID(i-…)で、セキュリティグループルールのように複合形式(sg-.../ingress/...)のものもあります。推測せず、プロバイダードキュメントの該当リソースページのいちばん下にある Import セクションを確認するのが正解です。すべてのリソースのドキュメントが、自分の import ID 形式を例つきで載せています。
ステップ 2: コードの下書きを生成する #
リソースブロックを手で書く前に、Terraform に下書きを任せます。
terraform plan -generate-config-out=generated.tfimport ブロックだけがあり、対応する resource ブロックがない状態でこのフラグを付けると、Terraform が実際のリソースを読み取って generated.tf にリソースブロックの下書きを作ってくれます。属性値をコンソールから目で書き写す労働がなくなります。
ステップ 3: 下書きを整える #
生成されたコードをそのまま使わない理由は 2 つあります。第一に、デフォルト値まですべて明示された冗長なコードで、読みにくいこと。第二に、null や空の値の引数が混ざっていて、そのままでは validate に引っかかることもある点です。下書きから意味のある引数だけを残して整理し、本来のコードファイルに移します。チームの既存のコードスタイル(変数の使用、共通タグ)に合わせるのもこの段階です。
ステップ 4: 「変更なし」になるまで #
整えたコードで plan を実行します。目標は明確です。
Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.ここで 0 to change ではなく change や replace が出るなら、コードと実際のリソースが食い違っているという意味です。そのまま apply すると、取り込みと同時に実際のリソースがコード側の値に修正されてしまうため、意図した変更でないなら plan の diff を見てコードを実際の値に合わせます。特に -/+(置き換え)が出たまま apply するのは、取り込みではなく再作成になるので必ず止まるべきです。この段階が import 作業の実質的な本体で、食い違いが 0 になった瞬間、取り込みの準備が整ったことになります。
ステップ 5: apply と後片付け #
apply すると state にリソースが登録され、以降はふつうの Terraform リソースと同じです。役目を終えた import ブロックは削除します(残しても害はありませんが、履歴は Git にあるのでコードはきれいに保ちます)。
知っておくべきこと #
- 旧方式との違い:
terraform import <アドレス> <ID>という CLI コマンドも今でも動きますが、state を即座に書き換えるコマンドなのでレビューができず、下書きの生成もありません。import ブロックは plan で結果を事前に確認して PR でレビューできるため、チーム作業のデフォルトです。 - 複数リソースの取り込み: import ブロックを複数並べれば、1 回の plan・apply で処理されます。互いに参照があるリソース(バケットとバケットポリシーなど)は一緒に取り込むほうが「変更なし」を作りやすいです。
- id に式を使う: id の場所には変数や式も使えるので、環境ごとに違う ID を変数で受け取る構成も可能です。
- 取り込み後の監査: 取り込んだリソースが多いなら、セキュリティ・コストのスキャナーを一度回してみる価値があります。コンソール時代の設定がチームの基準に合っていないことが多いからです。ドリフト検知と運用手順の文脈は Terraform 運用 #2で扱いました。
まとめ #
- 既存リソースは apply では取り込めません。import ブロックで「このリソースがこのコードだ」と宣言する手順が必要です
- import ID の形式はリソースごとに違います。プロバイダードキュメントの Import セクションが答え合わせの場所です
- リソースブロックは手で書かず、
-generate-config-outの下書きを整えます - 完了基準は「1 to import, 0 to change」です。change が残ったまま apply すると、取り込みと同時に実際のリソースが修正されます
- CLI コマンド方式より import ブロックのほうがレビューできるためチームのデフォルトです。取り込み後は import ブロックを消します