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 使策略文档起作用,文档中没有涵盖一些怪癖。
- 尝试将 json 直接传递给
aws sqs set-queue-attributes
命令中的 --attributes
标志时出现了各种错误。出于某种原因,它要求修改 json 位于 cli 引用的 .json
文档中。
- 在提供给 cli 的
.json
文件中,"Policy"
值(嵌套 json)内的所有双引号都必须转义(即 { \"Statement\": \"HelloWorld\" }
) .如果不遵循这一点,它将验证错误。我最终需要使用 ascii 转义字符才能正确格式化输出 (\x5C
)。
- 必须在
--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 队列的兼容性:
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"
}
我创建了一个 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 使策略文档起作用,文档中没有涵盖一些怪癖。
- 尝试将 json 直接传递给
aws sqs set-queue-attributes
命令中的--attributes
标志时出现了各种错误。出于某种原因,它要求修改 json 位于 cli 引用的.json
文档中。 - 在提供给 cli 的
.json
文件中,"Policy"
值(嵌套 json)内的所有双引号都必须转义(即{ \"Statement\": \"HelloWorld\" }
) .如果不遵循这一点,它将验证错误。我最终需要使用 ascii 转义字符才能正确格式化输出 (\x5C
)。 - 必须在
--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 队列的兼容性:
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"
}