如何解决将 AWS Lambda 函数订阅到 AWS CloudFormation 中基于推送的事件源时收到的错误?
上次更新时间:2020 年 10 月 15 日
我无法将 AWS Lambda 函数订阅到我的 AWS CloudFormation 堆栈中的 Amazon Simple Storage Service (Amazon S3) 事件通知或 Amazon Simple Notification Service (Amazon SNS) 主题。如果使用 AWS::Lambda::EventSourceMapping 资源,我将收到以下错误:“Unrecognized event source, must be kinesis or dynamodb stream(无法识别的事件源,必须是 kinesis 或 dynamodb 流)。”
简短描述
AWS::Lambda::EventSourceMapping 资源为基于提取的事件源设计,例如 Amazon DynamoDB 事件流和 Amazon Kinesis。借助基于推送的事件源,例如 Amazon S3 事件通知或 Amazon SNS 消息,事件源负责调用 Lambda 函数。为了使推送事件源调用 Lambda 函数时,该函数的资源策略必须授权受支持的事件源。
解决方法
在您的 AWS CloudFormation 模板,使用 AWS::Lambda::Permission 资源添加一个基于资源的策略。
例如,下面的基于资源的策略允许 Amazon SNS 主题调用 Lambda 函数:
"LambdaResourcePolicy": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName" : { "Ref" : "MyFunction" },
"Principal": "sns.amazonaws.com",
"Action": "lambda:InvokeFunction",
"SourceArn" : { "Ref" : "MySNSTopic" }
}
}
{
"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>"
}
]
}
}
]
}
}
}
}
在前面的示例中,S3 存储桶和通知配置同时创建。该示例通过使用 Fn::Join 内部函数和 DependsOn 属性按照以下顺序创建资源,从而避免循环依赖:1) IAM 角色,2) Lambda 函数,3) Lambda 权限,然后是 4) S3 存储桶。有关更多信息,请参阅如何避免在 AWS CloudFormation 中使用 Lambda 事件通知时出现的“Unable to validate the following destination configurations”错误?