概要
手動で作った S3 バケットや DynamoDB テーブルを CloudFormation でも管理したい——このときの選択肢は「既存の実体をそのまま取り込む Import」「同構成の別実体を作る Clone(複製)」「ゼロから作る 新規作成」の3つです。この記事では、それぞれが内部で何をしているかを切り分け、「既存リソースを 別リソース として二重管理する」という発想がなぜ成立しないのかを、内部動作と Import の検証ルールから説明します。
- 想定場面: 手動作成リソースの IaC 化 / スタック分割・統合(リファクタ) / 別アカウント・別リージョンへの複製
- つまずくポイント: 「Import すれば元リソースは残したままコピーが1つ増える」という誤解
- ゴール: Import / Clone / 新規作成を、内部動作と制約から使い分けられるようになる
Import・Clone・新規作成とは何か
3つの操作は「物理リソース(実体)を新しく作るか」「スタックの管理台帳に載せるか」の2軸で整理できます。
| 操作 | 物理リソースを新規作成するか | スタック管理に載せるか | 代表的な用途 |
|---|---|---|---|
| Import(リソースインポート) | しない(既存の実体をそのまま紐付け) | する | 手動作成リソースの IaC 化・スタック間移動 |
| Clone(複製) | する(同構成の別実体を作る) | する | 別アカウント・別リージョン展開・環境複製 |
| 新規作成 | する | する | ゼロから作る通常のスタック運用 |
- Import は「所有権の付け替え」。実体は1つのまま、CloudFormation がその状態を管理し始めるだけ。ARN も設定も変わりません。
- Clone は AWS の単一機能名ではなく、実務上は「IaC generator で既存リソースからテンプレを起こし、物理名を一意にして作り直す」流れを指します。結果として別 ARN の別実体が生まれます。別アカウント/リージョンへの展開が代表例ですが、今回の検証のように同一リージョンでもバケット名を変えれば作成できます。
-
新規作成 は Import と違い、同名リソースが既に存在すると
AlreadyExistsExceptionで衝突します。
「既存リソースを別リソースとして管理」が成立しない理由
Import は「コピーを増やす」操作ではありません。1つの物理リソースを2つのスタックが同時に管理することはできません。「元は残しつつ CloudFormation 版も持ちたい」は Import ではなく Clone(別実体を作る)の話になります。
現象
Import まわりでよく報告されるトラブルは、ほとんどが「Import が実体を作らない」性質の理解不足に起因します。
- Import 対象が既に別スタックに属していると、変更セットの作成時に
<リソース名> already exists in stack <スタックARN>で失敗する - 「Import したのに新しいリソースが増えない」——Import は実体を作らないので当然(誤解による報告)
- 「複製したかったのに Import してしまい、元リソースの管理者がスタックに移っただけ」になる
- IaC generator で起こしたテンプレを物理名を変えずに同一アカウント・同一リージョンで流すと、同名リソースが
AlreadyExistsExceptionで作成失敗する(今回の検証ではバケット名に-2を付けて回避し、同一リージョンでも作成できることを確認)
原因
Import はメタデータ操作であり、実体を作らない
Import が内部でやっているのは、「テンプレートの論理 ID ↔ 既存リソースの識別子」の対応付けです。識別子はリソース種別ごとに決まっており、例えば AWS::S3::Bucket なら BucketName を使います。CloudFormation はこの対応を内部状態に登録するだけで、CreateBucket のような物理リソース作成 API は呼びません。だから ARN も設定も変わらず、「別リソースとしてのコピー」は生まれません。
Import 時に CloudFormation が行う検証は次の4点です(公式ドキュメント: AWS リソースを CloudFormation スタックに手動でインポートする)。
- 取り込むリソースが実在すること
- プロパティがリソースタイプのスキーマ(受理されるプロパティ・必須プロパティ・許容値)に適合すること
- 必須プロパティがテンプレートに記述されていること
- 取り込むリソースが同一リージョンの別スタックに属していないこと
1リソース=1スタックの排他制約
上の検証の4番目が「二重管理できない」の根拠です。1つの物理リソースの「正」の管理者が複数存在すると、更新・削除の整合性が壊れるためです。結果として「同じリソースを2つのスタックに Import して別々に管理」はできず、今回の検証でも別スタックへ再 Import しようとすると、変更セット作成時に import-clone-demo-20260704 already exists in stack arn:aws:cloudformation:ap-northeast-1:<アカウントID>:stack/s3-import-test/...(=対象は既に別スタック s3-import-test が管理している)で拒否されました。
一方で、この検証はテンプレート記述と実設定の一致までは検証しません。公式にも CloudFormation は、テンプレート構成がリソースプロパティの実際の構成と一致しているかどうかをチェックしません。 と明記されています(AWS リソースを CloudFormation スタックに手動でインポートする)。
この非対称性が後述の「Import 後のドリフト検出必須」の根拠です。
Clone(複製)は別実体なので識別子が衝突しうる
IaC generator は既存リソースをスキャンしてテンプレート化しますが、生成されたテンプレートには元の物理名(BucketName 等)がそのまま入ります。これを物理名を変えずに同一アカウント・同一リージョンで新規作成すると、グローバル/リージョン一意な名前を持つリソースは AlreadyExistsException になります。
逆に物理名を一意にすれば、同一アカウント・同一リージョンでも別実体を作成できます。今回の検証では BucketName を import-clone-demo-20260704-2 に変えたテンプレート(docs/clone.yml)を同一リージョン(ap-northeast-1)で新規作成し、CREATE_COMPLETE(スタック名 clone-s3-test)と別 ARN の新しいバケット生成を確認しました。
別アカウント・別リージョンへ複製する場合は、元の名前のままでもリージョン境界を越えるため衝突しません。
移動(refactor)は Retain を挟む2段階操作
スタック間でリソースを移すときは、次の2段階を踏みます(公式手順: スタック間でのリソースの移動))。
-
移動元から切り離す: 移動元テンプレートで
DeletionPolicy: Retainを付けて更新し、論理定義を削除する(Retain により実体は残存) - 移動先へ取り込む: 移動先スタックへ Import する
Retain を付け忘れると、移動元スタックからの削除時に実体まで消えます。なお現在は、この手順を安全に自動化する スタックリファクタリング(スタックリファクタリング) という公式機能も用意されています。手作業で Retain を付け外しするより事故が起きにくいので、対応リージョンでは検討する価値があります。
切り分け
Import はデプロイ系オペレーションで、性能を示す CloudWatch メトリクスが出ません。そのため切り分けは「何を観測するか(スタックステータス/イベント)→ 何を判断するか → 次にどう動くか」の順で進めます。
判断フロー(観測 → 判断 → アクション)
| 観測ポイント(何を見るか) | 判断 | 次のアクション |
|---|---|---|
スタックステータスが IMPORT_COMPLETE にならず IMPORT_ROLLBACK_*、または変更セットが FAILED
|
Import 検証で拒否された | Events タブ/変更セットの理由を読む |
変更セット / Events に <リソース名> already exists in stack <スタックARN>
|
対象は既に別スタックが管理 | 二重 Import は不可。既存管理スタック側で扱う/移動(refactor)に切替 |
Events / API 応答に AlreadyExistsException
|
Import ではなく「新規作成」経路に入り同名衝突 |
ChangeSetType を IMPORT に直す/物理名を一意化 |
Import は成功したがドリフト検出で MODIFIED / NOT_CHECKED
|
テンプレ記述と実設定が不一致 | テンプレを実設定に合わせて更新(Import は一致を検証しない) |
「Import か Clone か 新規作成か」の選択
失敗要因を切り分けたうえで、そもそもどの操作を選ぶべきかは次の質問で判定します。
-
元の実体をそのまま使い続けたいか?
- はい → Import(またはスタック間移動)
- いいえ(別の実体が欲しい) → Clone または新規作成
-
対象リソースは既にどこかのスタックに属していないか?
- 属している(Events で二重 Import 拒否を観測) → まず移動(refactor: Retain → 削除 → Import)が必要。二重 Import は不可
- 属していない → そのまま Import 可能
-
別アカウント/別リージョンへ持っていきたいか?
- はい → IaC generator でテンプレ化 → 移送先で新規作成(=Clone)
- いいえ → 現アカウント内で Import
-
同名リソースが移送先に既にあるか?
- ある → 新規作成は
AlreadyExistsException。Import で取り込むか名前を変える
- ある → 新規作成は
メトリクス
Import はデプロイ系オペレーションであり、性能メトリクスというより スタックイベントとオペレーション状態 を追います。
- Import 操作のステータス(スタック単位):
-
IMPORT_IN_PROGRESS/IMPORT_COMPLETE/IMPORT_ROLLBACK_IN_PROGRESS/IMPORT_ROLLBACK_FAILED/IMPORT_ROLLBACK_COMPLETE
-
- IaC generator の scan は リージョン全体 が対象。
- 1スキャンで処理できるリソース: 最大 100,000
- 1テンプレートにモデル化できるリソース: 合計 500(同時モデル化は 5)
- アカウントあたり同時にテンプレート生成できる数: 5
- アカウントあたり生成テンプレート総数: 最大 1,000
- スキャン回数: 1万リソース未満なら1日 10 回、超なら1日 1 回
- CloudFormation の Import 専用の CloudWatch メトリクスは用意されていません。監視はスタックイベント/CloudTrail 側で行います。
クォータ詳細(公式)
・IaC ジェネレーターを使用して既存のリソースからテンプレートを生成する
・CloudFormation クォータを理解する
ログ確認
-
スタックイベント/変更セットの理由(コンソールの Events タブ・変更セット画面 /
DescribeStackEvents) を第一に見ます。Import 失敗時はここに失敗理由が出ます。今回の検証では、二重 Import は変更セットの作成段階でエラーとして表示されました。- 例(今回の検証で観測):
import-clone-demo-20260704 already exists in stack arn:aws:cloudformation:ap-northeast-1:<アカウントID>:stack/s3-import-test/... - いずれも「取り込むリソースが同一リージョンの別スタックに属している」という検証拒否を意味します
- 例(今回の検証で観測):
-
AlreadyExistsException— Import ではなく「新規作成」経路に入って同名リソースと衝突したサインです。ChangeSetTypeの指定ミスを疑います。 -
CloudTrail —
CreateChangeSet/ExecuteChangeSet(ChangeSetType=IMPORT)の履歴で、誰がいつ Import を仕掛けたかを追えます。 - Import 後は ドリフト検出(ドリフト検出を使用してスタックとリソースへのアンマネージド型設定変更を検出する) を必ず実行します。CloudFormation は Import 時に「テンプレートの記述と実設定が一致するか」までは検証しないため、記述漏れがドリフトとして表面化します。
暫定対応
-
二重 Import で詰まったら: まず
DescribeStacksやリソース一覧で「今どのスタックが管理者か」を確認し、Import は諦めて既存スタック側で管理します(一時的に運用を分けない)。 - 複製したいだけなら Import を止める: 元実体をそのまま使いたいのでなければ、Import ではなく IaC generator でテンプレを起こして別リージョン/アカウントに新規作成します。
-
AlreadyExistsExceptionの一時回避: 作成側の物理名(BucketName等)を一意な名前に変えて回避します(恒久的には Import で取り込むか設計を見直す)。
恒久対応
-
手動リソースを IaC 化したい: 各リソースに
DeletionPolicyを付けたテンプレートを用意し、ChangeSetType=IMPORTの change set で取り込みます(実体はそのまま管理下に入る)。 -
スタックを分割/統合したい(リファクタ): 「移動元で
DeletionPolicy: Retainを付けて論理定義を削除」→「移動先へ Import」の2段階を守ります。対応リージョンでは公式のスタックリファクタリング機能を使うと Retain の付け外しを自動化でき、事故を減らせます。 - 同一アカウント/同一リージョン内でリソース名を変更したものを複製したい: IaC generator でスキャン → テンプレート生成 → 移送先で新規スタック作成(=Clone)。物理名は移送先で一意になるよう調整します。
- Import 完了後は必ずドリフト検出を実行し、テンプレートと実体の乖離を解消してから通常運用に戻します。
よくある誤解
- 「Import すると元リソースのコピーが1つ増える」→ 誤り。Import は実体を作らず、管理者(スタック)を紐付けるだけ。ARN も設定も不変。
-
「同じリソースを複数スタックで別々に管理できる」→ 不可。今回の検証では
<リソース名> already exists in stack <スタックARN>で拒否された。1リソース=1スタックが原則。 - 「Import で別アカウントに持っていける」→ 直接は不可。別アカウント展開は IaC generator でテンプレ化 → 移送先で新規作成(Clone)という別ルート。
- 「Import すればテンプレートと実体が一致している保証がある」→ 誤り。CloudFormation は Import 時に実設定との一致まで検証しない。Import 後のドリフト検出が必須。
-
「DeletionPolicy は Import には無関係」→ 誤り。Import 対象には
DeletionPolicy必須。スタック間移動ではRetainを挟まないと実体ごと消える危険がある。
簡易的な検証リソース構成
「Import は複製ではない」「同一リソースを二重 Import できない」「Clone は別実体を作る」「Retain ならスタックを消しても実体は残る」を最小構成で体感します。検証用の「既存リソース」は Terraform で用意します。
以下の検証はすべて AWS マネジメントコンソール(GUI) 上で実施しました。
検証に使用したリソースおよび詳細手順は以下Githubリポジトリにて公開しています。【Githubリポジトリ】
aws-cfn-import-clone-demo
準備(Terraform)
CloudFormation 管理外の「既存リソース」を1つ作ります。
resource "aws_s3_bucket" "existing" {
bucket = "import-clone-demo-20260704" # リージョン/グローバルで一意な名前
}
検証1(インポートの成功事例)
- スタックステータスが
IMPORT_COMPLETEになり、取り込みが成功することを確認する。
※ import操作はClassMethodさんの以下のサイトを主に参考にさせていただきました。
検証結果
- 現状のS3の状態をスキャン
「ステップ1.アカウントのリソースをスキャンする > 新しいスキャンを開始 > 特定のリソースをスキャン」を押下。

