【问题标题】:SNS topic not publishing to SQSSNS 主题未发布到 SQS
【发布时间】:2011-08-21 01:42:35
【问题描述】:

我正在尝试使用 SNS 和 SQS 对分布式应用程序进行原型设计。我有这个主题:

arn:aws:sns:us-east-1:574008783416:us-east-1-live-auction

还有这个队列:

arn:aws:sqs:us-east-1:574008783416:queue4

我使用 JS Scratchpad 创建了队列。我使用控制台添加了订阅。我使用暂存器将权限添加到队列。队列策略现在是:

{  
   "Version":"2008-10-17",
   "Id":"arn:aws:sqs:us-east-1:574008783416:queue4/SQSDefaultPolicy",
   "Statement":[  
      {  
         "Sid":"RootPerms",
         "Effect":"Allow",
         "Principal":{  
            "AWS":"574008783416"
         },
         "Action":"SQS:*",
         "Resource":"arn:aws:sqs:us-east-1:574008783416:queue4"
      }
   ]
}

我订阅了同一主题的电子邮件,并且电子邮件正常到达,但消息从未到达队列中。我已经尝试使用 Scratchpad 直接将 SendMessage 发送到队列 - 而不是通过 SNS - 它工作正常。任何想法为什么它不会发送到队列?

