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

CloudFormation栈删除时Route53托管区因证书验证记录无法删除的解决方法

解决CloudFormation删除栈时Route53托管区无法删除的问题

问题场景

我使用以下CloudFormation模板创建example.com的Route53托管区和ACM SSL/TLS证书:

Resources:
  HostedZone:
    Type: AWS::Route53::HostedZone
    Properties: 
      Name: example.com

  Certificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: example.com
      ValidationMethod: DNS
      DomainValidationOptions:
        - DomainName: example.com
          HostedZoneId: !Ref HostedZone

删除栈时收到报错:

The specified hosted zone contains non-required resource record sets and so cannot be deleted. (Service: Route53, Status Code: 400, Request ID: …)

原因是ACM证书DNS验证过程中自动添加的记录留在了托管区,CloudFormation未按正确顺序先清理这些记录再删除托管区,导致无法删除托管区。

解决方案

方案1:手动定义DNS验证记录(推荐)

将ACM自动创建的验证记录转为栈内显式管理的Route53资源,确保CloudFormation能按顺序删除记录、证书、托管区:

Resources:
  HostedZone:
    Type: AWS::Route53::HostedZone
    Properties: 
      Name: example.com

  Certificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: example.com
      ValidationMethod: DNS
      DomainValidationOptions:
        - DomainName: example.com
          HostedZoneId: !Ref HostedZone

  # 手动创建ACM验证所需的DNS记录
  CertificateValidationRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: !Ref HostedZone
      Name: !GetAtt Certificate.DomainValidationOptions.0.ResourceRecord.Name
      Type: !GetAtt Certificate.DomainValidationOptions.0.ResourceRecord.Type
      TTL: 300
      ResourceRecords:
        - !GetAtt Certificate.DomainValidationOptions.0.ResourceRecord.Value
    DependsOn: HostedZone

删除栈时,CloudFormation会先删除CertificateValidationRecord,再删除Certificate,最后删除HostedZone,无残留记录干扰。

方案2:使用自定义Lambda清理托管区记录

添加自定义Lambda资源,在栈删除时自动清理托管区中非必需的记录(除NS、SOA外):

Resources:
  HostedZone:
    Type: AWS::Route53::HostedZone
    Properties: 
      Name: example.com

  Certificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: example.com
      ValidationMethod: DNS
      DomainValidationOptions:
        - DomainName: example.com
          HostedZoneId: !Ref HostedZone

  # 清理托管区记录的Lambda函数
  CleanHostedZoneFunction:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.11
      Handler: index.lambda_handler
      Role: !GetAtt CleanHostedZoneRole.Arn
      Code:
        ZipFile: |
          import boto3
          import cfnresponse

          def lambda_handler(event, context):
              route53 = boto3.client('route53')
              hosted_zone_id = event['ResourceProperties']['HostedZoneId']
              try:
                  if event['RequestType'] == 'Delete':
                      # 获取托管区所有记录
                      record_sets = route53.list_resource_record_sets(HostedZoneId=hosted_zone_id)['ResourceRecordSets']
                      # 收集要删除的记录(跳过NS和SOA)
                      changes = []
                      for record in record_sets:
                          if record['Type'] not in ['NS', 'SOA']:
                              changes.append({
                                  'Action': 'DELETE',
                                  'ResourceRecordSet': record
                              })
                      # 批量删除
                      if changes:
                          route53.change_resource_record_sets(
                              HostedZoneId=hosted_zone_id,
                              ChangeBatch={'Changes': changes}
                          )
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
              except Exception as e:
                  cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)})

  # Lambda所需的IAM角色
  CleanHostedZoneRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: CleanHostedZonePermissions
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - route53:ListResourceRecordSets
                  - route53:ChangeResourceRecordSets
                Resource: !Sub 'arn:aws:route53:::hostedzone/${HostedZone}'
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: '*'

  # 触发自定义资源的栈资源
  CleanHostedZoneResource:
    Type: Custom::CleanHostedZone
    Properties:
      ServiceToken: !GetAtt CleanHostedZoneFunction.Arn
      HostedZoneId: !Ref HostedZone
    DependsOn: Certificate

栈删除时,自定义资源会先清理托管区的验证记录,再允许托管区被正常删除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:35:37