AWS Lambda SNS 事件未使用无服务器 yml 绑定到正确的 SNS 主题 ARN

AWS Lambda SNS event is not binding to the correct SNS Topic ARN using Serverless yml

我在 serverless.yml 的资源部分有一个 SNS 主题的无服务器资源,类似这样,

resources:
  Resources:
    SNSTopic:
      Type: AWS::SNS::Topic
      Properties:
        DisplayName: SNS Topic
        TopicName: ${self:service}-${self:provider.stage}-Topic 

当我尝试将此 SNS 主题绑定到我的 lambda 事件时,如下所示,lambda 未由 SNS 事件触发。当我检查 AWS 控制台的 lambda 函数时,SNS 事件绑定了错误的 ARN 值。

Function:
    handler: src/sample/file.lambdaHandler
    role: s3FullAccessRole
    events: SNSTopic
    Properties:
      Policies:
        - AWSLambdaExecute
        - Statement:
            - Effect: Allow
              Action:
                - 'lambda:InvokeFunction'

我已经尝试使用此处提到的所有不同方式更改事件,https://serverless.com/framework/docs/providers/aws/events/sns/。我发现的唯一方法是在 lambda 事件中对 SNS 主题 ARN 值进行硬编码,这对我的情况来说并不理想。 非常感谢任何帮助。

您实际上可以使用 sns 主题的 arn 创建自定义变量

custom:
  region: ${opt:region, self:provider.region}
  snsTopic: ${self:service}-${self:provider.stage}-Topic 
  snsTopicArn: { "Fn::Join" : ["", ["arn:aws:sns:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":${self:custom.snsTopic}" ] ]  }

然后在你需要的地方使用 arn。

或者您可以使用插件 https://github.com/silvermine/serverless-plugin-external-sns-events 来基本引用主题名称。

如果您只有一个 serverless.yml 并且不想有一个单独的 cloudformation 文件,我会使用第一个选项

编辑:

要使用 arn,请按照无服务器上的说明进行操作 https://serverless.com/framework/docs/providers/aws/events/sns#using-a-pre-existing-topic

functions:
  dispatcher:
    handler: <handler>
    events:
      - sns:
          arn: ${self:custom.snsTopicArn}

因为你在同一个 serverless.yml 上有 sns 主题,你甚至可以忽略 snsTopicArn 变量并像使用 !Ref 的建议之一那样构建它,这对你来说应该是更好的选择:

functions:
  dispatcher:
    handler: <handler>
    events:
      - sns:
          arn: !Ref SNSTopic
          topicName: ${self:custom.snsTopic}

完整示例:

service: testsns
provider:
  name: aws
  runtime: nodejs12.x
  region: eu-west-1

functions:
  hello:
    handler: handler.hello
    events:
      - sns:
          arn: !Ref SuperTopic
          topicName: MyCustomTopic
    Properties:
      Policies:
        - AWSLambdaExecute
        - Statement:
            - Effect: Allow
              Action:
                - 'lambda:InvokeFunction'
resources:
  Resources:
    SuperTopic:
      Type: AWS::SNS::Topic
      Properties:
        TopicName: MyCustomTopic

终于明白了!

我最终从 iamRoleStatements 下添加的 serverless.yml 的资源部分删除了我的 SNS TOPIC 声明,像这样,

 iamRoleStatements:
    - Effect: Allow
      Action:
        - SNS:Publish
      Resource: { "Fn::Join" : ["", ["arn:aws:sns:${self:provider.region}:", { "Ref" : "AWS::AccountId" }, ":${self:custom.mySnsTopic}" ] ]  }

并在自定义部分添加了变量

custom:  
  mySnsTopic: "${self:service}-${self:provider.stage}-sns-consume"
  mySnsTopicArn: { "Fn::Join" : ["", ["arn:aws:sns:${self:provider.region}:", { "Ref" : "AWS::AccountId" }, ":${self:custom.mySnsTopic}" ] ]  }

然后将其映射到 lambda 函数事件

Function:
    handler: src/sample/file.lambdaHandler
    role: s3FullAccessRole
    events: ${self:custom.mySnsTopicArn}
    Properties:
      Policies:
        - AWSLambdaExecute

供参考link