【问题讨论】:

    标签: amazon-web-services amazon-sqs amazon-sns


    【解决方案1】:

    这是不久前在 AWS 论坛上发布的:https://forums.aws.amazon.com/thread.jspa?messageID=202798

    然后我授予 SNS 主题向 SQS 队列发送消息的权限。这里的诀窍是允许所有主体。 SNS 不会从您的帐户 ID 发送 - 它有自己的帐户 ID,它是从它发送的。

    【讨论】:

    • 谢谢,谢谢。有一张 AWS 支持的公开票,并请求他们将此答案添加到文档中的策略示例中。
    • 您需要限制对 sourceArn 的访问:docs.aws.amazon.com/sns/latest/dg/…
    • 这是一个非常糟糕的答案。通过这样做,每个人都可以发送来自该主题的消息。用户应该寻求允许他们做他们想做的事情的政策,同时成为他们可以拥有的最严格的政策——这样更安全。我认为您的 SQS 将在使用 * 作为主体后公开。
    【解决方案2】:

    除了 Skyler 的回答之外,如果您像我一样对允许任何主体 (Principal: '*') 的想法感到畏缩,您可以将主体限制为 SNS:

    Principal:
      Service: sns.amazonaws.com
    

    虽然这种行为没有记录在案,但它确实有效。

    【讨论】:

    • 这是问题的正确答案。通过这种方式,您不会将您的 SQS 暴露给全世界。
    • 哇,经过数小时的尝试,这对我来说是可行的解决方案,非常感谢 :)
    【解决方案3】:

    这是 Skyler 回答的完整 CloudFormation 示例

    {
      "Resources": {
        "MyTopic": {
          "Type": "AWS::SNS::Topic"
        },
        "MyQueue": {
          "Type": "AWS::SQS::Queue"
        },
        "Subscription": {
          "Type" : "AWS::SNS::Subscription",
          "Properties" : {
              "Protocol" : "sqs",
              "TopicArn" : {"Ref": "MyTopic"},
              "Endpoint": {"Fn::GetAtt": ["MyQueue", "Arn"]}
            }
        },
        "QueuePolicy": {
          "Type": "AWS::SQS::QueuePolicy",
          "Properties": {
            "Queues": [
              {"Ref": "MyQueue"}
            ],
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Sid": "allow-sns-messages",
                  "Effect": "Allow",
                  "Principal": {"Service": "sns.amazonaws.com"},
                  "Action": "sqs:SendMessage",
                  "Resource": {"Fn::GetAtt": ["MyQueue", "Arn"]},
                  "Condition": {
                    "ArnEquals": {
                      "aws:SourceArn": {"Ref": "MyTopic"}
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
    

    亚马逊在其Sending Amazon SNS Messages to Amazon SQS Queues 文档中有更多选项。

    【讨论】:

    • 据我所知,Statement 需要包含一个 Resource 属性: "Resource": { "Fn::GetAtt": ["MyQueue", "Arn" ] },
    【解决方案4】:

    大多数答案(除了@spg 答案)建议使用principal: * - 这是非常危险的做法,它会将您的 SQS 暴露给全世界。

    来自AWS docs

    对于基于资源的策略,例如 Amazon S3 存储桶策略,主体元素中的通配符 (*) 指定所有用户或公共访问权限。
    我们强烈建议您不要在角色信任策略的 Principal 元素中使用通配符,除非您通过策略中的 Condition 元素限制访问。否则,您分区中任何账户中的任何 IAM 用户都可以访问该角色。

    因此强烈建议不要使用此主体。

    相反,您需要指定 sns 服务作为您的主体:

    "Principal": {
            "Service": "sns.amazonaws.com"
    },
    

    示例政策:

    {
      "Version": "2012-10-17",
      "Id": "Policy1596186813341",
      "Statement": [
        {
          "Sid": "Stmt1596186812579",
          "Effect": "Allow",
          "Principal": {
            "Service": "sns.amazonaws.com"
          },
          "Action": [
            "sqs:SendMessage",
            "sqs:SendMessageBatch"
          ],
          "Resource": "Your-SQS-Arn"
        }
      ]
    }
    

    使用此策略,sns 将能够向您的 SQS 发送消息。

    SQS 有 more permissions,但据我所知,SendMessageSendMessageBatch 对于 SNS->SQS 订阅应该足够了。

    【讨论】:

    • 你知道SNS是否使用SendMessageBatch来降低成本?
    • 这是一个很好的答案。当我在 AWS 控制台中将 SNS 连接到 SQS 时,我很惊讶,它不会自动执行权限部分。
    【解决方案5】:

    老问题,但使用 AWS SDK 版本 > 1.10

    查看文档SQS-SNS sendMessage Permission

    private static void updateQueuePolicy(AmazonSQS sqs, String queueURL, String topicARN) {
       Map<String, String> attributes = new HashMap<String, String>(1);
       Action actions = new Action() {
           @Override
           public String getActionName() {
               return "sqs:SendMessage"; // Action name
           }
       };
       Statement mainQueueStatements = new Statement(Statement.Effect.Allow)
               .withActions(actions)
               .withPrincipals(new Principal("Service", "sns.amazonaws.com"))
               .withConditions(
                   new Condition()
                   .withType("ArnEquals")
                   .withConditionKey("aws:SourceArn")
                   .withValues(topicARN)
               );
    
       final Policy mainQueuePolicy = new Policy()
            .withId("MainQueuePolicy")
            .withStatements(mainQueueStatements);
    
       attributes.put("Policy", mainQueuePolicy.toJson());
    
       updateQueueAttributes(sqs, queueURL, attributes);
    }
    

    输出类似于

    的策略
    {
       Policy={
          "Version":"2012-10-17",
           "Id":"MainQueuePolicy",
           "Statement":
                [
                  {
                     "Sid":"1",
                     "Effect":"Allow",
                     "Principal": {
                       "Service": "sns.amazonaws.com"
                     },
                     "Action":["sqs:SendMessage"],
                     "Condition":
                       {"ArnEquals":
                         {"aws:SourceArn":["arn:aws:sns:us-east-1:3232:testSubscription"]}
                       }
                  }
                ]
          }
     }
    

    【讨论】:

    • 您可能指的是 topicARN,而不是 queueARN。
    • 感谢您更新您的答案以促进正确的校长! :)
    【解决方案6】:

    与提到的其他答案一样,您必须选择加入并授予此 SNS 主题的权限才能发布到您的 SQS 队列。

    如果您使用 terraform,则可以使用 sqs_queue_policy 资源。

    这里是an example

    resource "aws_sqs_queue_policy" "your_queue_policy" {
        queue_url = "${aws_sqs_queue.your_queue.id}"
    
        policy = <<POLICY
    {
      "Version": "2012-10-17",
      "Id": "sqspolicy",
      "Statement": [
        {
          "Sid": "First",
          "Effect": "Allow",
          "Principal": "*",
          "Action": "sqs:SendMessage",
          "Resource": "${aws_sqs_queue.your_queue.arn}",
          "Condition": {
            "ArnEquals": {
              "aws:SourceArn": "${aws_sns_topic.your_topic.arn}"
            }
          }
        }
      ]
    }
    POLICY
    }
    

    【讨论】:

      【解决方案7】:

      只有您需要从队列控制台为队列订阅主题。

      • 第一步:选择队列
      • 第二步:队列操作
      • 第三步:订阅队列到 SNS 主题
      • 步骤选择:主题
      • 结束。

      【讨论】:

        【解决方案8】:

        如果您在队列上启用了加密,也可能是 SNS 无法将消息放入订阅者队列的原因。您需要向该 KMS 密钥授予对 SNS 的访问权限。

        This article 解释了如何解决这个问题:

        【讨论】:

          猜你喜欢
          • 2021-11-14
          • 1970-01-01
          • 1970-01-01
          • 2018-03-01
          • 1970-01-01
          • 2020-06-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多