「AWS::S3::Bucket」にチェックをして「スキャンを開始」を押下。

- Terraformで事前に作成したS3のインポートを実施
「ステップ2.CloudFormationテンプレートを作成する > テンプレートを作成」を押下。

「テンプレートを準備:新しいテンプレート」を選択し、任意のテンプレート名を入力し、「次へ」を押下。

「テンプレート:生成されたテンプレート」を選択し、任意のスタック名を入力後「次へ」を押下。

「CloudFormation > スタック」にて作成したスタック(スタック名: s3-import-test)のステータスが「IMPORT_COMPLETE」になっていることを確認。

補足
Import は物理実体を作らないため、この時点でも既存バケット import-clone-demo-20260704 の ARN・作成日時は変わりません(新しいバケットは増えていません)。
検証2(二重 Import の拒否・意図的な失敗)
- 検証1で
s3-import-testに取り込んだのと同じバケットを、別スタックにもう一度 Import しようとする。 - ウィザードは最後まで進められるが、変更セットの作成段階でエラーになり、取り込めないことを確認する。
「スタックの作成 > 既存のリソースを使用(リソースをインポート)」を押下。

「テンプレートリソース:テンプレートファイルのアップロード」より、 verification-1.yml をアップロードし「次へ」を押下。

「BucketName」にインポート済みのS3バケット名(import-clone-demo-20260704)を入力し、「次へ」を押下。

