【问题标题】:AWS SNS ought to trigger my lambda, but does notAWS SNS 应该触发我的 lambda,但不会
【发布时间】:2017-02-02 23:51:11
【问题描述】:

我有一个通过 apex 创建的 AWS lambda 函数。我还通过 terraform 创建了一个 SNS 主题和订阅。

我的话题是:arn:aws:sns:ap-southeast-1:178284945954:fetch_realm_auctions

我有一个订阅:arn:aws:sns:ap-southeast-1:178284945954:fetch_realm_auctions:2da1d182-946d-4afd-91cb-1ed3453c5d86,类型为 lambda,端点是:arn:aws:lambda:ap-southeast-1:178284945954:function:wowauctions_get_auction_data

我已经确认这是正确的函数 ARN。一切似乎都连接正确:

我手动触发 SNS:

aws sns publish 
  --topic-arn arn:aws:sns:ap-southeast-1:178284945954:fetch_realm_auctions 
  --message '{"endpoint": "https://us.api.battle.net", "realm": "spinebreaker"}'

它返回消息 ID,但没有调用发生。为什么?

【问题讨论】:

  • Lambda Monitoring 选项卡是否显示调用计数?如果是这样,它是否显示错误计数?您是否尝试过订阅 SNS 主题(例如电子邮件)以确认消息是在 SNS 中发送的?
  • Lambda函数是否有被SNS调用的权限?这里有一个例子:mobile.awsblog.com/post/Tx1VE917Z8J4UDY/…
  • @BretzL 啊,这就是问题所在。谢谢。
  • 抱歉标题变更;我想重新标记,删除 Apex,遵循标记指南,但随后还需要重新编写标题文本!

标签: amazon-web-services aws-lambda amazon-sns


【解决方案1】:

我添加了一个内联策略以允许调用 lambda:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1474873816000",
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "arn:aws:lambda:ap-southeast-1:178284945954:function:wowauctions_get_auction_data"
            ]
        }
    ]
}

现在它正在工作。

【讨论】:

  • 您也可以只添加"Principal": "sns.amazonaws.com" 以允许任何sns主题调用任何lambda函数
  • 我花了一点时间来确定应该将此内联策略应用于 SNS 主题
【解决方案2】:

SNS 主题需要有调用 Lambda 的权限。

这是一个如何在 Terraform 中表达的示例:

# Assumption: both SNS topic and Lambda are deployed in the same region
# resource "aws_sns_topic" "instance" { ... }
# resource "aws_lambda_function" "instance" {... }

# Step 1: Allow the SNS topic to invoke the Lambda
resource "aws_lambda_permission" "allow_invocation_from_sns" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.instance.function_name}"
  principal     = "sns.amazonaws.com"
  source_arn    = "${aws_sns_topic.instance.arn}"
}

# Step 2: Subscribe the Lambda to the SNS topic
resource "aws_sns_topic_subscription" "instance" {
  topic_arn = "${aws_sns_topic.instance.arn}"
  protocol  = "lambda"
  endpoint  = "${aws_lambda_function.instance.arn}"
}

解决此问题的一些一般提示(未触发 Lambda):

  1. 我的消息是否到达 Lambda? -- 将您的电子邮件地址订阅到 SNS 主题。如果您收到电子邮件,您将知道消息何时到达主题。
  2. Lambda 是否订阅了该主题? -- 在 AWS 控制台(在 SNS -> Topic 下)检查订阅是否正确(endpoint 必须与 Lambda 的 ARN 完全匹配)

一旦您确认了这些基本检查并且您仍然没有看到任何调用,这一定是权限错误。当您在 AWS 控制台中打开 Lambda 时,您应该会看到 SNS 被列为触发器:

作为对比,如果权限缺失,就看不到SNS:

如果您不使用自动部署(例如,使用 CloudFormation 或 Terraform),您也可以手动添加缺少的权限:

  1. Add triggers 下选择SNS(您需要在列表中向下滚动才能看到它)
  2. Configure triggers 中,选择SNS 主题
  3. 点击Add并保存Lambda

【讨论】:

    【解决方案3】:

    对我来说,问题是我在 cloudformation 模板中的 AWS::Lambda::Permission 内指定了 SourceAccount 参数,而 documentation 声明如下:

    添加策略时,请勿使用 --source-account 参数将源账户添加到 Lambda 策略。 Amazon SNS 事件源不支持源账户,这将导致访问被拒绝。这不会影响安全,因为源帐户包含在源 ARN 中。

    我删除SourceAccount 后,一切正常。

    【讨论】:

    • 当然,这为我节省了几个小时,希望 AWS 权限有一定程度的一致性,因为 SourceAccount 为 Cloud Watch Events 工作:我从那里复制 :)
    【解决方案4】:

    正如 Robo 在 cmets 中提到的,添加基于 Principal 的权限是执行此操作的最简单方法:

    "FooFunctionPermission" : {
        "Type" : "AWS::Lambda::Permission",
        "Properties" : {
            "Action" : "lambda:InvokeFunction",
            "FunctionName" : { "Ref" : "FooFunction" },
            "Principal" : "sns.amazonaws.com"
        }
    }
    

    【讨论】:

      【解决方案5】:

      有同样的问题: 1) 创建和部署简单的 lambda 2) 从 java sdk 手动创建 aws sns 主题 3)从java sdk创建sns订阅(sns主题和 λ)

      然后我遇到了一个问题,当从控制台向主题推送一些消息时 - 它没有被 lambda 拦截。而且,sns 触发器甚至没有在 lambda 中注册。

      所以我通过使用以下命令简单地解决了这个问题: https://docs.aws.amazon.com/cli/latest/reference/lambda/add-permission.html

      运行aws lambda add-permission ...... 后,一切都恢复正常。

      【讨论】:

        【解决方案6】:

        这篇文章帮助我走得更远,但有一个缺失的部分。 Terraform 将创建错误的订阅。你必须放弃$LATEST

        resource "aws_sns_topic" "cloudwatch_notifications" {
          name = "aws-${var.service_name}-${var.stage}-alarm"
        }
        
        data "aws_lambda_function" "cloudwatch_lambda" {
          function_name = "sls-${var.service_name}-${var.stage}-cloudwatch-alarms"
        }
        
        resource "aws_lambda_permission" "with_sns" {
          statement_id  = "AllowExecutionFromSNS"
          action        = "lambda:InvokeFunction"
          function_name = "${replace(data.aws_lambda_function.cloudwatch_lambda.arn, ":$LATEST", "")}"
          principal     = "sns.amazonaws.com"
          source_arn    = "${aws_sns_topic.cloudwatch_notifications.arn}"
        }
        
        resource "aws_sns_topic_subscription" "cloudwatch_subscription" {
          topic_arn = "${aws_sns_topic.cloudwatch_notifications.arn}"
          protocol  = "lambda"
          endpoint  = "${replace(data.aws_lambda_function.cloudwatch_lambda.arn, ":$LATEST", "")}"
        }
        

        【讨论】:

          【解决方案7】:

          这是对这个问题的具体答案 - 我在别处删除了我的其他答案!

          对于 Terraform 用户,另请参见此处: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission

          显示“aws_lambda_permission”资源的使用情况; SNS 包含在其中一个示例中,在此处复制:

          resource "aws_lambda_permission" "with_sns" {
            statement_id  = "AllowExecutionFromSNS"
            action        = "lambda:InvokeFunction"
            function_name = aws_lambda_function.func.function_name
            principal     = "sns.amazonaws.com"
            source_arn    = aws_sns_topic.default.arn
          }
          

          【讨论】:

            猜你喜欢
            • 2017-12-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-18
            • 1970-01-01
            • 2018-11-14
            • 1970-01-01
            • 2020-09-11
            • 2015-11-16
            相关资源
            最近更新 更多