0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】CDKでVPCをCfnレベルで作成&サブネットをインポートして他で指定する方法

Posted at

概要

CDKでVPC周りをPythonで実装したので、紹介します。
基本的にCloudformationレベルのコンストラクトで実装しています。

CDKサンプルコード

以下はパブリックサブネット、プライベートサブネット、プロテクトサブネットをそれぞれ二つずつ作る構成です。Cfnレベルにしているので、インターネットゲートウェイ、NATゲートウェイ、ルートテーブルも一緒に明示的に指定して作成します。

class SampleApiStack(Stack):

    def __init__(self, scope: Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        system_tag = "sample-api"

        ##############################
        # VPC
        ##############################

        vpc = ec2.CfnVPC(self, f"{system_tag}-VPC",
            cidr_block="10.0.0.0/16",
            enable_dns_support=True,
            enable_dns_hostnames=True,
            tags=[{
                "key": "Name",
                "value": f"{system_tag}"
            }]
        )

        internet_gateway = ec2.CfnInternetGateway(self, f"{system_tag}-InternetGateway",
            tags=[{
                "key": "Name",
                "value": f"{system_tag}"
            }]
        )

        ec2.CfnVPCGatewayAttachment(self, f"{system_tag}-InternetGatewayAttachment",
            vpc_id=vpc.ref,
            internet_gateway_id=internet_gateway.ref
        )

        availability_zones = [f"{self.region}a", f"{self.region}c"]

        public_subnets = []
        private_subnets = []
        protected_subnets = []

        for i, az in enumerate(availability_zones):
            public_subnet = ec2.CfnSubnet(self, f"{system_tag}-PublicSubnet-{i+1}",
                vpc_id=vpc.ref,
                cidr_block=f"10.0.{i+1}.0/24",
                availability_zone=az,
                map_public_ip_on_launch=True,
                tags=[{
                    "key": "Name",
                    "value": f"{system_tag}-PublicSubnet-{i+1}"
                }]
            )
            public_subnets.append(public_subnet)

            private_subnet = ec2.CfnSubnet(self, f"{system_tag}-PrivateSubnet-{i+1}",
                vpc_id=vpc.ref,
                cidr_block=f"10.0.{i+3}.0/24",
                availability_zone=az,
                tags=[{
                    "key": "Name",
                    "value": f"{system_tag}-PrivateSubnet-{i+1}"
                }]
            )
            private_subnets.append(private_subnet)

            protected_subnet = ec2.CfnSubnet(self, f"{system_tag}-ProtectedSubnet-{i+1}",
                vpc_id=vpc.ref,
                cidr_block=f"10.0.{i+5}.0/24",
                availability_zone=az,
                tags=[{
                    "key": "Name",
                    "value": f"{system_tag}-ProtectedSubnet-{i+1}"
                }]
            )
            protected_subnets.append(protected_subnet)

        public_route_table = ec2.CfnRouteTable(self, f"{system_tag}-PublicRouteTable",
            vpc_id=vpc.ref,
            tags=[{
                "key": "Name",
                "value": f"{system_tag}-PublicRouteTable"
            }]
        )

        ec2.CfnRoute(self, f"{system_tag}-PublicRoute",
            route_table_id=public_route_table.ref,
            destination_cidr_block="0.0.0.0/0",
            gateway_id=internet_gateway.ref
        )

        for i, public_subnet in enumerate(public_subnets):
            ec2.CfnSubnetRouteTableAssociation(self, f"{system_tag}-PublicSubnetAssociation-{i+1}",
                subnet_id=public_subnet.ref,
                route_table_id=public_route_table.ref
            )

        nat_eips = []
        for i in range(len(availability_zones)):
            nat_eip = ec2.CfnEIP(self, f"{system_tag}-NatEIP-{i+1}",
                tags=[{
                    "key": "Name",
                    "value": f"{system_tag}-NatEIP-{i+1}"
                }]
            )
            nat_eips.append(nat_eip)

        nat_gateways = []
        for i, public_subnet in enumerate(public_subnets):
            nat_gateway = ec2.CfnNatGateway(self, f"{system_tag}-NatGateway-{i+1}",
                subnet_id=public_subnet.ref,
                allocation_id=nat_eips[i].attr_allocation_id,
                tags=[{
                    "key": "Name",
                    "value": f"{system_tag}-Public{i+1}"
                }]
            )
            nat_gateways.append(nat_gateway)

        private_route_tables = []
        for i, nat_gateway in enumerate(nat_gateways):
            private_route_table = ec2.CfnRouteTable(self, f"{system_tag}-PrivateRouteTable-{i+1}",
                vpc_id=vpc.ref,
                tags=[{
                    "key": "Name",
                    "value": f"{system_tag}-Private{i+1}"
                }]
            )
            private_route_tables.append(private_route_table)

            ec2.CfnRoute(self, f"{system_tag}-PrivateRoute-{i+1}",
                route_table_id=private_route_table.ref,
                destination_cidr_block="0.0.0.0/0",
                nat_gateway_id=nat_gateway.ref
            )

        for i, private_subnet in enumerate(private_subnets):
            ec2.CfnSubnetRouteTableAssociation(self, f"{system_tag}-PrivateSubnetAssociation-{i+1}",
                subnet_id=private_subnet.ref,
                route_table_id=private_route_tables[i].ref
            )

No routeTableId was provided to...警告について

ちなみに、以下のようにすることで仮想的にVPCのサブネット(private subnet)をインポートできます。

        private_subnets_vpc = ec2.Vpc.from_vpc_attributes(
            self, f"{system_tag}-PrivateSubnetsVPC",
            vpc_id=vpc.ref,
            availability_zones=availability_zones,
            private_subnet_ids=[private_subnet.ref for private_subnet in private_subnets],
            private_subnet_route_table_ids=[private_route_table.ref for private_route_table in private_route_tables]
        )

private_subnet_route_table_idsがない場合、以下のwarningが出ました。

No routeTableId was provided to the subnet at 'xxxx-PrivateSubnetsVPC/PrivateSubnet1'. Attempting to read its .routeTable.routeTableId will return null/undefined.

このwarningは、ec2.Vpc.from_vpc_attributesを使用して仮想的にインポートした VPC のサブネットに対して、routeTableIdが指定されていないために発生する警告。

AWS CDK はサブネットのルートテーブル情報を正しく解釈するためにrouteTableIdを必要としますが、指定されていない場合はnullまたはundefinedを返す可能性がありますよ、ということを伝えてくれています。

private_subnet_route_table_idsを指定してルートテーブル ID を明示的に渡すことで、この警告を解消できました。

ちなみに、仮想的にインポートされたVPCのサブネットは、以下のリソースで指定できました。

  • セキュリティグループ(ec2.SecurityGroup
  • EC2インスタンス(ec2.Instance
  • Lambda関数(_lambda.Function

その他エラー

RDS インスタンスが作成される VPC と、関連付けられているセキュリティグループが異なる VPC に存在してしまうと以下のエラーにも何度か遭遇しました。上述の通りにすることで、以下のエラーが出ることは無くなりました。

Resource handler returned message: "The DB instance and EC2 security group are in different VPCs. The DB instance is in vpc-xxxxxxxx and the EC2 security group is in vpc-xxxxxxxxxxxxxxxx

また、

  • vpc にec2.CfnVPC(L1 コンストラクト)を渡している
  • ec2.SecurityGroup(L2 コンストラクト)はec2.Vpc(L2 コンストラクト)を期待している

という状態だと以下のエラーになります。
L1 コンストラクトと L2 コンストラクトの混在は、CDK作成の際に留意するポイントですね。

"SecurityGroupEgress cannot be specified without VpcId"

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?