変更セットの作成中にエラーが発生し、取り込めないことを確認。エラー内容は import-clone-demo-20260704 already exists in stack arn:aws:cloudformation:ap-northeast-1:<アカウントID>:stack/s3-import-test/... で、対象が既に検証1のスタック s3-import-test に属していることが理由。

検証3(内部設定のClone作成の実施)
- IaC generator で同じバケットからテンプレートを生成し、同一アカウント・同一リージョン(ap-northeast-1) で新規作成する。
- ただし物理名(
BucketName)だけはimport-clone-demo-20260704-2に変えておく(元の名前のままだとAlreadyExistsExceptionで衝突するため)。 - 物理名以外は同一の内容の別実体が、同一リージョンでも作成できることを確認する。
「スタックの作成 > 新しいリソースを使用(標準)」を押下。

「テンプレートの準備:既存のテンプレートを選択」を選択し、「テンプレートソース:テンプレートファイルのアップロード」を選択し、 clone.yml (BucketName: import-clone-demo-20260704-2)をアップロードする。

任意のスタック名(今回は clone-s3-test)を入力し、「次へ」を押下。

「CloudFormation > スタック」にて作成したスタック(clone-s3-test)のステータスが「CREATE_COMPLETE」になっていることを確認。

S3バケット import-clone-demo-20260704-2 が新しく作成され、元の import-clone-demo-20260704 とは別 ARN・別作成日時の別実体になっていることを確認。

