Delete ECR images using CloudFormation Custom Resources

Delete ECR images using CloudFormation custom resources AWS_EN

Delete ECR images using CloudFormation Custom Resources

If you use CloudFormation to create an ECR and push an image to it, you may encounter an error during the CloudFormation stack.
This is due to an attempt to delete the ECR with the image still in place.

With the image remaining in ECR, the stack deletion fails.

In this case, we will use CloudFormation custom resources to automatically remove the images from the ECR repository when deleting the CloudFormation stack.
By deleting the image in advance, we aim to ensure that the stack is deleted without error.


Diagram of delete ECR images using CloudFormation custom resources

Create a CloudFormation stack and define two resources inside it.

The first is the ECR.
Push images to this repository.

The second is a Lambda function.
This function is set up as a custom resource.
It should be configured to automatically remove images from the ECR repository when the stack is deleting.
The runtime for the function is Python 3.8.

CloudFormation template files

Build the above configuration with CloudFormation.
The CloudFormation templates are located at the following URL

awstut-fa/078 at main · awstut-an-r/awstut-fa
Contribute to awstut-an-r/awstut-fa development by creating an account on GitHub.

Explanation of key points of the template files

This page focuses on how to remove an ECR image using a custom resource.

For more information on CloudFormation custom resources, please refer to the following page

Lambda functions to invoke with custom resources

Resources: Function: Type: AWS::Lambda::Function Properties: Code: ZipFile: | import boto3 import cfnresponse import os account_id = os.environ['ACCOUNT_ID'] ecr_repository_name = os.environ['ECR_REPOSITORY_NAME'] ecr_client = boto3.client('ecr') DELETE = 'Delete' response_data = {} def lambda_handler(event, context): try: if event['RequestType'] == DELETE: list_images_response = ecr_client.list_images( registryId=account_id, repositoryName=ecr_repository_name ) image_ids = list_images_response['imageIds'] if len(image_ids) == 0: cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) return batch_delete_image_response = ecr_client.batch_delete_image( registryId=account_id, repositoryName=ecr_repository_name, imageIds=image_ids ) print(batch_delete_image_response) cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) except Exception as e: print(e) cfnresponse.send(event, context, cfnresponse.FAILED, response_data) Environment: Variables: ACCOUNT_ID: !Ref AWS::AccountId ECR_REPOSITORY_NAME: !Ref ECRRepositoryName FunctionName: !Sub "${Prefix}-function" Handler: !Ref Handler Runtime: !Ref Runtime Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)

There are no special settings for the function itself.
The environment variable is the key point.
The parameters for deleting an image (repository name or account ID) are passed to the function as environment variables.

Refer to the value of event[‘RequestType’] to implement the process according to the stack operation.
“Delete” is used when deleting the stack.
So use an if statement to ensure that the following processing is performed when the stack is deleting.

  • Obtain a list of images stored in the repository using the list_images method.
  • If the number of images is 0, the process is aborted.
  • In the batch_delete_image method, delete the images.

A function invocation completion message must be returned to the CloudFormation stack.
In this case, we use cfnresponse.send to implement this.

There is one issue with the object deletion we have implemented this time.
It is not intended to delete more than 1000 images.
When boto3’s list_images tries to retrieve more than 1000 images, it returns a token to retrieve the remaining data.
In this code, that part of the process is not yet implemented.

The following is the IAM role for the above function.

Resources: FunctionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: - ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: !Sub "${Prefix}-ECRDeleteImagesPolicy" PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - ecr:BatchDeleteImage - ecr:ListImages Resource: - !Ref ECRRepositoryArn
Code language: YAML (yaml)

As we saw earlier, the function will list and delete images stored in the ECR.
Therefore, we grant permission to allow these.

Custom Resources

Resources: CustomResource: Type: Custom::CustomResource Properties: ServiceToken: !Ref FunctionArn
Code language: YAML (yaml)

Specify the ARN of the aforementioned Lambda function in the ServiceToken property.
This setting will cause the function to be invoked each time the CloudFormation stack is operated.


Resources: ECRRepository: Type: AWS::ECR::Repository Properties: RepositoryName: !Ref Prefix
Code language: YAML (yaml)

ECR Repository.
No special configuration is required.


Use CloudFormation to build this environment and check the actual behavior.

Create CloudFormation stacks and check resources in stacks

Create a CloudFormation stacks.
For information on how to create stacks and check each stack, please refer to the following page

After checking the resources in each stack, information on the main resources created this time is as follows

  • ECR: fa-078

Check Action

Image push

Now that everything is ready, push the image to ECR.

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [account-id] ... Login Succeeded $ docker build -t fa-078 . ... Successfully tagged fa-078:latest $ docker tag fa-078:latest [account-id] $ docker push [account-id] The push refers to repository [[account-id]] 209cb42bdfb7: Pushed latest: digest: sha256:4adf0089f316607778fd6a5e073205b767bd849ac8a2234921fddc4351139b96 size: 529
Code language: JavaScript (javascript)

Image build/push successfully executed.

Check the ECR.

Detail of ECR 1.

The image is indeed stored.

Delete CloudFormation stack

Attempt to delete the stack with the image still in the ECR.

Detail of ECR 2.

Wait until the deletion process is complete.

Detail of ECR 3.

Stack deletion is completed.
This means that when the stack is deleted, the CloudFormation custom resource has preemptively deleted the remaining images in the ECR repository.

Checking the Operation of the Lambda function associated with the custom resource.

Detail of CloudFormation Custom Resources Action.

The logs delivered to CloudWatch Logs show two things.

The first is that we are getting a list of images stored in the ECR.
In this case, we can read that one image is stored.

The second is that this function has acted as a CloudFormation custom resource.
It can be read that a message is sent to the CloudFormation stack using the cfnresponse module.

This means that when the stack is deleted, the image is automatically removed from the ECR repository before the stack is deleted.


We have seen how to use CloudFormation custom resources to automatically delete images from the ECR repository when deleting the CloudFormation stack.