[英]SNS topic not publishing to 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"
}
]
}
我有一个关于同一主题的 email 订阅,并且电子邮件可以正常到达,但消息永远不会到达队列。 我已经尝试使用 Scratchpad 将 SendMessage 直接发送到队列 - 而不是通过 SNS - 它工作正常。 任何想法为什么它不会发送到队列?
这是在 AWS 论坛上发布的一段时间: https : //forums.aws.amazon.com/thread.jspa? messageID =202798
然后我给了 SNS 主题向 SQS 队列发送消息的权限。 这里的技巧是允许所有主体。 SNS 不会从您的帐户 ID 发送——它有自己的帐户 ID 来发送。
这是 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"}
}
}
}
]
}
}
}
}
}
Amazon 在其将Amazon SNS 消息发送到 Amazon SQS 队列文档中有更多选项。
添加到 Skyler 的回答中,如果像我一样,您对允许任何委托人( Principal: '*'
)的想法感到畏缩,您可以将委托人限制为 SNS:
Principal:
Service: sns.amazonaws.com
尽管此行为未记录在案,但它确实有效。
大多数答案(@spg 答案旁边)都建议使用principal: *
- 这是非常危险的做法,它会将您的 SQS 暴露给全世界。
来自AWS 文档
对于基于资源的策略,例如 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 有更多权限,但从我看来SendMessage
和SendMessageBatch
应该足以用于 SNS->SQS 订阅。
我刚刚经历了这一点,花了一段时间才弄清楚原因:
如果我从 SNS 控制台创建 SQS 订阅,它不会向 SQS 访问策略添加必要的权限。
如果我在 SQS 控制台中创建对同一个 SNS 的订阅,则可以。
老问题,但使用 AWS SDK 版本 > 1.10
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"]}
}
}
]
}
}
只有您需要从队列控制台为队列订阅主题。
与提到的其他答案一样,您必须选择加入并授予此 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
}
如果您在队列上启用了加密,也可能是 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,此类政策不适用。 请如果有人知道为什么请分享它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.