AWS SQS 不接收 SNS 消息

AWS SQS not receiving SNS messages

我创建了一个 SNS 主题,通过 cli 发布来自 Cloudformation 的所有信息。但是,当我检查队列时,它没有收到任何 SNS 消息。我通过订阅我的电子邮件来验证 SNS 是否正常工作,因此问题似乎出在队列和 SNS 之间的连接上。但是,我找不到我的语法有任何问题。据我所知,我已经完全按照亚马逊的文档进行操作了。

Bash:

#SNS parameters
SNS_NAME="${NAME}_SNS"
SQS_NAME="${NAME}_SQS"

#Create SNS topic to send cloudformation notifications to
SNS_ARN=`aws sns create-topic --name ${SNS_NAME} | jq -r '.TopicArn'`

#Create SQS to send SNS to (holding SNS messages for lambda -^ up)
SQS_URL=`aws sqs create-queue --queue-name ${SQS_NAME} | jq -r '.QueueUrl'`
SQS_ARN=`aws sqs get-queue-attributes --queue-url ${SQS_URL} --attribute-names QueueArn | jq -r '.Attributes .QueueArn'`

#subscribe the queue to the notifications
aws sns subscribe --topic-arn ${SNS_ARN} --protocol sqs --notification-endpoint ${SQS_ARN}
aws sns subscribe --topic-arn ${SNS_ARN} --protocol email-json --notification-endpoint ${EMAIL}

#Create the stack which kicks everything else off-
aws cloudformation create-stack $REGIONTEXT $ITYPETEXT --capabilities CAPABILITY_IAM --template-url https://${BUCKETNAME}.s3.amazonaws.com/${TEMPLATE} --notification-arns ${SNS_ARN} --stack-name $NAME --parameters ParameterKey=SNSARN,ParameterValue=${SNS_ARN} ParameterKey=Bucket,ParameterValue=${BUCKETNAME} ${PARAMTEXT} ${EXTRAARGS}

您似乎没有授予 SNS 主题发布到 SQS 队列的权限。查看 this walkthrough 中的步骤 2。您需要将这样的策略添加到 SQS 队列:

{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid":"MySQSPolicy001",
      "Effect":"Allow",
      "Principal":"*",
      "Action":"sqs:SendMessage",
      "Resource":"arn:aws:sqs:us-east-1:123456789012:MyQueue",
      "Condition":{
        "ArnEquals":{
          "aws:SourceArn":"arn:aws:sns:us-east-1:123456789012:MyTopic"
        }
      }
    }
  ]
}

将 ARN 替换为您的主题和队列的 ARN。

感谢 Mark B 的回答。它为这项工作提供了开始。但是,为了通过 CLI 使策略文档起作用,文档中没有涵盖一些怪癖。

  1. 尝试将 json 直接传递给 aws sqs set-queue-attributes 命令中的 --attributes 标志时出现了各种错误。出于某种原因,它要求修改 json 位于 cli 引用的 .json 文档中。
  2. 在提供给 cli 的 .json 文件中,"Policy" 值(嵌套 json)内的所有双引号都必须转义(即 { \"Statement\": \"HelloWorld\" }) .如果不遵循这一点,它将验证错误。我最终需要使用 ascii 转义字符才能正确格式化输出 (\x5C)。
  3. 必须在 --attributes 标志中使用 file://local-location 来引用 json 文件。如果不遵守,它会抛出错误。

参考以下元素:

load_sqs.sh:

SQS_POLICY=
sqs-policy()
{
#First param is the queue arn, second param is the topic arn
SQS_POLICY=`printf '{ "Policy": "{\x5C\"Version\x5C\":\x5C\"2012-10-17\x5C\",\x5C\"Statement\x5C\":[{\x5C\"Sid\x5C\":\x5C\"CloudformationLambdaSQSPolicy\x5C\",\x5C\"Effect\x5C\":\x5C\"Allow\x5C\",\x5C\"Principal\x5C\":\x5C\"*\x5C\",\x5C\"Action\x5C\":\x5C\"sqs:SendMessage\x5C\",\x5C\"Resource\x5C\":\x5C\"%s\x5C\",\x5C\"Condition\x5C\":{\x5C\"ArnEquals\x5C\":{\x5C\"aws:SourceArn\x5C\":\x5C\"%s\x5C\"}}}]}" }' "" ""`
`echo $SQS_POLICY > $PWD/sqs-policy.json`
}

#SNS parameters
SNS_NAME="${NAME}_SNS"
SQS_NAME="${NAME}_SQS"

#Create SNS topic to send cloudformation notifications to
SNS_ARN=`aws sns create-topic --name ${SNS_NAME} | jq -r '.TopicArn'`

#Create SQS to send SNS to (holding SNS messages for lambda -^ up)
SQS_URL=`aws sqs create-queue --queue-name ${SQS_NAME} | jq -r '.QueueUrl'`
SQS_ARN=`aws sqs get-queue-attributes --queue-url ${SQS_URL} --attribute-names QueueArn | jq -r '.Attributes .QueueArn'`

#Add necessary SQS <--> SNS permissions
sqs-policy ${SQS_ARN} ${SNS_ARN}
`aws sqs set-queue-attributes --queue-url ${SQS_URL} --attributes file://sqs-policy.json`

#subscribe the queue to the notifications
aws sns subscribe --topic-arn ${SNS_ARN} --protocol sqs --notification-endpoint ${SQS_ARN}

sqs-policy.json:

{ "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"CloudformationLambdaSQSPolicy\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"sqs:SendMessage\",\"Resource\":\"ResourceARN\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"SourceARN\"}}}]}" }

在我的案例中,SQS 不接收来自 SNS 的消息,因为 SQS 已启用加密。当我在 SQS 上关闭加密时,它开始工作了!

此 AWS 文档解释了如何启用 SNS 与加密 SQS 队列的兼容性:

https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#compatibility-with-aws-services

SNS 需要额外的权限才能使用 KMS 密钥为队列加密消息。

如果 SQS 已加密,则将消息推送到队列的事件必须遵循以下步骤

多个 AWS 服务将事件发送到 Amazon SQS 队列。要允许这些事件源使用加密队列,您必须执行以下步骤。

  • 使用客户管理的 CMK。

    允许 AWS 服务拥有 kms:GenerateDataKey* 和 kms:Decrypt权限,在CMK中添加如下语句 政策。

    { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": "service.amazonaws.com" }, "Action": [ "kms:GenerateDataKey*", "kms:Decrypt" ], "Resource": "*" }] }

  • 使用 您的 CMK 的 ARN。

    将加密队列的 ARN 提供给事件源。

For sns replace service section with sns.amazonaws.com

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