Skip to content

Instantly share code, notes, and snippets.

@magnetikonline
Last active February 16, 2025 22:44
Show Gist options
  • Save magnetikonline/51bbb3de48dc4a10e11f38f9d911ac08 to your computer and use it in GitHub Desktop.
Save magnetikonline/51bbb3de48dc4a10e11f38f9d911ac08 to your computer and use it in GitHub Desktop.
Remove existing AWS CloudFormation stack, but retain all managed resources.

Delete CloudFormation stack - retaining resources

A guide for removing an existing CloudFormation stack - but retaining all managed resources.

First step - we need to get the CloudFormation stack into a state of DELETE_FAILED. This can be achieved by attempting stack delete with an IAM role that only has IAM action rights to cloudformation:DeleteStack and cloudformation:DescribeStackResources.

Create a new temporary IAM role with only the following allowed policy actions - for the rest of this guide that will be IAM role TEMP_CLOUDFORMATION_ROLE:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "cloudformation:DeleteStack",
        "cloudformation:DescribeStackResources",
        "iam:PassRole"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

...and the following trust relationship/assume role policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudformation.amazonaws.com"
      }
    }
  ]
}

Next, configure your AWS CLI via ~/.aws/config to include this new IAM role.

Important

Confirm you can successfully assume the temporary IAM role before attempting the failed delete operation - otherwise, you may successfully delete resources.

$ aws sts get-caller-identity --profile TEMP_CLOUDFORMATION_ROLE

{
  "UserId": "AIDXXXXXXXXXXXXXXXXXX",
  "Account": "1234567890",
  "Arn": "arn:aws:sts::1234567890:assumed-role/TEMP_CLOUDFORMATION_ROLE"
}

Now, proceed with the CloudFormation stack delete which will intentionally fail based on the IAM permissions set for the TEMP_CLOUDFORMATION_ROLE IAM role:

$ aws cloudformation delete-stack \
  --profile TEMP_CLOUDFORMATION_ROLE \
  --role-arn arn:aws:iam::1234567890:role/TEMP_CLOUDFORMATION_ROLE \
  --stack-name DELETE_THIS_STACK

The CloudFormation stack will now enter a DELETE_FAILED state.

Next, obtain a list of the logical resource IDs managed by the stack:

$ aws cloudformation describe-stack-resources \
  --profile TEMP_CLOUDFORMATION_ROLE \
  --stack-name DELETE_THIS_STACK \
  --output text \
  --query "join(' ',StackResources[].LogicalResourceId)"

Now delete the stack using the --retain-resources argument to aws cloudformation delete-stack - providing a space delimited list of logical resource IDs obtained above to retain:

$ aws cloudformation delete-stack \
  --profile TEMP_CLOUDFORMATION_ROLE \
  --retain-resources LOGICAL_RESOURCE_ID1 LOGICAL_RESOURCE_ID2 LOGICAL_RESOURCE_IDX \
  --role-arn arn:aws:iam::1234567890:role/TEMP_CLOUDFORMATION_ROLE \
  --stack-name DELETE_THIS_STACK

Finally, remove your temporary IAM role TEMP_CLOUDFORMATION_ROLE. Done!

Reference

@tgigli
Copy link

tgigli commented May 24, 2023

Would be interested to see an example of the commands you ran. I can only assume you didn't form the --retain-resources argument correct - or your temporary user had more IAM actions/rights beyond cloudformation:*.
The user would not be able to delete the RDS database without permissions to do so.

Yeah, sure.
As you can see, the policy
image

Then, I tried to run, with the --profile set to the temp user, ec2 describe-instances, a cloudformation list-stacks and then the sts get-caller-identity to be sure about the selected user. Describe instances was not possible, so, I thought that this user could not delete ec2 resources also.
Then I tried to retain resources, but, as you mention, it couldn't be done before the DELETE_FAILED state
(names changed for privacy reasons)

