I can't subscribe my AWS Lambda function to an Amazon Simple Storage Service (Amazon S3) Event Notification or Amazon Simple Notification Service (Amazon SNS) topic in my AWS CloudFormation stack.
Short description
If you use the AWS::Lambda::EventSourceMapping resource to subscribe your Lambda function, then you might receive the following error: "Unrecognized event source, must be kinesis or dynamodb stream."
This resource is designed for pull-based event sources, such as Amazon DynamoDB event streams and Amazon Kinesis. When you use push-based event sources, such as Amazon S3 Event Notifications or Amazon SNS messages, the event source invokes the Lambda function. For a push event source to invoke a Lambda function, the function's resource policy must authorize a service that can invoke Lambda functions.
Resolution
In your CloudFormation template, add a resource-based policy with the AWS::Lambda::Permission resource.
For example, the following resource-based policy allows an Amazon SNS topic to invoke a Lambda function:
"LambdaResourcePolicy": { "Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName" : { "Ref" : "MyFunction" },
"Principal": "sns.amazonaws.com",
"Action": "lambda:InvokeFunction",
"SourceArn" : { "Ref" : "MySNSTopic" }
}
}
For an Amazon SNS topic event source, you must define a topic policy that has the required permissions.
For an Amazon S3 event source, you must have a notification configuration statement that subscribes the Lambda function to the Amazon S3 bucket. For example:
{ "AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"BucketPrefix": {
"Type": "String",
"Default": "test-bucket-name"
}
},
"Resources": {
"EncryptionServiceBucket": {
"DependsOn": "LambdaInvokePermission",
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": {
"Fn::Sub": "${BucketPrefix}-encryption-service"
},
"NotificationConfiguration": {
"LambdaConfigurations": [
{
"Function": {
"Fn::GetAtt": [
"AppendItemToListFunction",
"Arn"
]
},
"Event": "s3:ObjectCreated:*",
"Filter": {
"S3Key": {
"Rules": [
{
"Name": "suffix",
"Value": "zip"
}
]
}
}
}
]
}
}
},
"LambdaInvokePermission": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Fn::GetAtt": [
"AppendItemToListFunction",
"Arn"
]
},
"Action": "lambda:InvokeFunction",
"Principal": "s3.amazonaws.com",
"SourceAccount": {
"Ref": "AWS::AccountId"
},
"SourceArn": {
"Fn::Sub": "arn:aws:s3:::${BucketPrefix}-encryption-service"
}
}
},
"AppendItemToListFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"LambdaExecutionRole",
"Arn"
]
},
"Code": {
"ZipFile": {
"Fn::Join": [
"",
[
"exports.handler = function(event, context) {",
"console.log('Received event: ', JSON.stringify(event, null, 2));",
"};"
]
]
}
},
"Runtime": "nodejs20.x"
}
},
"LambdaExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:*"
],
"Resource": "arn:aws:logs:*:*:log-group:/path/<log-group-name>:log-stream:<log-stream-name>"
}
]
}
}
]
}
}
}
}
In this example, the S3 bucket and notification configuration are created at the same time. The example avoids a circular dependency through the Fn::GetAtt intrinsic function and the DependsOn attribute to create the resources.
Note: When the DependsOn attribute isn't specified, CloudFormation creates the S3 bucket and Lambda permission resources at the same time.
The resources are created in the following order:
- AWS Identity and Access Management (IAM) role
- Lambda function
- Lambda permission
- S3 bucket
For more information, see How do I avoid the "Unable to validate the following destination configurations" error with Lambda event notifications in CloudFormation?
Related information
CloudFormation best practices
Lambda resource action permissions
Update behaviors of stack resources