amazon-web-services - 从 Cloudformation 设置 QueuePolicy 在堆栈创建时不会生效 - 但在创建后设置相同的策略会生效

标签 amazon-web-services permissions aws-cloudformation amazon-sqs amazon-sns

我正在尝试创建一个队列并从(现有)SNS 主题订阅它。所有资源都在同一个帐户中。我知道,为了做到这一点,队列需要有一个 QueuePolicy,允许 SNS SendMessage 到队列。

但是,我发现我通过 Cloudformation 创建的 QueuePolicy 似乎并未受到尊重 - 消息未传递到队列,并且 Cloudwatch 从主题报告中记录传递失败,因为权限被拒绝。但是,如果我在创建后重新应用相同的策略,它就会生效并传递消息。

这是我首先尝试的:

$ cat template.yaml
---
AWSTemplateFormatVersion: "2010-09-09"

Description:
  ...

Parameters:
  TopicParameter:
    Type: String

Resources:
  Queue:
    Type: AWS::SQS::Queue

  Subscription:
    Type: AWS::SNS::Subscription
    DependsOn: QueuePolicy
    Properties:
      Endpoint:
        Fn::GetAtt:
          - "Queue"
          - "Arn"
      Protocol: "sqs"
      RawMessageDelivery: "true"
      TopicArn: !Ref TopicParameter

  QueuePolicy:
    Type: AWS::SQS::QueuePolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: '1'
            Effect: Allow
            Principal: "*"
            Action: "SQS:SendMessage"
            Resource: !Ref Queue
            Condition:
              ArnEquals:
                aws:SourceArn: !Ref TopicParameter
      Queues:
        - !Ref Queue

Outputs:
  QueueArn:
    Value:
      Fn::GetAtt:
        - "Queue"
        - "Arn"
    Export:
      Name: "QueueArn"
$ aws cloudformation create-stack --stack-name my-test-stack --template-body file://template.yaml --parameters ParameterKey=TopicParameter,ParameterValue=<topicArn>
{
    "StackId": "<stackId>"
}
# ...wait...
$ aws cloudformation describe-stacks --stack-name my-test-stack --query "Stacks[0] | Outputs[0] | OutputValue"
"<queueArn>"
# Do some trivial substitution to get the QueueUrl - it's *probably* possible via the CLI, but I don't think you need me to prove that I can do it
$ aws sqs get-queue-attributes --queue-url <queueUrl> --attribute-names ApproximateNumberOfMessages --query "Attributes.ApproximateNumberOfMessages"
"0"
# The above is consistently true, even if I wait and retry after several minutes. I've confirmed that messages *are* being published from the topic via other subscriptions
$ aws sqs get-queue-attributes --queue-url <queueUrl> --attribute-names Policy --query "Attributes.Policy"
"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"1\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"SQS:SendMessage\",\"Resource\":\"<queueUrl>\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"<topicArn>\"}}}]}"
$ aws sqs get-queue-attributes --queue-url <queueUrl> --attribute-names Policy --query "Attributes.Policy" | | perl -pe 's/^.(.*?).$/$1/' | perl -pe 's/\\"/"/g' | python -m json.tool
{
    "Statement": [
        {
            "Action": "SQS:SendMessage",
            "Condition": {
                "ArnEquals": {
                    "aws:SourceArn": "<topicArn>"
                }
            },
            "Effect": "Allow",
            "Principal": "*",
            "Resource": "<queueUrl>",
            "Sid": "1"
        }
    ],
    "Version": "2012-10-17"
}

此时,一切看起来都是正确的。如果我转到 AWS 控制台,我会在队列上看到一个 QueuePolicy,这正是我所期望的 - 但没有消息。

但是,如果我重新应用 QueuePolicy...

$ aws sqs get-queue-attributes --queue-url <queueUrl> --attribute-names Policy --query "Attributes" > policyInFile
$ cat policyInFile
{
    "Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"1\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"SQS:SendMessage\",\"Resource\":\"<queueUrl>\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"<topicArn>\"}}}]}"
}
$ aws sqs set-queue-attributes --queue-url <queueUrl> --attributes policyInFile

然后,几秒钟后,队列开始接收消息。

更奇怪的是,我可以通过执行以下操作来重现相同的行为:

  • 设置堆栈
  • 前往控制台中的队列
  • 确认队列没有接收消息
  • 点击队列策略上的“编辑”
  • 点击“保存”(即 - 不更改政策中的任何内容)
  • 观察接收消息的队列

如何使 Cloudformation Stack 中的 QueuePolicy 在创建队列时生效?

最佳答案

问题是我应该使用队列的 ARN 作为资源,而不是 URL。我猜想,当为队列设置 QueuePolicy 时(通过控制台或 CLI,但通过 Cloudformation),resource 字段会被覆盖为相关队列的 ARN。

关于amazon-web-services - 从 Cloudformation 设置 QueuePolicy 在堆栈创建时不会生效 - 但在创建后设置相同的策略会生效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55153065/

相关文章:

python - 在 Cloudformation 中使用时无法从 S3 下载引导文件

node.js - 不支持 Nodejs 10.x 运行时的 Sam 构建失败

amazon-web-services - 使用AWS API获取证书时如何引用AWS ACM证书

amazon-web-services - Cloudformation 宏使用跨区域 Lambda

尝试运行nodejs脚本时的linux权限问题

amazon-web-services - 用于 asp.net 的 Amazon CloudFormation 模板是什么?

amazon-web-services - 无法 RDP 到 Amazon EC2 实例(Windows 服务器)

linux - 当我尝试使用 "make"安装某些东西时,为什么我的权限被拒绝?

linux - 咕噜咕噜 "Error: EACCES: permission denied, open"

aws-lambda - 在内联 Lambda Nodejs 代码中使用 GetAtt