You need to provision a resource type that CloudFormation does not natively support - for example, creating a Datadog dashboard or configuring a third-party SaaS. How do you implement a CloudFormation custom resource backed by Lambda?
Quick Answer
Create a Lambda function that handles Create, Update, and Delete lifecycle events from CloudFormation, processes the custom logic, and sends a SUCCESS or FAILED response to the pre-signed S3 URL. Reference it in the template using `Custom::ResourceType` with `ServiceToken` pointing to the Lambda ARN.
Detailed Answer
Custom Resource Lifecycle
When CloudFormation encounters a custom resource, it sends a JSON event to the Lambda function containing the RequestType (Create, Update, Delete), ResourceProperties (your custom parameters), StackId, LogicalResourceId, and a ResponseURL (pre-signed S3 URL). The Lambda must process the request and send an HTTP PUT to the ResponseURL with a JSON body containing Status (SUCCESS/FAILED), PhysicalResourceId, and any output Data. If the Lambda fails to respond, CloudFormation waits for the timeout (default 1 hour) before failing.
Critical Implementation Details
The PhysicalResourceId is crucial: if it changes between Create and Update, CloudFormation triggers a Delete of the old resource. Always return a stable physical ID unless you intend replacement. The cfn-response module (provided in the Lambda runtime) simplifies sending responses, but for production use, implement your own response logic with proper error handling. Always wrap your Lambda in a try-catch to ensure a response is sent even on errors - an unhandled exception means CloudFormation hangs for an hour.
CloudFormation Resource Provider Framework
For production custom resources, use the CloudFormation CLI (cfn init) to build a proper resource provider. This generates a schema, handler code, and test harnesses. Registered resource types appear as AWS::MyCompany::ResourceType and support drift detection, import, and all standard CloudFormation lifecycle operations. This is significantly more robust than raw Lambda-backed custom resources.
Common Use Cases
Custom resources are commonly used for: looking up AMI IDs dynamically, emptying S3 buckets before deletion, configuring third-party services (Datadog, PagerDuty), running database migrations, waiting for DNS propagation, and any operation that requires imperative logic during stack operations.