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

如何为CDK管理的EC2实例启用终止保护并允许CDK替换时终止?

解决CDK管理的EC2堡垒机终止保护导致更新失败的问题

你的核心问题是:直接给BastionHostLinux对应的EC2实例开启DisableApiTermination=true后,CloudFormation在更新堆栈、销毁旧实例时会因终止保护无法执行操作。以下是可行的解决方案:

方案:自定义资源 + Lambda 钩子

通过创建CloudFormation自定义资源,关联Lambda函数,在实例被标记为删除时自动关闭终止保护,确保CloudFormation能正常销毁旧实例。

步骤1:编写Lambda函数(自动关闭终止保护)

Lambda函数接收CloudFormation事件,当触发删除操作时,调用EC2 API修改实例属性,关闭终止保护。这里用Python编写Lambda代码(简洁易维护):

import boto3
import cfnresponse

ec2 = boto3.client('ec2')

def handler(event, context):
    try:
        instance_id = event['ResourceProperties']['InstanceId']
        if event['RequestType'] == 'Delete':
            # 关闭实例终止保护
            ec2.modify_instance_attribute(
                InstanceId=instance_id,
                DisableApiTermination={'Value': False}
            )
        cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
    except Exception as e:
        cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)})

步骤2:在CDK中集成自定义资源

在你的Java CDK代码中,创建Lambda函数、配置权限,并关联自定义资源与堡垒机实例:

import software.amazon.awscdk.*;
import software.amazon.awscdk.services.lambda.*;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.ec2.*;
import software.amazon.awscdk.services.cloudformation.*;
import software.constructs.Construct;
import java.util.List;
import java.util.Map;

public class BastionStack extends Stack {
    public BastionStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public BastionStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        // 创建堡垒机实例
        BastionHostLinux bastion = BastionHostLinux.Builder.create(this, "BastionHost")
            .vpc(Vpc.fromLookup(this, "Vpc", VpcLookupOptions.builder().isDefault(true).build()))
            .build();

        // 获取底层CfnInstance资源
        CfnInstance cfnBastion = (CfnInstance) bastion.getNode().getDefaultChild().getNode().getDefaultChild();
        // 开启终止保护
        cfnBastion.setDisableApiTermination(true);

        // 创建Lambda函数:销毁前关闭终止保护
        Function disableTerminationLambda = Function.Builder.create(this, "DisableTerminationLambda")
            .runtime(Runtime.PYTHON_3_9)
            .code(Code.fromInline("""
                import boto3
                import cfnresponse

                ec2 = boto3.client('ec2')

                def handler(event, context):
                    try:
                        instance_id = event['ResourceProperties']['InstanceId']
                        if event['RequestType'] == 'Delete':
                            ec2.modify_instance_attribute(
                                InstanceId=instance_id,
                                DisableApiTermination={'Value': False}
                            )
                        cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
                    except Exception as e:
                        cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)})
            """))
            .handler("index.handler")
            .build();

        // 给Lambda添加修改EC2实例属性的权限
        disableTerminationLambda.addToRolePolicy(PolicyStatement.Builder.create()
            .actions(List.of("ec2:ModifyInstanceAttribute"))
            .resources(List.of(String.format("arn:aws:ec2:%s:%s:instance/%s", this.getRegion(), this.getAccount(), cfnBastion.getRef())))
            .build());

        // 创建自定义资源,关联堡垒机实例
        CustomResource.Builder.create(this, "DisableTerminationHook")
            .serviceToken(disableTerminationLambda.getFunctionArn())
            .properties(Map.of("InstanceId", cfnBastion.getRef()))
            .dependsOn(bastion) // 确保自定义资源在堡垒机销毁前执行
            .build();
    }
}

方案说明

  • 自定义资源会绑定堡垒机实例的生命周期:当CloudFormation执行销毁旧实例的操作时,会先触发Lambda函数关闭终止保护,再执行销毁。
  • 既满足渗透测试要求(实例运行时始终开启终止保护),又不会阻碍CDK/CloudFormation的正常更新流程。

替代方案:使用EC2启动模板(可选)

如果你的BastionHostLinux支持指定启动模板,可以在启动模板中配置DisableApiTermination=true,然后结合上述自定义资源方案,同样能解决更新时的销毁问题。不过此方案需要确保启动模板的配置与CDK代码兼容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:03:25