検証4(DeletionPolicy によるスタック削除時の挙動の違い)
- 検証3で作成した Clone スタック
clone-s3-test(対象バケットimport-clone-demo-20260704-2)を使って、DeletionPolicyの値でスタック削除時の挙動がどう変わるかを確認する。 -
DeletionPolicy: Retainのスタックを削除すると、スタックは消えるが S3 バケット(物理実体)は残存することを確認する(ARN・作成日時は不変)。 - 対比として、
DeletionPolicy: Delete(または未指定)のスタックを削除すると、実体まで消えることを確認する。これがスタック間移動で Retain を挟む理由。
テンプレートは検証3の clone.yml (
DeletionPolicy: Retain)と、値だけを変えた clone-delete.yml (DeletionPolicy: Delete)を使い分けています。
「DeletionPolicy: Retain」の場合
clone-s3-test スタックのテンプレートが「DeletionPolicy: Retain」であることを確認。

スタック削除後にS3を確認し、バケット import-clone-demo-20260704-2 が残っていることを確認。

「DeletionPolicy: Delete」の場合
clone-delete.yml(DeletionPolicy: Delete)で clone-s3-test を作り直し、テンプレートが「DeletionPolicy: Delete」であることを確認。

スタック削除後にS3を確認し、バケット import-clone-demo-20260704-2 が削除されていることを確認。

補足
検証後は残存したバケットを手動削除して後片付けします。
まとめ
- CloudFormation の Import は「所有権の付け替え」 であり、既存リソースを別リソースとして複製する機能ではない。
- 1つの物理リソースを複数スタックで管理することはできない(二重 Import は明示的に拒否される)。
- 「元を残しつつコピーも持ちたい」は Import ではなく Clone(IaC generator でテンプレ化 → 別リージョン/アカウントで新規作成) の領域。
- スタック間の移動は 「Retain で切り離す → 移動先へ Import」の2段階 を守る(公式のスタックリファクタリング機能でも代替可)。Retain 忘れは実体消失につながる。
- Import 対象には DeletionPolicy 必須、Import 後は ドリフト検出必須(実設定との一致は保証されない)。











