$npx -y skills add pulumi/agent-skills --skill cloudformation-to-pulumiConvert, migrate, or import AWS CloudFormation stacks or templates into Pulumi programs. Load this skill whenever a user wants to move from CloudFormation to Pulumi, convert a CFN template, import existing CloudFormation-managed resources into Pulumi, or asks about CloudFormation
| 1 | ## IMPORTANT: PLAN ADJUSTMENT REQUIRED |
| 2 | |
| 3 | **If you have already generated a migration plan before loading this skill, you MUST:** |
| 4 | 1. Review your existing plan against the workflows and requirements in this skill |
| 5 | 2. Identify any gaps, missing steps, or incorrect assumptions |
| 6 | 3. Update and revise your plan to align with this skill's guidance |
| 7 | 4. Communicate the adjusted plan to the user before proceeding |
| 8 | |
| 9 | ## CRITICAL SUCCESS REQUIREMENTS |
| 10 | |
| 11 | The migration output MUST meet all of the following: |
| 12 | |
| 13 | 1. **Complete Resource Coverage** |
| 14 | - Every CloudFormation resource MUST be represented in the Pulumi program OR explicitly justified in the final report. |
| 15 | |
| 16 | 2. **CloudFormation Logical ID as Resource Name** |
| 17 | - **CRITICAL**: Every Pulumi resource MUST use the CloudFormation Logical ID as its resource name. |
| 18 | - This enables the `cdk-importer` tool to automatically find import IDs. |
| 19 | - DO NOT rename resources. Automated import will FAIL if you change the logical IDs. |
| 20 | |
| 21 | 3. **Successful Deployment** |
| 22 | - The produced Pulumi program must be structurally valid and capable of a successful `pulumi preview` (assuming proper config). |
| 23 | |
| 24 | 4. **Zero-Diff Import Validation** (if importing existing resources) |
| 25 | - After import, `pulumi preview` must show NO updates, replaces, creates, or deletes. |
| 26 | |
| 27 | 5. **Final Migration Report** |
| 28 | - Always output a formal migration report suitable for a Pull Request. |
| 29 | |
| 30 | ## WHEN INFORMATION IS MISSING |
| 31 | |
| 32 | If the user has not provided a CloudFormation template, you MUST fetch it from AWS using the stack name. |
| 33 | |
| 34 | ## MIGRATION WORKFLOW |
| 35 | |
| 36 | Follow this workflow **exactly** and in this order: |
| 37 | |
| 38 | ### 1. INFORMATION GATHERING |
| 39 | |
| 40 | #### 1.1 Verify AWS Credentials (ESC) |
| 41 | |
| 42 | Running AWS commands requires credentials loaded via Pulumi ESC. |
| 43 | |
| 44 | - If the user has already provided an ESC environment, use it. |
| 45 | - If no ESC environment is specified, **ask the user which ESC environment to use** before proceeding. |
| 46 | |
| 47 | **For detailed ESC information:** Use skill `pulumi-esc`. |
| 48 | |
| 49 | You MUST confirm the AWS region with the user. |
| 50 | |
| 51 | #### 1.2 Get the CloudFormation Template |
| 52 | |
| 53 | **If user provided a template file**: Read the template directly. |
| 54 | |
| 55 | **If user only provided a stack name**: Fetch the template from AWS: |
| 56 | |
| 57 | ```bash |
| 58 | aws cloudformation get-template \ |
| 59 | --region <region> \ |
| 60 | --stack-name <stack-name> \ |
| 61 | --query 'TemplateBody' \ |
| 62 | --output json > template.json |
| 63 | ``` |
| 64 | |
| 65 | #### 1.3 Build Resource Inventory |
| 66 | |
| 67 | List all resources in the stack: |
| 68 | |
| 69 | ```bash |
| 70 | aws cloudformation list-stack-resources \ |
| 71 | --region <region> \ |
| 72 | --stack-name <stack-name> \ |
| 73 | --output json |
| 74 | ``` |
| 75 | |
| 76 | This provides: |
| 77 | - `LogicalResourceId` - **Use this as the Pulumi resource name** |
| 78 | - `PhysicalResourceId` - The actual AWS resource ID |
| 79 | - `ResourceType` - The CloudFormation resource type |
| 80 | |
| 81 | #### 1.4 Analyze Template Structure |
| 82 | |
| 83 | Extract from the template: |
| 84 | - Parameters and their defaults |
| 85 | - Mappings |
| 86 | - Conditions |
| 87 | - Outputs |
| 88 | - Resource dependencies (Ref, GetAtt, DependsOn) |
| 89 | |
| 90 | ### 2. CODE CONVERSION (CloudFormation → Pulumi) |
| 91 | |
| 92 | **IMPORTANT:** There is NO automated conversion tool for CloudFormation. You MUST convert each resource manually. |
| 93 | |
| 94 | #### 2.1 Resource Name Convention (CRITICAL) |
| 95 | |
| 96 | **Every Pulumi resource MUST use the CloudFormation Logical ID as its name.** |
| 97 | |
| 98 | ```typescript |
| 99 | // CloudFormation: |
| 100 | // "MyAppBucketABC123": { "Type": "AWS::S3::Bucket", ... } |
| 101 | |
| 102 | // Pulumi - CORRECT: |
| 103 | const myAppBucket = new aws.s3.Bucket("MyAppBucketABC123", { ... }); |
| 104 | |
| 105 | // Pulumi - WRONG (DO NOT do this - import will fail): |
| 106 | const myAppBucket = new aws.s3.Bucket("my-app-bucket", { ... }); |
| 107 | ``` |
| 108 | |
| 109 | This naming convention is REQUIRED because the `cdk-importer` tool matches resources by name. |
| 110 | |
| 111 | #### 2.2 Provider Strategy |
| 112 | |
| 113 | **⚠️ CRITICAL: ALWAYS USE aws-native BY DEFAULT ⚠️** |
| 114 | |
| 115 | - Use `aws-native` for all resources unless there's a specific reason to use `aws`. |
| 116 | - CloudFormation types map directly to aws-native (e.g., `AWS::S3::Bucket` → `aws-native.s3.Bucket`). |
| 117 | - Only use `aws` (classic) when aws-native doesn't support a required feature. |
| 118 | |
| 119 | **This is MANDATORY for successful imports with cdk-importer.** The cdk-importer works by matching CloudFormation resources to Pulumi resources, and CloudFormation maps 1:1 to aws-native. Using the classic `aws` provider will cause import failures. |
| 120 | |
| 121 | #### 2.3 CloudFormation Intrinsic Functions |
| 122 | |
| 123 | Map CloudFormation intrinsic functions to Pulumi equivalents: |
| 124 | |
| 125 | | CloudFormation | Pulumi Equivalent | |
| 126 | |----------------|-------------------| |
| 127 | | `!Ref` (resource) | Resource output (e.g., `bucket.id`) | |
| 128 | | `!Ref` (parameter) | Pulumi config | |
| 129 | | `!GetAtt Resource.Attr` | Resource property output | |
| 130 | | `!Sub "..."` | `pulumi |