You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

复用CloudFormation模板适配已有/新建S3桶并配置跨区域复制

解决CloudFormation模板复用问题:存在S3桶则仅配置复制规则,不存在则创建并配置

原模板问题分析

  1. 直接声明AWS::S3::Bucket资源,当目标桶已存在时,CloudFormation会因桶名全局唯一报错,无法跳过创建步骤
  2. 复制配置的目标桶ARN末尾缺少闭合单引号,属于语法错误
  3. IAM复制策略的资源权限范围不合理,复制操作仅需目标桶对象权限,无需源桶对象权限
  4. 桶策略仅限制了桶本身的非HTTPS访问,未覆盖桶内对象

解决方案思路

通过Lambda-backed自定义资源检查目标桶是否存在,结合CloudFormation条件判断,实现:

  • 桶不存在:创建桶+配置版本控制+复制规则+桶策略
  • 桶已存在:跳过桶创建,直接为现有桶配置复制规则和桶策略(前提是现有桶已启用版本控制)

修改后的完整模板

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  TargetBucketName:
    Type: String
    Default: test-source-us-east-1
  SourceBucketARN:
    Type: String
    Default: arn:aws:s3:::test-source-us-west-2

Resources:
  # Lambda函数:检查目标桶是否存在及版本控制状态
  CheckBucketExistsFunction:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.12
      Handler: index.lambda_handler
      Role: !GetAtt CheckBucketRole.Arn
      Code:
        ZipFile: |
          import boto3
          import cfnresponse

          def lambda_handler(event, context):
              s3 = boto3.client('s3', region_name='us-east-1')
              bucket_name = event['ResourceProperties']['BucketName']
              response_data = {}
              try:
                  # 检查桶是否存在
                  s3.head_bucket(Bucket=bucket_name)
                  # 检查版本控制是否启用
                  versioning = s3.get_bucket_versioning(Bucket=bucket_name)
                  if versioning.get('Status') != 'Enabled':
                      response_data['Exists'] = 'false'
                      response_data['Error'] = 'Bucket exists but versioning is not enabled'
                      cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
                      return
                  response_data['Exists'] = 'true'
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
              except s3.exceptions.ClientError as e:
                  if e.response['Error']['Code'] == '404':
                      response_data['Exists'] = 'false'
                      cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
                  else:
                      response_data['Error'] = str(e)
                      cfnresponse.send(event, context, cfnresponse.FAILED, response_data)

  # Lambda执行角色
  CheckBucketRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: S3CheckAccess
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - s3:HeadBucket
                  - s3:GetBucketVersioning
                Resource: !Sub arn:aws:s3:::${TargetBucketName}
              - Effect: Allow
                Action: logs:*
                Resource: arn:aws:logs:*:*:*

  # 自定义资源:触发桶检查
  CheckBucketExists:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt CheckBucketExistsFunction.Arn
      BucketName: !Ref TargetBucketName

  # 条件判断:仅当桶不存在时创建桶
  BucketDoesNotExist:
    Condition:
      !Equals [!GetAtt CheckBucketExists.Exists, 'false']

  # 创建目标桶(仅当桶不存在时执行)
  TargetS3Bucket:
    Type: AWS::S3::Bucket
    Condition: BucketDoesNotExist
    UpdateReplacePolicy: Retain
    Properties:
      BucketName: !Ref TargetBucketName
      VersioningConfiguration:
        Status: Enabled
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  # 复制角色
  ReplicationRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Retain
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: s3.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: S3ReplicationPolicy
          PolicyDocument:
            Statement:
              # 源桶权限:读取版本对象、列表桶等
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetReplicationConfiguration
                  - s3:GetObjectVersionForReplication
                  - s3:GetObjectVersionAcl
                  - s3:GetObjectVersionTagging
                  - s3:GetObjectRetention
                  - s3:GetObjectLegalHold
                Resource:
                  - !Sub arn:aws:s3:::${TargetBucketName}
                  - !Sub arn:aws:s3:::${TargetBucketName}/*
              # 目标桶权限:复制对象、删除等
              - Effect: Allow
                Action:
                  - s3:ReplicateObject
                  - s3:ReplicateDelete
                  - s3:ReplicateTags
                  - s3:ObjectOwnerOverrideToBucketOwner
                Resource: !Sub ${SourceBucketARN}/*

  # 复制配置:兼容已存在的桶
  BucketReplicationConfig:
    Type: AWS::S3::BucketReplicationConfiguration
    Properties:
      Bucket: !Ref TargetBucketName
      Role: !GetAtt ReplicationRole.Arn
      Rules:
        - Id: CrossRegionReplicationToUsWest2
          Status: Enabled
          DeleteMarkerReplication:
            Status: Enabled
          Priority: 1
          Filter:
            Prefix: ''
          Destination:
            Bucket: !Ref SourceBucketARN

  # 桶策略:强制HTTPS访问,兼容已存在的桶
  TargetBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref TargetBucketName
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Deny
            Principal: "*"
            Action: s3:*
            Resource:
              - !Sub arn:aws:s3:::${TargetBucketName}
              - !Sub arn:aws:s3:::${TargetBucketName}/*
            Condition:
              Bool:
                aws:SecureTransport: "false"

关键修改说明

  1. 自定义资源检查桶状态:通过Lambda检查目标桶是否存在,同时验证版本控制是否启用(跨区域复制必须要求版本控制开启)
  2. 条件创建桶:用Condition控制AWS::S3::Bucket资源的创建,仅当桶不存在时执行
  3. 独立复制配置资源:使用AWS::S3::BucketReplicationConfiguration单独管理复制规则,而非嵌套在桶资源中,这样即使桶已存在也能直接配置
  4. 优化IAM权限:严格区分源桶和目标桶的权限范围,避免过度授权
  5. 修复语法错误:补全目标桶ARN的闭合单引号,完善桶策略的资源范围

注意事项

  • 若现有桶未启用版本控制,模板会部署失败,需先手动开启版本控制
  • 确保执行CloudFormation的角色拥有足够权限:创建Lambda、IAM角色、S3桶及配置复制规则的权限
  • 首次部署后,若后续复用模板,CloudFormation会自动跳过桶创建步骤,仅检查并更新复制规则和桶策略

内容的提问来源于stack exchange,提问作者EnergeticBlue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:23:10