跳至內容

如何解決在 CloudFormation 中,將 Lambda 函式訂閱至推送型事件來源時收到的錯誤?

2 分的閱讀內容
0

在 AWS CloudFormation 堆疊中,我無法將 AWS Lambda 函式訂閱至 Amazon Simple Storage Service (Amazon S3) 事件通知或 Amazon Simple Notification Service (Amazon SNS) 主題。

簡短描述

如果您使用 AWS::Lambda::EventSourceMapping 資源訂閱 Lambda 函式,則可能會收到以下錯誤:"Unrecognized event source, must be kinesis or dynamodb stream."

此資源專為提取型事件來源 (例如 Amazon DynamoDB 事件串流和 Amazon Kinesis) 而設計。當您使用推送型事件來源 (例如 Amazon S3 事件通知或 Amazon SNS 訊息) 時,事件來源會調用 Lambda 函式。若要讓推送事件來源調用 Lambda 函式,函式的資源政策必須授權可以調用 Lambda 函式的服務

解決方法

在您的 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" }
  }
}

對於 Amazon SNS 主題事件來源,您必須定義具有必要權限的主題政策

對於 Amazon S3 事件來源,您必須擁有將 Lambda 函式訂閱到 Amazon S3 儲存貯體的通知組態陳述式。例如:

{  "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>"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

在此範例中,會同時建立 S3 儲存貯體和通知組態。此範例透過 Fn::GetAtt 內部函式和 DependsOn 屬性來建立資源,以避免循環相依性。

注意: 當未指定 DependsOn 屬性時,CloudFormation 會同時建立 S3 儲存貯體和 Lambda 權限資源。

資源會依以下順序建立:

  • AWS Identity and Access Management (IAM) 角色
  • Lambda 函數
  • Lambda 權限
  • S3 儲存貯體

如需詳細資訊,請參閱如何修復 CloudFormation 中的 錯誤?"Unable to validate the following destination configurations"

相關資訊

CloudFormation 最佳實務

Lambda 資源動作權限

更新堆疊資源的行為

AWS 官方已更新 2 年前