13
votes

Is there a reliable way in boto3 to determine what CloudFormation stack an AWS resource belongs to? Or if it belongs to a stack at all? Say I have a DynamoDB table or an EC2 instance, how do I find out what stack it is a member of? The boto3 API for CloudFormation gets pretty vague at the resource level, or so it appears. Any help is much appreciated.

4

4 Answers

6
votes

You can also use the AWS CLI to determine which stack a resource belongs to:

aws cloudformation describe-stack-resources --physical-resource-id "resourceId"

2
votes

You can pass PhysicalResourceId of a resource to desribe_stack_resources and get the stack information if it belongs to a CF stack To find an EC2 host for example

cf = boto3.client('cloudformation')
cf.describe_stack_resources(PhysicalResourceId="i-07bd92638b049ccc4")

AWS Documentation on this http://boto3.readthedocs.io/en/latest/reference/services/cloudformation.html#CloudFormation.Client.describe_stack_resources

2
votes

There is no single API to determine which stack a resource belongs to, however, a resource will be constructed with tags reflecting the origin stack. (AWS tagging is done through an internal service all the services communicate with, and they then expose that service through their own API.)

Some resources don't support tagging at all, so you'd have to scan stacks for those.

Three tags are added to resources generated by Cloudformation, and all of these names are reserved by AWS:

  • aws:cloudformation:stack-name
  • aws:cloudformation:stack-id
  • aws:cloudformation:logical-id

Cloudformation will let you look up a stack by its name or its ID. We shouldn't use the name, however.

Preferably, you want to look up by stack-id and check the stack status to see if it's a live stack.

The stack-id lets us handle stack deletion correctly, because once a stack with a given stack-id is DELETE_COMPLETE, it never exits that state.

Consider this scenario:

We create a stack named ExampleStack with an AWS::HypotheticalResource. The Hypothetical will be tagged with the name ExampleStack and ID arn:...:1234.

Say we mark that resource to be retained during deletion, and then delete the stack.

Now we recreate the stack, same template, same name. Now there's a new Hypothetical, and it's tagged with the name ExampleStack and the ID arn:...:4567.

If we look up arn:...:1234, Cloudformation will tell us the stack state is "DELETE_COMPLETE" so we know it once was associated with a live stack. If we searched by the stack name, that would falsely direct us to the new stack.

If we look up arn:...:4567, we can see the stack status is "CREATE_COMPLETE" so it is associated with a live stack.

We can further inspect the logical-id to match it to the logical ID in the stack's resources, and determine if the specific resource had a failure, e.g. it could be in a DELETE_FAILED state.

Relevant APIs

There's no standard way to get tags, and often you have to create the correct ARNs, unfortunately. As an example, one API is ListTagsOfResource for DynamoDB, but sometimes it's in their describe method. Generally, just search the service's page in boto's docs for "tags" and you should find it pretty easily. The Cloudformation tags themselves are standard as far as I know.

The DescribeStacks API; note that StackName is the argument you pass the ID to, and it should be (IIRC) the UUID portion of the ARN.

1
votes

Yes. Boto3 CF client has methods to get the information you want.

cf = boto3.client('cloudformation'
stacks = cf.list_stacks(StackStatusFilter=['CREATE_COMPLETE'])['StackSummaries'] 

will return the stack summary for completed stacks. Change the filter to suit your needs.

Get the names of the stacks

names = [stack['StackName'] for stack in stacks]

Then get all stack resources for a given stack

for name in names:
  resources = cf.describe_stack_resources(StackName=name)['StackResources']