➜  stack git:(feature/DO-1039) ✗ aws cloudformation delete-stack \
  --profile cf-delete \
  --stack-name stagingStack \
  --retain-resources abc def ghy
An error occurred (ValidationError) when calling the DeleteStack operation: Invalid operation on stack [arn:aws:cloudformation:us-east-1:123456789012:stack/stagingStack/xxxxxxxxxxxxxx]. When you delete a stack, specify which resources to retain only when the stack is in the DELETE_FAILED state.

So, I removed the last line --retain-resources and re-ran. It doesn't show any output. The ec2 instances was not deleted because of a "deletion protection" that I've set to them before. I'm not 100% sure that I've set the same to the RDS database, but I remember to do it and set the "apply immediately" option. But this is another issue.
Well, the RDS and some other resources were deleted. :/

@magnetikonline
Copy link
Author

I would confirm the IAM user/IAM role assigned to --profile cf-delete only has the IAM action of cloudformation:* - as it honestly sounds like that is not the case. But I can't offer more I'm afraid without looking into your account.

@tgigli
Copy link

tgigli commented May 24, 2023

Yeap, buddy, I did. I made a review, step by step to be sure that I followed all the steps and, re-reviewed it again when printing and copying to put here.
One thing that my partner found and tested is that adding "DeletionPolicy": "Retain", to the resource at the template, really works. I mean, I can delete the stack, even without the --retain-resources param in the cli, and the resource is retained. (Accordingly to https://repost.aws/knowledge-center/delete-cf-stack-retain-resources)
I need to investigate if the user that has a policy with cloudformation.* can create/modify/delete resources from the stack, or if it needs specific policies to do that.
But, don't worry. I could restore the database quickly.

@magnetikonline
Copy link
Author

Thanks @tgigli 👍

Yeah I'd probably suggest in the future doing a dry run with test resources - but this technique hasn't failed me yet for working with VPCs/S3 buckets/NATs/etc. in the past when I've been trying to get away existing work from CloudFormation and over to Terraform.

@silveur
Copy link

silveur commented Jun 10, 2023

Nice trick!

@magnetikonline
Copy link
Author

I did exactly this process but my RDS database was deleted by cloudformation when deleting the stack with the temporary user :'(

@tgigli FWIW, did this today with an RDS database - it was retained, not dropped.

@martinhelfert
Copy link

martinhelfert commented Dec 19, 2023

@tgigli
You might have an IAM role attached to the stack (see stack info tab). This makes the deletion run with the role that is associated there, instead of the user role.
Append —role-arn NAME_OF_THE_TEMPORARY_ROLE to all cloudformation delete-stack commands. That worked in my case.
So basically, I just created the role from above and using my admin user with the —role-arn param on all delete-stack commands. This worked like a charm.

@magnetikonline
Copy link
Author

magnetikonline commented Dec 20, 2023

You might have an IAM role attached to the stack (see stack info tab). This makes the deletion run with the role that is associated there, instead of the user role.

@martinhelfert boom - I think you might have nailed it 👍

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudformation/delete-stack.html

If you don’t specify a value, CloudFormation uses the role that was previously associated with the stack. If no role is available, CloudFormation uses a temporary session that’s generated from your user credentials.

I might have to update this guide to use this arg (--role-arn) instead. Great callout 👍

@albertodiazdorado
Copy link

Would this work with resources that do not define a DeletionPolicy attribute, such as AWS::AutoScaling::AutoScalingGroup?

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-autoscalinggroup.html

@magnetikonline
Copy link
Author

magnetikonline commented Jan 8, 2024

Thanks again @martinhelfert - have updated the instructions to use an IAM role (not user) - and make use of --role-arn with all aws cloudformation delete-stack commands for additional safety. I think that's great advice 👍.

Also noted the IAM role needs a assume role policy of:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudformation.amazonaws.com"
      }
    }
  ]
}

otherwise the use of --role-arn won't work.

@SamuelNeves
Copy link

It would be really usefull if AWS just give us an option like --not-delete-resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment