AWS Cloud Operations Blog
Delete Amazon CloudWatch Synthetics dependent resources when you delete a CloudFormation stack
Amazon CloudWatch Synthetics allows you to monitor application endpoints more easily. It runs tests on your endpoints every minute, and alerts you if your application endpoints don’t behave as expected. These tests can be customized to check for availability, latency, transactions, broken or dead links, page load errors, load latencies for UI assets, complex wizard flows, or checkout flows in your applications.
You can use Amazon CloudWatch Synthetics to create canaries, which are configurable scripts that run on a schedule, to monitor your endpoints and APIs. A canary creates dependent resources in your account, such as AWS Lambda functions, CloudWatch logs, CloudWatch alarms, and Amazon Simple Storage Service (Amazon S3) buckets that hold the canary runs artifacts, such as logs and screenshot. However, when you delete a canary, these resources are not automatically deleted.
Similarly, you can use AWS CloudFormation to describe and provision all the infrastructure resources in your cloud environment. You can model your environment in JSON or YAML templates, or in code, by using tools like the AWS Cloud Development Kit (AWS CDK). When canary created from CloudFormation, the canary-dependent resources in your account are not deleted when you delete the stack. The stack deletion will fail if, for example, artifacts S3 bucket isn’t empty.
After you delete a canary that you do not intend to use again, you should also delete the following:
- Lambda functions and layers used by the canary. Their prefix is
cwsyn-MyCanaryName
. - CloudWatch alarms created for the canary. These alarms have a name that starts with
Synthetics-Alarm-MyCanaryName
. For more information about deleting alarms, see Editing or Deleting a CloudWatch Alarm. - S3 objects and buckets, such as the canary’s results location and artifact location.
- AWS Identity and Access Management (IAM) roles created for the canary. These have the name
role/service-role/CloudWatchSyntheticsRole-MyCanaryName
. - Log groups in CloudWatch Logs created for the canary. These logs groups have the name
/aws/lambda/cwsyn-MyCanaryName
.
In this post, I’ll show you how to use custom resources (along with AWS Lambda) in a CloudFormation template to delete CloudWatch Synthetics dependent resources.
Overview
I will use Custom resources to trigger a lambda function that will delete all canary dependant resources on CloudFormation stack deletion.
Custom resources enable you to write custom provisioning logic in templates when you create, update, or delete stacks. For example, if resources aren’t available as CloudFormation resource types, you can include them by using custom resources. This enables you to manage all your related resources in a single stack.
When you associate a Lambda function with a custom resource, the function is invoked whenever the custom resource is created, updated, or deleted. AWS CloudFormation calls the Lambda API to invoke the function and to pass the requested data (such as the request type and resource properties) to the function.
On stack deletion, the custom resource triggers the Lambda function passing the CloudWatch canary name and S3 artifact bucket name to delete canary-dependent resources.
Figure 1: Custom resource flow on stack deletion
Walkthrough
The CloudFormation template creates the following resources:
- An S3 bucket for canary artifacts.
- A canary execution role with standard permissions.
- A canary of the heartbeat monitor type.
- A Lambda function to clean up Synthetics resources.
- An IAM role with permissions for the Lambda function to perform delete operations.
- A CloudFormation custom resource that invokes the Lambda function on stack deletion.
Use the following button to launch the CloudFormation stack that creates an S3 artifact bucket and a heartbeat monitor canary. The canary uses the syn-nodejs-puppeteer-3.1
runtime version to monitor public endpoints.
Prerequisites
If you want to follow along make sure you have access to the AWS Management Console with the proper IAM permissions required to create or delete CloudWatch Synthetics Canaries, AWS Lambda functions, IAM roles, IAM policies and Amazon S3 buckets.
Create an S3 artifact bucket
Create an S3 bucket in the same AWS Region where you create the CloudFormation stack.
Create a canary execution role
Create a canary execution role and follow the standard security advice of granting least privilege, or granting only the permissions required to perform a task. This role must include lambda.amazonaws.com
as a principal in the trust policy. The role must also have the following permissions:
s3:PutObject
s3:GetBucketLocation
s3:ListAllMyBuckets
cloudwatch:PutMetricData
xray:PutTraceSegments
logs:CreateLogGroup
logs:CreateLogStream
logs:PutLogEvents
If you want to create a canary on a VPC, you need to add permissions for ec2:CreateNetworkInterface, ec2:DescribeNetworkInterface,
and ec2:DeleteNetworkInterface
.
Create a CloudWatch canary
Use a blueprint or your custom code to create a canary to monitor your endpoint. To create canaries, your IAM role/user must have the CloudWatchSyntheticsFullAccess
policy. If you are creating an IAM role for the canary, you also need the iam:CreateRole
, iam:CreatePolicy
, and iam:AttachRolePolicy
permissions. For more information, see Required roles and permissions for CloudWatch canaries in the Amazon CloudWatch User Guide.
Create a Lambda execution IAM role
Create a Lambda execution role and follow the standard security advice of granting least privilege. This role must have permission to delete the Lambda function, CloudWatch logs, alarms if they exist, the S3 bucket, and S3 artifact objects for CloudFormation stack resources CloudWatchSyntheticsCanary
and CanaryBucket
.
Create the cleaner Lambda function
The CloudFormation custom resource sends two events to the Lambda function:
On Create, the Lambda function will receive the following event:
On Delete, the Lambda function will receive the following event:
I used inline Python code with the cfn-response Python module to signal responses back to CloudFormation template based on the invocation result. If the invocation event is create
the Lambda code will always return a responseStatus
of SUCCESS
. If the invocation event is Delete
, it parse the ResourceProperties
field in received JSON event to get the canary resource name and S3 artifact bucket name, then using the AWS SDK for Python (Boto3), the code does the following:
- Retrieves canary details to locate the Lambda function.
- Deletes the Lambda function.
- Deletes the CloudWatch log group for the canary Lambda function.
- Searches for and deletes alarms that have the prefix of
Synthetics-Alarm-MyCanaryName
. - Deletes all objects inside the S3 artifact bucket.
In the case of any exception, Lambda will return a responseStatus
of FAILED
to the CloudFormation stack along with information about which resource returned the error.
Create a custom resource
Give the custom resource a name like Custom::cleanCanaryStack
. Under Properties
, in the ServiceToken
property, we point toe the Lambda function ARN. We define resources to pass to the Lambda function in the invocation event, such as the S3 artifact bucket resource name and the canary resource name.
Create a CloudFormation stack
- Open the CloudFormation console and choose Create Stack.
- Choose with new resources (standard).
- Choose Upload a template file, and then choose your CloudFormation template file.
- Enter a name for your stack, complete the Parameters section, and then choose Next.
- Keep the defaults on the Configure stack options page, and then choose Next.
- On the Review page, select the checkbox to acknowledge that AWS CloudFormation might create IAM resources, and then choose Create Stack.
Figure 2 shows the created resources:
Figure 2: Created resources
Test stack deletion result
On stack deletion, custom resource invokes the lambda function that will delete all canary dependant resources and empty the S3 artifacts bucket. If Lambda failed to empty the S3 artifacts bucket the stack deletion would have failed to delete the S3 artifacts bucket.
To delete a stack
- Open the AWS CloudFormation console.
- On the Stacks page in the CloudFormation console, select the stack that you want to delete. The stack must be currently running.
- In the stack details pane, choose Delete.
- Select Delete stack when prompted.
Figure 3: Deleted resources events
Cleanup
To avoid charges to your account, delete the CloudFormation stack and resources. For more information, see Deleting a stack on the AWS CloudFormation console in the AWS CloudFormation User Guide.
Conclusion
In this blog post I showed you how to use a Lambda-backed custom resource to delete Amazon CloudWatch Synthetics dependent resources, such as AWS Lambda functions, CloudWatch logs, CloudWatch alarms, and S3 artifact buckets and objects.
Although we used the Lambda-backed custom resource on stack deletion, Lambda functions in combination with AWS CloudFormation enable a range of scenarios, such as dynamically looking up AMI IDs during stack creation or implementing and using utility functions, such as string reversal functions. You can also write your own resources to extend AWS CloudFormation beyond AWS resources and provision any other resource you can think of. For example, you can integrate a third-party software as a service (SaaS) product or you can even provision on-premises resources in hybrid environments.