mcpField
C
cloudformation-to-pulumi

cloudformation-to-pulumi

github.com/pulumiクラウド・DevOps78892 回インストール3 週間前に更新
リポジトリ

cloudformation-to-pulumi について

AWS CloudFormation テンプレートを Pulumi プログラムへ手動変換し、既存リソースをインポートするためのスキルです。論理 ID の維持、aws-native の標準利用、差分のないプレビューによる検証を重視します。

主な機能

  1. 01CloudFormation テンプレート分析
  2. 02リソースごとの手動変換
  3. 03論理 ID の命名要件
  4. 04aws-native Provider の指針
  5. 05カスタムリソースの扱い
  6. 06インポートと差分ゼロ検証

活用シーン

  1. 01CloudFormation スタックを Pulumi に変換
  2. 02既存スタックのリソースを Pulumi インポート用に準備
  3. 03テンプレートのパラメーターと組み込み関数を対応付け
  4. 04インポート後の予期しない変更を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pulumi/agent-skills --skill cloudformation-to-pulumi

インストール後、Claude Code で/cloudformation-to-pulumiを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

cfn-importer.md
cloudformation-id-lookup.md
use_cases.yaml
agents/
openai.yaml

詳細

重要:計画の調整が必要です

このスキルを読み込む前に移行計画をすでに作成している場合は、必ず次の作業を行ってください。

  1. このスキルのワークフローと要件に照らして、既存の計画を確認します
  2. 不足している点、抜けている手順、または誤った前提を特定します
  3. このスキルの指針に沿うよう、計画を更新して修正します
  4. 作業を進める前に、調整した計画をユーザーに伝えます

成功に不可欠な要件

移行の成果物は、以下の要件をすべて満たす必要があります。

  1. すべてのリソースを網羅する

    • CloudFormation のすべてのリソースを Pulumi プログラムに含めるか、最終レポートで含めない理由を明示する必要があります。
  2. CloudFormation の論理 ID をリソース名として使用する

    • **重要:**すべての Pulumi リソースで、CloudFormation の論理 ID をリソース名として使用する必要があります。
    • これにより、cdk-importer ツールがインポート ID を自動的に見つけられます。
    • リソースの名前を変更しないでください。論理 ID を変更すると、自動インポートは失敗します。
  3. デプロイの成功

    • 作成する Pulumi プログラムは構造的に妥当であり、pulumi preview を正常に実行できる必要があります(適切な設定があることを前提とします)。
  4. 差分ゼロのインポート検証(既存のリソースをインポートする場合)

    • インポート後、pulumi preview で更新、置換、作成、削除が一切表示されない必要があります。
  5. 最終移行レポート

    • 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 リソース ID
  • ResourceType - 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 の同等機能に対応付けます。

CloudFormationPulumi の同等機能
!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::*)には、特別な対応が必要です。

  1. 目的を特定する:Lambda 関数のコードを読み、何を行うのかを把握します
  2. ネイティブな代替手段を探す:Pulumi に同じ機能を提供するネイティブリソースがあるか確認します
  3. 代替手段がない場合:手動での実装が必要であることを移行レポートに記載します
2.8 TypeScript の出力処理

aws-native の出力には undefined が含まれることがよくあります。! による非 null アサーションは避けてください。必ず .apply() で安全に値を取り出します。

// WRONG
functionName: lambdaFunction.functionName!,

// CORRECT
functionName: lambdaFunction.functionName.apply(name => name || ""),
3. リソースのインポート

変換後、既存のリソースをインポートして Pulumi で管理します。

3.0 インポート前の検証(必須)

インポートに進む前に、コードを確認してください。

  1. プロバイダーの使用状況を確認する:すべてのリソースで aws-native が使用されていることを確認するため、コードを調べます
  2. 例外を記録する:aws(クラシック)プロバイダーを使用する場合は、その理由を明記します
  3. リソース名を確認する:すべてのリソースで CloudFormation の論理 ID が名前として使用されていることを確認します
3.1 cdk-importer による自動インポート

リソース名に CloudFormation の論理 ID を使用しているため、cdk-importer ツールでリソースを自動的にインポートできます。

詳しいインポート手順は cfn-importer.md に従ってください。

3.2 インポートに失敗したリソースの手動インポート

自動インポートに失敗したリソースについては、次の手順に従ってください。

  1. インポート ID の形式を確認するには、cloudformation-id-lookup.md に従います
  2. pulumi import を使用します。
pulumi import <pulumi-resource-type> <logical-id> <import-id>
3.3 インポート後のプレビュー実行

インポート後、pulumi preview を実行します。次の変更があってはなりません。

  • 更新なし
  • 置換なし
  • 作成なし
  • 削除なし

変更がある場合は原因を調査し、プレビューに差分がなくなるまでプログラムを更新してください。

出力形式(必須)

移行を実施する際は、必ず次の内容を出力してください。

  1. 概要(全体的な説明)
  2. 移行計画の要約
  3. Pulumi コードの出力(TypeScript。ファイルごとに整理)
  4. リソースの対応表:
CloudFormation の論理 IDCFN タイプPulumi タイププロバイダー
MyAppBucketABC123AWS::S3::Bucketaws-native.s3.Bucketaws-native
MyLambdaFunction456AWS::Lambda::Functionaws-native.lambda.Functionaws-native
  1. カスタムリソースの概要(該当する場合)
  2. 最終移行レポート(PR 提出可能な状態)
  3. 次のステップ(インポート手順)

詳細なドキュメントについて

Pulumi の公式ドキュメントから内容を取得してください。

コメント