在 CloudFormation 堆栈更新时从 SQS 队列中删除了队列策略

问题描述 投票:0回答:1

我今天更新 CloudFormation 堆栈时观察到奇怪的行为,想知道我是否做错了什么。下面是简化的示例。

重现步骤

第 1 步: 创建一个包含两个队列的堆栈,并为两个队列创建一个队列策略。

AWSTemplateFormatVersion: '2010-09-09'
Description: >
  Cloudformation queue policy change bug repro step one: create stack with
  this template.
Resources:

  FirstQueue:
    Type: "AWS::SQS::Queue"
  
  SecondQueue:
    Type: "AWS::SQS::Queue"
  
  FirstPolicy:
    Type: "AWS::SQS::QueuePolicy"
    Properties: 
      Queues: 
        - !Ref FirstQueue
        - !Ref SecondQueue
      PolicyDocument: 
        Statement: 
          - Action: 
              - "SQS:SendMessage" 
            Effect: "Deny"
            Principal: "*"

第 2 步: 使用模板更新堆栈,其中原始策略仅应用于第一个队列,新策略应用于第二个队列:

AWSTemplateFormatVersion: '2010-09-09'
Description: >
  Cloudformation queue policy change bug repro step two: update stack with
  this template.
Resources:

  FirstQueue:
    Type: "AWS::SQS::Queue"
  
  SecondQueue:
    Type: "AWS::SQS::Queue"
  
  FirstPolicy:
    Type: "AWS::SQS::QueuePolicy"
    Properties: 
      Queues: 
        - !Ref FirstQueue
      PolicyDocument: 
        Statement: 
          - Action: 
              - "SQS:SendMessage" 
            Effect: "Deny"
            Principal: "*"
  
  SecondPolicy:
    Type: "AWS::SQS::QueuePolicy"
    Properties: 
      Queues: 
        - !Ref SecondQueue
      PolicyDocument: 
        Statement: 
          - Action: 
              - "SQS:ReceiveMessage"
            Effect: "Deny"
            Principal: "*"

结果

堆栈更新后我期望的结果是每个队列都有自己的队列策略。具体来说,我希望第二个队列应用新的第二个策略。我观察到的是第二个队列有一个空策略。

empty queue policy

如果我查看 CloudTrail 中的事件历史记录,我会看到 CloudFormation 在堆栈更新期间对第二个队列发出两个

SetQueueAttributes
请求:

  1. 正如我所期望的那样,它制定了“第二项政策”;和
  2. 第二个清除政策的地方:
{
    "eventVersion": "1.09",
    "eventSource": "sqs.amazonaws.com",
    "eventName": "SetQueueAttributes",
    "sourceIPAddress": "cloudformation.amazonaws.com",
    "userAgent": "cloudformation.amazonaws.com",
    
    /* ... */
    
    "requestParameters": {
        "queueUrl": "https://sqs.ca-central-1.amazonaws.com/XXXXXXXXXXXX/BugRepro-SecondQueue-hZyO53RvsmdK",
        "attributes": {
            "Policy": ""
        }
    },

    /* ... */
}

问题

对我来说,CloudFormation 似乎没有意识到第二个队列上的策略正在被替换,因此,它不仅设置新策略,还设置它(设置为新策略)并清除它(以删除旧策略) )。我在这里错过了什么或者做错了什么吗?这是预期的行为吗?

amazon-web-services aws-cloudformation amazon-sqs
1个回答
0
投票

我认为这是由简单的竞争条件以及

AWS::SQS::Queue
AWS::SQS::QueuePolicy
之间不直观的关系引起的。

CloudFormation 的工作原理是识别模板中已定义资源的更改,并根据依赖关系构建这些更改的有向无环图 (DAG):如果

ResourceB
依赖于
ResourceA
,则 CloudFormation 将确保
A
将之前修改过
B
。如果 CloudFormation 无法确定两个资源之间的依赖顺序,则可以随意并行修改它们,这就是竞争条件出现的地方。

但这只是故事的一部分。更重要的是,CloudFormation 资源与物理 AWS 资源并不完全匹配。

更常见的是,CloudFormation 资源对应于 AWS API 调用——通常是

单个 API 调用。例如,AWS::SQS::Queue

 对应于 SQS 
CreateQueue API 调用。如果您查看该 API,您会发现没有地方可以指定队列策略。相反,您必须调用 SetQueueAttributes API 来更新队列策略。

我不知道为什么 CloudFormation 开发人员决定创建一个单独的

QueuePolicy

 资源来执行此操作,而不是将其合并到 
Queue
 资源中。我怀疑这是因为许多/大多数 CloudFormation 资源类型是根据通用 API 定义自动生成的。这也可以解释为什么 
QueuePolicy
 指的是 
Queue
,而不是相反(这就是 API 的工作原理)。

但结果是,当您删除从

FirstPolicy

SecondQueue
 的引用时,您导致 CloudFormation 将这两个策略放在 DAG 的不同分支上,从而允许它们并行执行。这意味着对 
QueueTwo
 的实际更改取决于最后处理这两个资源中的哪一个。

解决此问题的一种方法是更新堆栈两次:第一次更新时,您将

QueueTwo

PolicyOne
 分离,第二次更新时,您将其附加到 
PolicyTwo
。这意味着 
QueueTwo
 在这些更新之间不会有策略,如果您已经部署了需要该策略的应用程序,这可能会出现问题。

另一种方法是使用

DependsOn

 资源属性声明 
PolicyOne
PolicyTwo 之间的显式依赖关系。指定 PolicyTwo
 取决于 
PolicyOne
,CloudFormation 将正确排序更新。请注意,仍然有一个(非常小的)窗口,其中 
QueueTwo
 没有策略,因为堆栈更新不是事务性的。

从长远来看,您不需要这种关系,因此(1)评论需要它以确保正确的堆栈更新,或者(2)在更新成功完成后删除。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.