Question: How can I resolve the error that I receive when I subscribe an AWS Lambda function to a push-based event source in AWS CloudFormation?

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. If I use the AWS::Lambda::EventSourceMapping resource, I receive the following error: "Unrecognized event source, must be kinesis or dynamodb stream."Short descriptionThe AWS::Lambda::EventSourceMapping resource is designed for pull-based event sources, such as Amazon DynamoDB event streams and Amazon Kinesis. With push-based event sources, such as Amazon S3 event notifications or Amazon SNS messages, the event source is responsible for invoking the Lambda function. For a push event source to invoke a Lambda function, the function’s resource policy must authorize a supported event source.

ResolutionIn your AWS CloudFormation template, add a resource-based policy using 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 with 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": "nodejs8.10"      }    },    "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 the preceding example, the S3 bucket and notification configuration are created at the same time. The example avoids a circular dependency by using the Fn::Join intrinsic function and the DependsOn attribute to create the resources in the following order: 1) IAM role, 2) Lambda function, 3) Lambda permission, and then 4) S3 bucket. For more information, see How do I avoid the "Unable to validate the following destination configurations" error with Lambda event notifications in AWS CloudFormation?Related informationCloudFormation best practicesLambda permissionsUpdate behaviors of stack resources