如何修复 S3 存储桶和 SQS 之间的循环依赖?

How can I fix the circular dependency between my S3 bucket and SQS?

我正在尝试为我的服务编写 serverless 配置。要求是 S3 存储桶在对象创建事件上向 SQS 队列发送通知。但是,当我尝试使用 serverless deploy 部署我的服务时,出现此错误:

Serverless Error ----------------------------------------

 An error occurred: PolicyS3Bucket - Unable to validate the following destination configurations (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: 4D25CQFZN0R2Q9FG; S3 Extended Request ID: dLfKHJgOnDUcAF3xwN9EgW9LibP3bt7ITj7PyuCXs2qH6Qvmn2iZu7aXYbbUdqptPvgvjwkcWYM=; Proxy: null).

我发现 this page 其中(如果我理解正确的话)解释了我的 S3 存储桶和 SQS 队列之间存在循环依赖关系,并且我必须修复此循环依赖关系才能成功部署我的服务。

此页面说明我可以使用 Fn::Sub or Fn::Join 修复循环依赖。基于这个建议,我将我的配置从原始版本修改为新版本,如下所示,使用 Sub:

cfn.s3.yml(原版)

Resources:
  PolicyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: ${self:custom.config.policyBucketName}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      NotificationConfiguration:
        QueueConfigurations:
          - Event: s3:ObjectCreated:*
            Queue: !GetAtt SQSQueue.Arn
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - BucketKeyEnabled: true
            ServerSideEncryptionByDefault:
              KMSMasterKeyID: !Ref CustomMasterKey
              SSEAlgorithm: aws:kms
      Tags: ${redacted}

cfn.s3.yml(新版本,粗体变化)

Resources:
  PolicyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: ${self:custom.config.policyBucketName}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      NotificationConfiguration:
        QueueConfigurations:
          - Event: s3:ObjectCreated:*
            Queue: !Sub arn:aws:sqs:${self:provider.region}:${AWS::AccountId}:${self:custom.config.sqsQueueName}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - BucketKeyEnabled: true
            ServerSideEncryptionByDefault:
              KMSMasterKeyID: !Ref CustomMasterKey
              SSEAlgorithm: aws:kms
      Tags: ${redacted}

我不变cfn.sqs.yml

Resources:
  SQSQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: ${self:custom.config.sqsQueueName}

当我尝试 serverless deploy 使用新版本时,我遇到了同样的错误。

我也尝试了@kgiannakakis 的建议来使用 DependsOn,但是我在尝试时遇到了同样的错误。

如何修复我的无服务器配置以便成功部署我的服务?

我找到了一个有效的修复程序。

我必须更新我的 cfn.sqs.yml 以包含 S3 存储桶将事件发送到 SQS 队列的权限,如下所示:

Resources:
  SQSQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: ${self:custom.config.sqsQueueName}
  S3EventQueuePolicy:
    Type: AWS::SQS::QueuePolicy
    DependsOn: SQSQueue
    Properties:
      PolicyDocument:
        Id: SQSPolicy
        Statement:
          - Effect: Allow
            Sid: PutS3Events
            Action: SQS:SendMessage
            Resource: !GetAtt SQSQueue.Arn
            Principal:
              Service: s3.amazonaws.com
      Queues:
        - !Ref SQSQueue

至于我的 cfn.s3.yml,引用队列的正确方法是

Queue: !GetAtt SQSQueue.Arn

我认为问题在于 AWS 检查通知是否可以在部署时发送,而不是让您的服务在运行时失败,如 this answer:

中所述

A lot of AWS configuration allows you to connect services and they fail at runtime if they don't have permission, however S3 notification configuration does check some destinations for access.

这意味着,由于我没有配置我的 SQS 队列以允许来自 S3 存储桶的通知,AWS 注意到了这个错误配置并停止了部署并出错。