cloudformation-to-pulumi について
AWS CloudFormation テンプレートを Pulumi プログラムへ手動変換し、既存リソースをインポートするためのスキルです。論理 ID の維持、aws-native の標準利用、差分のないプレビューによる検証を重視します。
主な機能
- 01CloudFormation テンプレート分析
- 02リソースごとの手動変換
- 03論理 ID の命名要件
- 04aws-native Provider の指針
- 05カスタムリソースの扱い
- 06インポートと差分ゼロ検証
活用シーン
- 01CloudFormation スタックを Pulumi に変換
- 02既存スタックのリソースを Pulumi インポート用に準備
- 03テンプレートのパラメーターと組み込み関数を対応付け
- 04インポート後の予期しない変更を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ pulumi/ agent-skills --skill cloudformation-to-pulumiインストール後、Claude Code で/cloudformation-to-pulumiを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
cfn-importer.mdcloudformation-id-lookup.mduse_cases.yamlagents/openai.yaml詳細
重要:計画の調整が必要です
このスキルを読み込む前に移行計画をすでに作成している場合は、必ず次の作業を行ってください。
- このスキルのワークフローと要件に照らして、既存の計画を確認します
- 不足している点、抜けている手順、または誤った前提を特定します
- このスキルの指針に沿うよう、計画を更新して修正します
- 作業を進める前に、調整した計画をユーザーに伝えます
成功に不可欠な要件
移行の成果物は、以下の要件をすべて満たす必要があります。
-
すべてのリソースを網羅する
- CloudFormation のすべてのリソースを Pulumi プログラムに含めるか、最終レポートで含めない理由を明示する必要があります。
-
CloudFormation の論理 ID をリソース名として使用する
- **重要:**すべての Pulumi リソースで、CloudFormation の論理 ID をリソース名として使用する必要があります。
- これにより、
cdk-importerツールがインポート ID を自動的に見つけられます。 - リソースの名前を変更しないでください。論理 ID を変更すると、自動インポートは失敗します。
-
デプロイの成功
- 作成する Pulumi プログラムは構造的に妥当であり、
pulumi previewを正常に実行できる必要があります(適切な設定があることを前提とします)。
- 作成する Pulumi プログラムは構造的に妥当であり、
-
差分ゼロのインポート検証(既存のリソースをインポートする場合)
- インポート後、
pulumi previewで更新、置換、作成、削除が一切表示されない必要があります。
- インポート後、
-
最終移行レポート
- Pull Request に適した正式な移行レポートを必ず出力してください。
情報が不足している場合
ユーザーから CloudFormation テンプレートが提供されていない場合は、スタック名を使って AWS から取得する必要があります。
移行ワークフロー
以下のワークフローを、記載された順序どおりに実行してください。
1. 情報収集
1.1 AWS 認証情報の確認(ESC)
AWS コマンドを実行するには、Pulumi ESC を使って認証情報を読み込む必要があります。
- ユーザーが ESC 環境をすでに指定している場合は、それを使用します。
- ESC 環境が指定されていない場合は、作業を進める前に、どの ESC 環境を使用するかユーザーに確認してください。
**ESC の詳細情報:**スキル pulumi-esc を使用してください。
AWS リージョンをユーザーに確認する必要があります。
1.2 CloudFormation テンプレートの取得
**ユーザーがテンプレートファイルを提供した場合:**テンプレートを直接読み取ります。
**ユーザーがスタック名のみを提供した場合:**AWS からテンプレートを取得します。
aws cloudformation get-template \
--region <region> \
--stack-name <stack-name> \
--query 'TemplateBody' \
--output json > template.json
1.3 リソース一覧の作成
スタック内のすべてのリソースを一覧表示します。
aws cloudformation list-stack-resources \
--region <region> \
--stack-name <stack-name> \
--output json
これにより、次の情報が得られます。
LogicalResourceId- これを Pulumi のリソース名として使用しますPhysicalResourceId- 実際の AWS リソース IDResourceType- CloudFormation のリソースタイプ
1.4 テンプレート構造の分析
テンプレートから次の情報を抽出します。
- パラメーターとそのデフォルト値
- マッピング
- 条件
- 出力
- リソースの依存関係(Ref、GetAtt、DependsOn)
2. コード変換(CloudFormation → Pulumi)
**重要:**CloudFormation 用の自動変換ツールはありません。各リソースを必ず手作業で変換してください。
2.1 リソース名の規則(重要)
すべての Pulumi リソースで、CloudFormation の論理 ID をリソース名として使用する必要があります。
// CloudFormation:
// "MyAppBucketABC123": { "Type": "AWS::S3::Bucket", ... }
// Pulumi - CORRECT:
const myAppBucket = new aws.s3.Bucket("MyAppBucketABC123", { ... });
// Pulumi - WRONG (DO NOT do this - import will fail):
const myAppBucket = new aws.s3.Bucket("my-app-bucket", { ... });
cdk-importer ツールは名前でリソースを照合するため、この命名規則は必須です。
2.2 プロバイダー戦略
⚠️ 重要:デフォルトでは常に aws-native を使用してください ⚠️
- 特別な理由がない限り、すべてのリソースで
aws-nativeを使用してください。 - CloudFormation のタイプは aws-native に直接対応します(例:
AWS::S3::Bucket→aws-native.s3.Bucket)。 - 必要な機能が aws-native でサポートされていない場合に限り、
aws(クラシック)を使用してください。
cdk-importer によるインポートを成功させるために、これは必須です。cdk-importer は CloudFormation のリソースと Pulumi のリソースを照合して動作します。CloudFormation のリソースは aws-native に 1 対 1 で対応します。クラシックな aws プロバイダーを使用すると、インポートに失敗します。
2.3 CloudFormation 組み込み関数
CloudFormation の組み込み関数を Pulumi の同等機能に対応付けます。
| CloudFormation | Pulumi の同等機能 |
|---|---|
!Ref(リソース) | リソースの出力(例:bucket.id) |
!Ref(パラメーター) | Pulumi の設定 |
!GetAtt Resource.Attr | リソースプロパティの出力 |
!Sub "..." | pulumi.interpolate |
!Join [delim, [...]] | pulumi.interpolate または .apply() |
!If [cond, true, false] | 三項演算子 |
!Equals [a, b] | === による比較 |
!Select [idx, list] | .apply() を使った配列のインデックス指定 |
!Split [delim, str] | .apply(v => v.split(...)) |
Fn::ImportValue | スタック参照または設定 |
例:!Sub
// CloudFormation: !Sub "arn:aws:s3:::${MyBucket}/*"
// Pulumi:
const bucketArn = pulumi.interpolate`arn:aws:s3:::${myBucket.bucket}/*`;
例:!GetAtt
// CloudFormation: !GetAtt MyFunction.Arn
// Pulumi:
const functionArn = myFunction.arn;
2.4 CloudFormation の条件
CloudFormation の条件を TypeScript のロジックに変換します。
// CloudFormation:
// "Conditions": {
// "CreateProdResources": { "Fn::Equals": [{ "Ref": "Environment" }, "prod"] }
// }
// Pulumi:
const config = new pulumi.Config();
const environment = config.require("environment");
const createProdResources = environment === "prod";
if (createProdResources) {
// Create production-only resources
}
2.5 CloudFormation のパラメーター
パラメーターを Pulumi の設定に変換します。
// CloudFormation:
// "Parameters": {
// "InstanceType": { "Type": "String", "Default": "t3.micro" }
// }
// Pulumi:
const config = new pulumi.Config();
const instanceType = config.get("instanceType") || "t3.micro";
2.6 CloudFormation のマッピング
マッピングを TypeScript のオブジェクトに変換します。
// CloudFormation:
// "Mappings": {
// "RegionMap": {
// "us-east-1": { "AMI": "ami-12345" },
// "us-west-2": { "AMI": "ami-67890" }
// }
// }
// Pulumi:
const regionMap: Record<string, { ami: string }> = {
"us-east-1": { ami: "ami-12345" },
"us-west-2": { ami: "ami-67890" },
};
const ami = regionMap[aws.config.region!].ami;
2.7 カスタムリソース
CloudFormation のカスタムリソース(AWS::CloudFormation::CustomResource または Custom::*)には、特別な対応が必要です。
- 目的を特定する:Lambda 関数のコードを読み、何を行うのかを把握します
- ネイティブな代替手段を探す:Pulumi に同じ機能を提供するネイティブリソースがあるか確認します
- 代替手段がない場合:手動での実装が必要であることを移行レポートに記載します
2.8 TypeScript の出力処理
aws-native の出力には undefined が含まれることがよくあります。! による非 null アサーションは避けてください。必ず .apply() で安全に値を取り出します。
// WRONG
functionName: lambdaFunction.functionName!,
// CORRECT
functionName: lambdaFunction.functionName.apply(name => name || ""),
3. リソースのインポート
変換後、既存のリソースをインポートして Pulumi で管理します。
3.0 インポート前の検証(必須)
インポートに進む前に、コードを確認してください。
- プロバイダーの使用状況を確認する:すべてのリソースで
aws-nativeが使用されていることを確認するため、コードを調べます - 例外を記録する:
aws(クラシック)プロバイダーを使用する場合は、その理由を明記します - リソース名を確認する:すべてのリソースで CloudFormation の論理 ID が名前として使用されていることを確認します
3.1 cdk-importer による自動インポート
リソース名に CloudFormation の論理 ID を使用しているため、cdk-importer ツールでリソースを自動的にインポートできます。
詳しいインポート手順は cfn-importer.md に従ってください。
3.2 インポートに失敗したリソースの手動インポート
自動インポートに失敗したリソースについては、次の手順に従ってください。
- インポート ID の形式を確認するには、cloudformation-id-lookup.md に従います
pulumi importを使用します。
pulumi import <pulumi-resource-type> <logical-id> <import-id>
3.3 インポート後のプレビュー実行
インポート後、pulumi preview を実行します。次の変更があってはなりません。
- 更新なし
- 置換なし
- 作成なし
- 削除なし
変更がある場合は原因を調査し、プレビューに差分がなくなるまでプログラムを更新してください。
出力形式(必須)
移行を実施する際は、必ず次の内容を出力してください。
- 概要(全体的な説明)
- 移行計画の要約
- Pulumi コードの出力(TypeScript。ファイルごとに整理)
- リソースの対応表:
| CloudFormation の論理 ID | CFN タイプ | Pulumi タイプ | プロバイダー |
|---|---|---|---|
MyAppBucketABC123 | AWS::S3::Bucket | aws-native.s3.Bucket | aws-native |
MyLambdaFunction456 | AWS::Lambda::Function | aws-native.lambda.Function | aws-native |
- カスタムリソースの概要(該当する場合)
- 最終移行レポート(PR 提出可能な状態)
- 次のステップ(インポート手順)
詳細なドキュメントについて
Pulumi の公式ドキュメントから内容を取得してください。