|
| 1 | +--- |
| 2 | +title_tag: "Finding AWS import IDs and special cases" |
| 3 | +meta_desc: Learn how to find AWS resource IDs and handle CloudFormation-specific edge cases when importing resources into Pulumi. |
| 4 | +title: AWS import IDs and special cases |
| 5 | +h1: "Finding AWS import IDs and special cases" |
| 6 | +meta_image: /images/docs/meta-images/docs-meta.png |
| 7 | +aliases: |
| 8 | + - /docs/iac/guides/migration/migrating-to-pulumi/aws-import-ids/ |
| 9 | +menu: |
| 10 | + iac: |
| 11 | + name: Finding AWS import IDs |
| 12 | + parent: iac-guides-migration |
| 13 | + weight: 3 |
| 14 | +--- |
| 15 | + |
| 16 | +This guide explains how to discover the correct AWS resource IDs to use when importing existing CloudFormation- or CDK-managed resources into Pulumi, and calls out CloudFormation features that require special handling. |
| 17 | + |
| 18 | +## Finding Resource IDs |
| 19 | + |
| 20 | +## About Pulumi import |
| 21 | + |
| 22 | +The [`pulumi import`](/docs/iac/cli/commands/pulumi_import/) command allows you to bring a resource created outside of Pulumi under Pulumi management. This includes resources created by clicking in the AWS Console, or by other infrastructure as code tools such as Terraform, CloudFormation, and AWS CDK. Each resource to be imported requires a resource ID, along with a name for the resource, and its type. |
| 23 | + |
| 24 | +## Finding resource ids |
| 25 | + |
| 26 | +Whether you are running `pulumi import` for a single resource or using a bulk `import.json` file (for example, generated with `pulumi preview --import-file import.json`), you need to supply an ID that uniquely identifies the existing AWS resource. Sometimes this ID is a single value like a resource `ARN`, but other times it is a composite value made up of a combination of property values. For example, to import a [Lambda Permission](https://www.pulumi.com/registry/packages/aws/api-docs/lambda/permission/) resource you need both the `functionName` and the Permission `id` and the id suppled to `pulumi import` must be in the format `functionName|id`. |
| 27 | + |
| 28 | +The first place you should look for resource ids for Pulumi import is by querying the CloudFormation stack. Import ids for most Pulumi resource types can be extracted from the `PhysicalResourceId` property in CloudFormation: |
| 29 | + |
| 30 | +```bash |
| 31 | +$ aws cloudformation list-stack-resources --stack-name my-stack \ |
| 32 | + --query 'StackResourceSummaries[].{Type:ResourceType,LogicalResourceId:LogicalResourceId,Physical:PhysicalResourceId}' |
| 33 | +``` |
| 34 | + |
| 35 | +Optionally, you can use the `cdk2pulumi` tool to lookup information on the import ids. `cdk2pulumi` has an `ids` subcommand that returns information on the expected import id format: |
| 36 | + |
| 37 | +```bash |
| 38 | +$ pulumi plugin run cdk2pulumi -- ids AWS::Lambda::Permission |
| 39 | +Resource: aws-native:lambda:Permission (CFN: AWS::Lambda::Permission, provider: aws-native) |
| 40 | +Format: {functionName}|{id} |
| 41 | +Parts: |
| 42 | + - functionName (Input): The name or ARN of the Lambda function, version, or alias. |
| 43 | + **Name formats** |
| 44 | + + *Function name* – ``my-function`` (name-only), ``my-function:v1`` (with alias). |
| 45 | + + *Function ARN* – ``arn:aws:lambda:us-west-2:123456789012:function:my-function``. |
| 46 | + + *Partial ARN* – ``123456789012:function:my-function``. |
| 47 | + |
| 48 | + You can append a version number or alias to any of the formats. The length constraint applies only to the full ARN. If you specify only the function name, it is limited to 64 characters in length. |
| 49 | + - id (Output) |
| 50 | +``` |
| 51 | + |
| 52 | +### Finding IDs example |
| 53 | + |
| 54 | +Lets walk through an example of finding the import ids for a couple of resources. |
| 55 | + |
| 56 | +1. List the stack resources: |
| 57 | + |
| 58 | + ```bash |
| 59 | + $ aws cloudformation list-stack-resources --stack-name test-app-dev \ |
| 60 | + --query 'StackResourceSummaries[].{ResourceType:ResourceType,LogicalResourceId:LogicalResourceId,PhysicalResourceId:PhysicalResourceId}' |
| 61 | + [output] |
| 62 | + [ |
| 63 | + { |
| 64 | + "ResourceType": "AWS::ApiGatewayV2::Api", |
| 65 | + "LogicalResourceId": "Api48B32C1D", |
| 66 | + "PhysicalResourceId": "uzelpdmlxi" |
| 67 | + }, |
| 68 | + { |
| 69 | + "ResourceType": "AWS::ApiGatewayV2::Stage", |
| 70 | + "LogicalResourceId": "ApiDefaultStageB9B75A7A", |
| 71 | + "PhysicalResourceId": "$default" |
| 72 | + }, |
| 73 | + { |
| 74 | + "ResourceType": "AWS::ApiGatewayV2::Route", |
| 75 | + "LogicalResourceId": "ApiGEThelloF5F722C0", |
| 76 | + "PhysicalResourceId": "2kaoey7" |
| 77 | + }, |
| 78 | + { |
| 79 | + "ResourceType": "AWS::ApiGatewayV2::Integration", |
| 80 | + "LogicalResourceId": "ApiGEThellointegration392349BE", |
| 81 | + "PhysicalResourceId": "qwo3s38" |
| 82 | + } |
| 83 | + ] |
| 84 | + |
| 85 | + ``` |
| 86 | + |
| 87 | +1. Find the import id format for each: |
| 88 | + |
| 89 | + ```bash |
| 90 | + $ pulumi plugin run cdk2pulumi -- ids AWS::ApiGatewayV2::Api |
| 91 | + [output] |
| 92 | + Resource: aws-native:apigatewayv2:Api (CFN: AWS::ApiGatewayV2::Api, provider: aws-native) |
| 93 | + Format: {apiId} |
| 94 | + Parts: |
| 95 | + - apiId (Output): The API identifier. |
| 96 | +
|
| 97 | + pulumi plugin run cdk2pulumi -- ids AWS::ApiGatewayV2::Stage |
| 98 | + Resource: aws:apigatewayv2/stage:Stage (CFN: AWS::ApiGatewayV2::Stage, provider: aws) |
| 99 | + Format: {apiId}/{name} |
| 100 | + Parts: |
| 101 | + - apiId (Segment) |
| 102 | + - name (Segment) |
| 103 | + Import doc: to import `aws_apigatewayv2_stage` using the API identifier and stage name.//{ to = aws_apigatewayv2_stage.example id = "aabbccddee/example-stage"} |
| 104 | +
|
| 105 | + $ pulumi plugin run cdk2pulumi -- ids AWS::ApiGatewayV2::Route |
| 106 | + [output] |
| 107 | + Resource: aws-native:apigatewayv2:Route (CFN: AWS::ApiGatewayV2::Route, provider: aws-native) |
| 108 | + Format: {apiId}|{routeId} |
| 109 | + Parts: |
| 110 | + - apiId (Input): The API identifier. |
| 111 | + - routeId (Output): The route ID. |
| 112 | +
|
| 113 | + pulumi plugin run cdk2pulumi -- ids AWS::ApiGatewayV2::Integration |
| 114 | + Resource: aws-native:apigatewayv2:Integration (CFN: AWS::ApiGatewayV2::Integration, provider: aws-native) |
| 115 | + Format: {apiId}|{integrationId} |
| 116 | + Parts: |
| 117 | + - apiId (Input): The API identifier. |
| 118 | + - integrationId (Output): The integration ID. |
| 119 | + ``` |
| 120 | + |
| 121 | +Typically if the import id consists of a single value (e.g. `apiId` in the Api example) then it will be the `PhysicalResourceId` from CloudFormation. Similarly if it is a composite id where one of the values refers to the `id`, or `name` of itself (e.g. `routeId` of the Route resource) then this will also typically be the `PhysicalResourceId`. |
| 122 | + |
| 123 | +We would then update the `id`s in the bulk import file based on the format and values. |
| 124 | + |
| 125 | +```json |
| 126 | +{ |
| 127 | + "resources": [ |
| 128 | + { |
| 129 | + "type": "aws-native:apigatewayv2:Api", |
| 130 | + "name": "Api48B32C1D", |
| 131 | + "id": "uzelpdmlxi" |
| 132 | + }, |
| 133 | + { |
| 134 | + "type": "aws-native:apigatewayv2:Integration", |
| 135 | + "name": "ApiGEThellointegration392349BE", |
| 136 | + "id": "uzelpdmlxi|qwo3s38" |
| 137 | + }, |
| 138 | + { |
| 139 | + "type": "aws-native:apigatewayv2:Route", |
| 140 | + "name": "ApiGEThelloF5F722C0", |
| 141 | + "id": "uzelpdmlxi|2kaoey7" |
| 142 | + }, |
| 143 | + { |
| 144 | + "type": "aws:apigatewayv2/stage:Stage", |
| 145 | + "name": "ApiDefaultStageB9B75A7A", |
| 146 | + "id": "uzelpdmlxi/$default" |
| 147 | + } |
| 148 | + ] |
| 149 | +} |
| 150 | +``` |
| 151 | + |
| 152 | +### Looking up Resource IDs |
| 153 | + |
| 154 | +For some resource types, the resource ID may not be the value of its `PhysicalResourceId` in CloudFormation. In these cases it is necessary to perform AWS API calls to look up the necessary information: |
| 155 | + |
| 156 | +```bash |
| 157 | +$ aws cloudformation list-stack-resources --stack-name test-app-dev \ |
| 158 | + --query 'StackResourceSummaries[].{ResourceType:ResourceType,Logical:LogicalResourceId,PhysicalResourceId:PhysicalResourceId}' |
| 159 | +[ |
| 160 | + { |
| 161 | + "ResourceType": "AWS::EC2::EIP", |
| 162 | + "LogicalResourceId": "VpcPublicSubnet1EIPD7E02669", |
| 163 | + "PhysicalResourceId": "3.150.255.6" |
| 164 | + }, |
| 165 | + { |
| 166 | + "ResourceType": "AWS::ApplicationAutoScaling::ScalingPolicy", |
| 167 | + "LogicalResourceId": "StorageDynamoTableReadScalingTargetTrackingDB061E27", |
| 168 | + "PhysicalResourceId": "arn:aws:autoscaling:us-east-2:12345678910:scalingPolicy:c54f759a-aa04-4c0e-afbc-d45a960593a4:resource/dynamodb/table/Example-Dev-StorageDynamoTable201FACD8-1KCPDDFW2WLP6:policyName/ExampleDevStorageDynamoTableReadScalingTargetTrackingDE82FE6D" |
| 169 | + } |
| 170 | +] |
| 171 | +
|
| 172 | +``` |
| 173 | + |
| 174 | +If we look up the information on these two resources we will see these are not as straightforward as the previous examples. |
| 175 | + |
| 176 | +```bash |
| 177 | +$ pulumi plugin run cdk2pulumi -- ids AWS::ApplicationAutoScaling::ScalingPolicy |
| 178 | +Resource: aws-native:applicationautoscaling:ScalingPolicy (CFN: AWS::ApplicationAutoScaling::ScalingPolicy, provider: aws-native) |
| 179 | +Format: {arn}|{scalableDimension} |
| 180 | +Parts: |
| 181 | + - arn (Output): Returns the ARN of a scaling policy. |
| 182 | + - scalableDimension (Input): The scalable dimension. This string consists of the service namespace, resource type, and scaling property. |
| 183 | + + ``dynamodb:table:ReadCapacityUnits`` - The provisioned read capacity for a DynamoDB table. |
| 184 | + + ``dynamodb:table:WriteCapacityUnits`` - The provisioned write capacity for a DynamoDB table. |
| 185 | + + ``dynamodb:index:ReadCapacityUnits`` - The provisioned read capacity for a DynamoDB global secondary index. |
| 186 | + + ``dynamodb:index:WriteCapacityUnits`` - The provisioned write capacity for a DynamoDB global secondary index. |
| 187 | + + ... # truncated for brevity |
| 188 | +
|
| 189 | +pulumi plugin run cdk2pulumi -- ids AWS::EC2::EIP |
| 190 | +Resource: aws-native:ec2:Eip (CFN: AWS::EC2::EIP, provider: aws-native) |
| 191 | +Format: {publicIp}|{allocationId} |
| 192 | +Parts: |
| 193 | + - publicIp (Output): The Elastic IP address. |
| 194 | + - allocationId (Output): The ID that AWS assigns to represent the allocation of the address for use with Amazon VPC. This is returned only for VPC elastic IP addresses. For example, `eipalloc-5723d13e` . |
| 195 | +
|
| 196 | +``` |
| 197 | + |
| 198 | +Starting with the `ScalingPolicy` resource we can see that we need the `arn` which matches the `PhysicalResourceId`, but we also need the `scalableDimension` which is not in the CloudFormation data. Based on the information provided from the `ids` command we might be able to look at that CloudFormation resource and figure out which `scalableDimension` to use, otherwise we can use the `cloudcontrol` CLI commands. The `aws cloudcontrol list-resources` command will list all the resources of that type, which we can filter using `jq` to only include entries that have the part of the identifier that we know. |
| 199 | + |
| 200 | +```bash |
| 201 | +$ aws cloudcontrol list-resources --type-name AWS::ApplicationAutoScaling::ScalingPolicy --resource-model '{"ServiceNamespace": "dynamodb"}' --profile dev-admin | jq '.ResourceDescriptions[] | select(.Identifier | contains("arn:aws:autoscaling:us-east-2:12345678910:scalingPolicy:c54f759a-aa04-4c0e-afbc-d45a960593a4:resource/dynamodb/table/Example-Dev-StorageDynamoTable201FACD8-1KCPDDFW2WLP6:policyName/ExampleDevStorageDynamoTableReadScalingTargetTrackingDE82FE6D")) | .Identifier' |
| 202 | +
|
| 203 | +"arn:aws:autoscaling:us-east-2:12345678910:scalingPolicy:c54f759a-aa04-4c0e-afbc-d45a960593a4:resource/dynamodb/table/Example-Dev-StorageDynamoTable201FACD8-1KCPDDFW2WLP6:policyName/ExampleDevStorageDynamoTableReadScalingTargetTrackingDE82FE6D|dynamodb:table:ReadCapacityUnits" |
| 204 | +
|
| 205 | +
|
| 206 | +``` |
| 207 | + |
| 208 | +The `EIP` resource is an example of a resource which has an id containing a value that cannot be determined by either the CloudFormation data or the template. It requires the `publicIp`, which we have, and the `allocationId` which we do not. We can use the same `aws cloudcontrol list-resources` command to find the correct identifier. |
| 209 | + |
| 210 | +```bash |
| 211 | +$ aws cloudcontrol list-resources --type-name AWS::EC2::EIP --profile dev-admin | jq '.ResourceDescriptions[] | select(.Identifier | contains("3.150.255.6")) | .Identifier' |
| 212 | +
|
| 213 | +"3.150.255.6|eipalloc-0a79aa2cb81750a49" |
| 214 | +``` |
0 commit comments