起きたこと
AWS CDKを使ってEKSクラスタを含むインフラの構成管理を試している際、cdk destroy
が正常に通らなかったり、VPC作成を含む変更が失敗した際にロールバックも失敗する問題が発生しました。
調査したところ、身に覚えのないVPCエンドポイントが作成されており、それがCDKの管理外であるため削除されず、結果として以下のリソースの削除を阻害していました。
- ネットワークインターフェースの削除失敗
- サブネットの削除失敗
- VPCの削除失敗
原因
この問題の原因は、AWSアカウントでランタイムモニタリングを有効にしていて、EKSの自動エージェント設定を有効にしているとGuardDutyのVPCエンドポイントが自動的に作成されることにあります。
AWS CDKでEKSクラスタを構築する際、AWSアカウントでGuardDutyを利用していると、GuardDutyが自動的にVPCエンドポイントを作成します。このVPCエンドポイントはCDKの管理外であり、cdk destroy
時に削除されないため、結果的にVPC全体の削除が妨げられるという問題が発生しました。
参考ドキュメント:
Using AWS CloudFormation and other Infrastructure as Code (IaC) tools with Amazon GuardDuty
対処法
この問題を回避するためには、GuardDuty用のVPCエンドポイントをCDKで作成し、CDKの管理下に置くことが有効です。
具体的な対処方法:CDKでGuardDuty用のVPCエンドポイントを明示的に作成
import * as cdk from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as eks from "aws-cdk-lib/aws-eks";
class EksClusterStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const vpc = new ec2.Vpc(stack, "Vpc", {
ipAddresses: ec2.IpAddresses.cidr("10.0.0.0/16"),
availabilityZones: ["ap-northeast-1b", "ap-northeast-1c"],
natGateways: 1,
ipProtocol: ec2.IpProtocol.DUAL_STACK,
subnetConfiguration: [
{
name: "PublicSubnet",
subnetType: ec2.SubnetType.PUBLIC,
cidrMask: 24,
ipv6AssignAddressOnCreation: true,
},
{
name: "PrivateSubnet",
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
cidrMask: 24,
ipv6AssignAddressOnCreation: true,
},
],
});
const guardDutySecurityGroup = new ec2.SecurityGroup(
stack,
"GuardDutyVpcEndpointSG",
{
vpc,
description: "Allow inbound traffic for GuardDuty VPC Endpoint",
allowAllOutbound: true,
}
);
// GuardDuty VPC エンドポイントの作成
const guardDutyVpcEndpoint = vpc.addInterfaceEndpoint(
"GuardDutyDataEndpoint",
{
service: ec2.InterfaceVpcEndpointAwsService.GUARDDUTY_DATA,
privateDnsEnabled: true,
securityGroups: [guardDutySecurityGroup],
subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
}
);
// GuardDuty のセキュリティグループに EKS, RDS, OpenSearch などからのアクセスを許可
guardDutySecurityGroup.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(443),
"Allow GuardDuty data traffic"
);
}
}
これにより、CDKの管理下でGuardDuty用のVPCエンドポイントが作成され、cdk destroy
時に適切に削除されるようになります。
ちなみに、VPC作成時に明示的にAZを指定しているのにも理由があります。
ap-northeast-1リージョンでは、NATゲートウェイを作れないAZがあるのです。
実はアカウントごとにAZを表すa,b,c,dと物理的なAZの対応関係は異なっているので、どのAZがハズレなのかはやってみないとわからないのですが、我々の環境ではap-northeast-1aがハズレAZでした。
まとめ
AWS CDKを使ってEKSクラスタを構成管理する際、GuardDutyが自動でVPCエンドポイントを作成することで、CDKの管理外リソースが発生し、削除やロールバックに失敗する問題があることがわかりました。
この問題を防ぐためには、GuardDuty用のVPCエンドポイントを明示的にCDKで作成し、CDK管理下に置くことが重要です。これにより、cdk destroy
時の削除エラーやロールバック失敗を防ぐことができます。