- Newest
- Most votes
- Most comments
The issue occurs because the cfn_response module is not available in modern AWS Lambda Python runtimes. Lambda no longer includes this module by default, so the function fails during initialization with No module named 'cfn_response'.
This is a common problem when using Lambda-backed CloudFormation custom resources.
To fix this, you should not import cfn_response. Instead, send the response back to CloudFormation manually using the presigned ResponseURL provided in the event. This is the recommended and most reliable approach for current Lambda runtimes.
You can either embed the response logic directly in your Lambda function or package your own helper file. Embedding the logic directly is simpler and avoids deployment issues.
Once the response is sent using an HTTP PUT request, CloudFormation will correctly receive SUCCESS or FAILED and your stack will proceed without hanging.
In short, this is not a permissions or configuration issue. It is simply caused by relying on a module that is no longer shipped with Lambda, and the solution is to handle the CloudFormation response yourself.
answered 9 months ago
The error you're encountering is because the Lambda function is trying to import a module called 'cfn_response' which isn't available in the Lambda execution environment by default.
The 'cfn_response' module is used to send responses back to CloudFormation when implementing custom resources. To fix this issue, you have two options:
Option 1: Include the cfn_response module directly in your Lambda function code instead of importing it. You can define the module's functionality within your Lambda function.
Option 2: Create your own cfn_response.py file with the necessary functionality and include it in your Lambda deployment package.
Here's a simple implementation of the cfn_response module that you can include directly in your Lambda function:
import json import boto3 import urllib.request def send(event, context, response_status, response_data, physical_resource_id=None, no_echo=False): response_body = { 'Status': response_status, 'Reason': f"See details in CloudWatch Log Stream: {context.log_stream_name}", 'PhysicalResourceId': physical_resource_id or context.log_stream_name, 'StackId': event['StackId'], 'RequestId': event['RequestId'], 'LogicalResourceId': event['LogicalResourceId'], 'NoEcho': no_echo, 'Data': response_data } response_body_json = json.dumps(response_body) headers = { 'content-type': '', 'content-length': str(len(response_body_json)) } try: req = urllib.request.Request( url=event['ResponseURL'], data=response_body_json.encode('utf-8'), headers=headers, method='PUT' ) with urllib.request.urlopen(req) as response: print(f"Status code: {response.status}") print(f"Status message: {response.reason}") except Exception as e: print(f"Error sending response: {str(e)}") SUCCESS = "SUCCESS" FAILED = "FAILED"
After adding this code to your Lambda function, you can remove the import statement for cfn_response and use the functions directly.
Sources
Enable Amazon GuardDuty conditionally by using AWS CloudFormation templates - AWS Prescriptive Guidance
Automate external system updates for AWS Control Tower account creation | Integration & Automation
Relevant content
- AWS OFFICIALUpdated 6 months ago
