SNS主题不发布到SQS

时间:2011-05-08 10:03:14

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

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

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

和这个队列:

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

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

{  
   "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 - 它工作正常。任何想法为什么它不会发送到队列?

8 个答案:

答案 0 :(得分:13)

这篇文章在AWS论坛上发布了一段时间:https://forums.aws.amazon.com/thread.jspa?messageID=202798

  

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

答案 1 :(得分:4)

以下是Skyler回答的完整CloudFormation示例

"MyQueue": {
  "Type": "AWS::SQS::Queue"
},
"QueuePolicy": {
  "Type": "AWS::SQS::QueuePolicy",
  "Properties": {
    "Queues": [
      {
        "Ref": "MyQueue"
      }
    ],
    "PolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "allow-sns-messages",
          "Effect": "Allow",
          "Principal": "*",
          "Action": "sqs:SendMessage",
          "Condition": {
            "ArnEquals": {
              "aws:SourceArn": {
                "Ref": "MyTopic"
              }
            }
          }
        }
      ]
    }
  }
}

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

答案 2 :(得分:3)

旧问题,但使用的是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(Principal.All)
           .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":"*",
               "Action":["sqs:SendMessage"],
               "Condition":
                   {"ArnEquals":
                       {"aws:SourceArn":["arn:aws:sns:us-east-1:3232:testSubscription"]}
                   }
              }]
      }
 }

答案 3 :(得分:2)

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

来自AWS docs

对于基于资源的策略(例如Amazon S3存储桶策略),principal元素中的通配符(*)指定所有用户或公共访问权限。
强烈建议您不要在角色的信任策略的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的要求。

答案 4 :(得分:1)

添加到Skyler的答案中,如果像我一样对允许任何主体(Principal: '*')的想法感到畏缩,则可以将主体限制为SNS:

Principal:
  Service: sns.amazonaws.com

尽管这种行为没有记录,但可以。

答案 5 :(得分:1)

仅需要从队列控制台将队列订阅到主题。

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

答案 6 :(得分:0)

与提到的其他答案一样,您必须选择加入并授予此 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 :(得分:0)

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

Redis Enterprise Cloud hosted in Azure 解释了如何解决这个问题: