Тема SNS не публикуется в SQS

Я пытаюсь создать прототип распределенного приложения с использованием 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"
      }
   ]
}

У меня есть подписка по электронной почте на ту же тему, и письма приходят нормально, но сообщения никогда не приходят в очередь. Я пробовал SendMessage непосредственно в очередь - а не через SNS - используя Scratchpad, и он работает нормально. Есть идеи, почему его не отправят в очередь?

10 ответов

Решение

Это было опубликовано некоторое время назад на форумах AWS: https://forums.aws.amazon.com/thread.jspa?messageID=202798

Затем я дал теме SNS разрешение отправлять сообщения в очередь SQS. Хитрость здесь в том, чтобы позволить всем принципалам. SNS не отправляет с вашего идентификатора учетной записи - он имеет свой собственный идентификатор учетной записи, с которого он отправляет.

Добавляя к ответу Скайлера, если вы, как и я, съеживаетесь от идеи разрешения какого-либо принципала (Principal: '*'), вы можете ограничить принципала SNS:

Principal:
  Service: sns.amazonaws.com

Хотя это поведение недокументировано, оно работает.

Большинство ответов (кроме ответа @spg) предлагают использование principal: * - это очень опасная практика, и она раскроет ваш SQS для всего мира.

Из документов AWS

Для политик на основе ресурсов, таких как политики корзины Amazon S3, подстановочный знак (*) в основном элементе указывает всех пользователей или общий доступ.
Мы настоятельно рекомендуем вам не использовать подстановочный знак в элементе Principal в политике доверия роли, если вы не ограничиваете доступ другим способом с помощью элемента Condition в политике. В противном случае любой пользователь IAM в любой учетной записи в вашем разделе может получить доступ к роли.

Поэтому использовать этот принцип настоятельно не рекомендуется.

Вместо этого вам нужно указать sns service в качестве принципала:

"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 есть больше разрешений, но из того, что я вижуSendMessage а также SendMessageBatch должно хватить для подписки на SNS->SQS.

Вот полный 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"
              }
            }
          }
        }
      ]
    }
  }
}

У Amazon есть больше опций в документе Отправка сообщений Amazon SNS в очереди Amazon SQS.

Я только что испытал это, и мне потребовалось некоторое время, чтобы понять, почему:

Если я создаю подписку SQS из консоли SNS, она не добавляет необходимые разрешения в политику доступа SQS.

Если я создам подписку в консоли SQS на тот же SNS, это произойдет.

Как и в других упомянутых ответах, вы должны зарегистрироваться и предоставить разрешение этой теме SNS для публикации в вашей очереди SQS.

Если вы используете terraform, вы можете использовать ресурс sqs_queue_policy .

Вот пример :

      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
}

Старый вопрос, но с использованием версии AWS SDK> 1.10

Проверьте документы SQS-SNS sendMessage Разрешение

private static void updateQueuePolicy(AmazonSQS sqs, String queueURL, String queueARN) {
   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(queueARN)
           );

   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"]}
                   }
              }]
      }
 }

Если вы включили шифрование в своей очереди, это также может быть причиной того, что SNS не может поместить сообщение в очередь подписчика. Вам необходимо предоставить доступ к SNS для этого ключа KMS.

В этой статье объясняется, как решить эту проблему:

Только вам нужно подписать очередь на тему из консоли очереди.

  • шаг первый: выберите очередь
  • шаг второй: действия в очереди
  • шаг третий: очередь подписки на тему SNS
  • шаг выбрать: тема
  • конец.

Это AWS::SQS::QueuePolicy.

Вам необходимо определить политику такого типа, чтобы разрешить определенным SNS выполнять действия с определенными SQS.

      QueuePolicy:
  Type: AWS::SQS::QueuePolicy
  Properties:
    Queues:
    - Ref: MyQueue1
    - Fn::Sub: arn:aws:sqs:us-east-1:${AWS::AccountId}:my-queue-*
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
      - Sid: allow-sns-messages
        Effect: Allow
        Principal:
          Service: sns.amazonaws.com
        Action: sqs:SendMessage
        Resource:
          - Fn::Sub: arn:aws:sqs:us-east-1:${AWS::AccountId}:my-queue-*
        Condition:
          ArnEquals:
            aws:SourceArn:
              - Fn::Sub: arn:aws:sns:us-east-1:${AWS::AccountId}:source-sns-*

С Lambda такие политики не применяются. Пожалуйста, если кто-нибудь знает, почему, пожалуйста, поделитесь им.

Другие вопросы по тегам