AWS SNS 应该触发我的 lambda,但没有

问题描述 投票:0回答:8

我有一个通过 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,但没有发生调用。为什么?

amazon-web-services aws-lambda amazon-sns
8个回答
16
投票

我添加了一个内联策略以允许调用 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"
            ]
        }
    ]
}

现在可以工作了。


16
投票

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. 选择
    SNS
    下的
    Add triggers
    (您需要在列表中向下滚动才能看到它)
  2. Configure triggers
    中,选择SNS主题
  3. 单击
    Add
    并保存 Lambda

5
投票

对我来说,问题是我在 cloudformation 模板中的

SourceAccount
中指定了
AWS::Lambda::Permission
参数,并且 documentation 说明了以下内容:

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

当我删除

SourceAccount
后,一切正常。


3
投票

正如 Robo 在评论中提到的,添加基于

Principal
的权限是最简单的方法:

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

0
投票

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

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

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

运行后

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


0
投票

这篇文章帮助我走得更远,但有一个缺失的部分。 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", "")}"
}

0
投票

这是这个问题的具体答案 - 我已经在其他地方删除了我的其他答案!

对于 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
}

0
投票

在我的例子中,lambda被触发,我收到了消息,但有些消息丢失/没有到达我的服务器,然后我承认我犯了一个非常愚蠢的错误,没有返回响应,因此连接从未关闭

return {
          statusCode: 500,
          body: JSON.stringify({ message: "Error sending message" })
      };

只需发回响应,您就会收到发出的所有消息

© www.soinside.com 2019 - 2024. All rights reserved.