CDKを使用してVPCを作成する

CDK+Pythonで3層構造のVPCを作成してみます。 AWS CDK(AWS Cloud Development)はAWSが提供しているIaCツールです。 TypeScriptやPythonなどの言語を使用してコードベースでインフラを定義することができます。
2022.01.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

今回作成するリソース

今回は2個のAZにまたがってVPCを定義します。 各AZにはpublicprivateisolatedの三つのサブネットを用意します。 図にすると以下のようになります。

publicサブネット

publicサブネットではインターネットゲートウェイへのルーティングが設定されており、直接インターネットとのやり取りが可能です。ElasticIPを割り振ることでEC2インスタンス、ELB、NATゲートウェイが外部からの通信を受け入れることが可能です。

privateサブネット

privateサブネットでは外部との通信はNATゲートウェイを介して行われます。インターネットゲートウェイへのルーティングがなく、基本的にはインターネットからのアクセスはありません。なので、publicサブネットを介して通信が行われることがあります。

isolatedサブネット

isolatedサブネットはローカルとの通信しかできません。ここではpublicprivateとの相互通信が可能です。 DBなど外部への通信が不要で、ローカルなマシンとののみ通信が必要なリソースがしばしば設置されます。

準備

CDKの準備

まずはCDKの準備をします。 今回はPythonを使用します。

PythonのCDKのパッケージのバージョンはaws-cdk-lib==2.9.0です。

CDKの準備

$ npm init
$ npm install aws-cdk
$ mkdir three-tier
$ cd three-tier
$ npx cdk init --language python

つぎにCDKで使用するPythonパッケージをインストールします。 CDKでPythonを使用する場合はvenvが用意されているので、それを使うと便利です。

依存関係のインストール

$ source .venv/bin/activate
$ pip3 install -r requirements.txt

以降では常にsource .venv/bin/activateを行ったあとのvenvの環境で作業を行います。

コードの準備

まずはスタックを定義します。

three_tier_stack.py

from aws_cdk import (
    Stack,
    aws_ec2 as ec2
)
from constructs import Construct

VCP_CIDR = '192.168.0.0/16'


class ThreeTierStack(Stack):

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

        self.vpc = ec2.Vpc(
            self,
            'three-tier',
            cidr=VCP_CIDR,
            max_azs=2,
            subnet_configuration=[
                ec2.SubnetConfiguration(
                    name='public',
                    subnet_type=ec2.SubnetType.PUBLIC
                ),
                ec2.SubnetConfiguration(
                    name='private',
                    subnet_type=ec2.SubnetType.PRIVATE_WITH_NAT
                ),
                ec2.SubnetConfiguration(
                    name='isolated',
                    subnet_type=ec2.SubnetType.PRIVATE_ISOLATED
                ),
            ]
        )

ここではVPCの定義を行っています。ec2.Vpcはリソースを作成するためのハイレベルなインターフェイスで、少ない手順でVPCで使用するインターネットゲートウェイや、NATゲートウェイ、サブネットなどの設定ができます。

ここではmax_azsを2とすることで以下でサブネットが各AZ毎に作成されます。

subnet_configurationではサブネットの設定を行っています。CIDRの分割はVPCに設定されたCIDRから自動で行ってくれます。このときsubnet_typeを指定することで先述のpublicprivateisolatedの設定ができます。

一緒にapp.pyも書き換えます。

app.py

#!/usr/bin/env python3
import os

import aws_cdk as cdk

from vpc.vpc_stack import ThreeTierStack

app = cdk.App()
vpc_stack = ThreeTierStack(app, "ThreeTierVPC")
cdk.Tags.of(vpc_stack).add('Project', 'three-tier')

app.synth()

ここではStackにタグをつけています。こうすることで、スタック内で作成されるリソースにタグが自動てつけられます。 タグのキーはProjectで値はthree-tierです。

デプロイする

最初にブートストラップを行い初期化を行ったのち、デプロイします。 デプロイには10分ぐらいの時間がかかります。

デプロイ

$ npx cdk bootstrap
$ npx cdk deploy

結果を確認する

サブネットのAZとCIDRを確認する

まずはサブネットの一覧を確認してみます。(見やすいように適宜開業を入れてあります。)

サブネット一覧

$ aws ec2 describe-subnets \
    --filter "Name=tag:Project,Values=three-tier" \
    --query 'Subnets[].[Tags[?Key==`Name`].Value,[AvailabilityZone,CidrBlock]] | reverse(sort_by(@, &[0][0]))' \
    --output text

ThreeTierVPC/three-tier/publicSubnet2
ap-northeast-1c 192.168.32.0/19
ThreeTierVPC/three-tier/publicSubnet1
ap-northeast-1a 192.168.0.0/19

ThreeTierVPC/three-tier/privateSubnet2
ap-northeast-1c 192.168.96.0/19
ThreeTierVPC/three-tier/privateSubnet1
ap-northeast-1a 192.168.64.0/19

ThreeTierVPC/three-tier/isolatedSubnet2
ap-northeast-1c 192.168.160.0/19
ThreeTierVPC/three-tier/isolatedSubnet1
ap-northeast-1a 192.168.128.0/19

ap-northeast-1aap-northeast-1aにそれぞれサブネットが作られています。

ルートテーブルの確認

続いてルートテーブルの設定を見てみます。

ルートテーブル

$ aws ec2 describe-route-tables \
    --filter "Name=tag:Project,Values=three-tier"\
    --query 'RouteTables[].[Tags[?Key==`Name`].Value,Routes[].[DestinationCidrBlock,GatewayId,NatGatewayId]] | reverse(sort_by(@, &[0][0]))' \
    --output text

ThreeTierVPC/three-tier/publicSubnet2
192.168.0.0/16  local   None
0.0.0.0/0       igw-XXXXXX   None
ThreeTierVPC/three-tier/publicSubnet1
192.168.0.0/16  local   None
0.0.0.0/0       igw-XXXXXX   None

ThreeTierVPC/three-tier/privateSubnet2
192.168.0.0/16  local   None
0.0.0.0/0       None    nat-XXXXXX
ThreeTierVPC/three-tier/privateSubnet1
192.168.0.0/16  local   None
0.0.0.0/0       None    nat-YYYYYY

ThreeTierVPC/three-tier/isolatedSubnet2
192.168.0.0/16  local   None
ThreeTierVPC/three-tier/isolatedSubnet1
192.168.0.0/16  local   None

publicサブネットにはインターネットゲートウェイ(igw-XXXXXX)へのルーティングが設定されています。

同様にprivateサブネットではNATゲートウェイ(nat-XXXXXX、nat-YYYYYY)へのルーティングが定義されています。

isolatedサブネットではローカル以外のルーティングが定義されていません。

また、privateサブネットではサブネット毎に異なったNATゲートウェイが指定されています。 これは各AZのpublicサブネットに展開されたNATゲートウェイを参照しているためです。 つまりは、同一AZのNATゲートウェイを使用するようになっています。

削除する

最後に削除して終わります。

スタックの削除

$ npx cdk destroy

最後に

CDKを使用することで簡単に複雑な構造のVPCを定義することができました。 細かい設定をしない場合はこのようにハイレベルのインターフェイスを使用することで手順を省くことができます。