LoginSignup
3
0

AWS CDK で Infrastructure as Code する: VPC編

Last updated at Posted at 2023-08-14

こんにちは。AWS勉強中の @masatomix です。

前回?までAWS CDKをいろいろいじくったところを記事にしていましたが、ひきつづき AWS CDKです。これからAWS CDK / CloudFormationでいろいろ AWSのリソースを作成するサンプルを作っていきたいのですが、なにはともあれ独立したVPCがほしいので、まずはVPCを新規作成するサンプルです。

前提

やってみる

作りたい環境はこんな感じ。

2FbK1J3

Availability Zone 3つにまたがるVPCを構築し、各AZにPublic/Private のSubnetを1つずつ。Private SubnetがInternet に出て行くための NAT Gatewayは1つのAZに配置1

もちろん、NAT Gatewayに割り振るElastic IPやInternet Gateway、各Subnetがネットに出て行くためのRouteTableなども作成しています。

CDKのソースコード

コードです

lib/VPCStack.ts
import { App, CfnParameter, Stack, StackProps } from 'aws-cdk-lib'
import {
  CfnEIP,
  CfnInternetGateway,
  CfnNatGateway,
  CfnRoute,
  CfnRouteTable,
  CfnSubnet,
  CfnSubnetRouteTableAssociation,
  CfnVPC,
  CfnVPCGatewayAttachment,
} from 'aws-cdk-lib/aws-ec2'
import { availabilityZones, getProfile } from './Utils'
// import * as sqs from 'aws-cdk-lib/aws-sqs';

export class VPCStack extends Stack {
  public readonly vpc: CfnVPC
  public readonly publicSubnets: CfnSubnet[]
  public readonly privateSubnets: CfnSubnet[]

  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props)

    // The code that defines your stack goes here
    const p = getProfile(this)

    const vpcCIDRs = {
      vpc: '192.168.0.0/16',
      subnets: [
        { public: '192.168.0.0/24', private: '192.168.1.0/24' },
        { public: '192.168.2.0/24', private: '192.168.3.0/24' },
        { public: '192.168.4.0/24', private: '192.168.5.0/24' },
      ],
    }
    const subnetCount = vpcCIDRs.subnets.length

    // VPC
    const vpc = new CfnVPC(this, `MyVPC`, {
      cidrBlock: vpcCIDRs.vpc,
      tags: [{ key: 'Name', value: `${p.name}-vpc` }],
    })
    this.vpc = vpc

    // Public Subnet
    const publicSubnets = vpcCIDRs.subnets.map(
      (subnet, index) =>
        new CfnSubnet(this, `MyPublicSubnet${index}`, {
          vpcId: vpc.ref,
          cidrBlock: subnet.public,
          availabilityZone: availabilityZones[index],
          mapPublicIpOnLaunch: true,
          tags: [{ key: 'Name', value: `${p.name}-public-subnet-${index}` }],
        }),
    )
    this.publicSubnets = publicSubnets

    // Private Subnet
    const privateSubnets = vpcCIDRs.subnets.map(
      (subnet, index) =>
        new CfnSubnet(this, `MyPrivateSubnet${index}`, {
          vpcId: vpc.ref,
          cidrBlock: subnet.private,
          availabilityZone: availabilityZones[index],
          mapPublicIpOnLaunch: false,
          tags: [{ key: 'Name', value: `${p.name}-private-subnet-${index}` }],
        }),
    )
    this.privateSubnets = privateSubnets

    // Internet Gateway
    const igw = new CfnInternetGateway(this, 'MyInternetGateWay', { tags: [{ key: 'Name', value: `${p.name}-igw` }] })
    const attachInternetGateway = new CfnVPCGatewayAttachment(this, 'AttachGateway', {
      vpcId: vpc.ref,
      internetGatewayId: igw.ref,
    })

    // Public RouteTables
    const publicRouteTables = vpcCIDRs.subnets.map(
      (subnet, index) =>
        new CfnRouteTable(this, `PublicRouteTable${index}`, {
          vpcId: vpc.ref,
          tags: [{ key: 'Name', value: `${p.name}-public-route-${index}` }],
        }),
    )

    // Private RouteTables
    const privateRouteTables = vpcCIDRs.subnets.map(
      (subnet, index) =>
        new CfnRouteTable(this, `PrivateRouteTable${index}`, {
          vpcId: vpc.ref,
          tags: [{ key: 'Name', value: `${p.name}-private-route-${index}` }],
        }),
    )

    for (let index = 0; index < subnetCount; index++) {
      // 各Public用 RouteTableに Public Subnetを紐付け
      new CfnSubnetRouteTableAssociation(this, `PublicSubnetRouteTableAssociation${index}`, {
        routeTableId: publicRouteTables[index].ref,
        subnetId: publicSubnets[index].ref,
      })

      // そのRouteTableはInternet Gatewayを紐付ける
      new CfnRoute(this, `PublicRouteToIGW${index}`, {
        routeTableId: publicRouteTables[index].ref,
        destinationCidrBlock: '0.0.0.0/0',
        gatewayId: igw.ref,
      })

      // 各Private用 RouteTableに Private Subnetを紐付け
      new CfnSubnetRouteTableAssociation(this, `PrivateSubnetRouteTableAssociation${index}`, {
        routeTableId: privateRouteTables[index].ref,
        subnetId: privateSubnets[index].ref,
      })
    }

    // // 各Subnetに、NAT GWを置くパタン
    // const eips = [...new Array(subnetCount)].map((_: undefined, index: number) => {
    //   return new CfnEIP(this, `EIPforNatGw${index}`, { domain: 'vpc' })
    // })
    // const natgws = [...new Array(subnetCount)].map((_: undefined, index: number) => {
    //   return new CfnNatGateway(this, `MyNAT${index}`, {
    //     allocationId: eips[index].attrAllocationId,
    //     subnetId: publicSubnets[index].ref
    //   })
    // })
    // for (let i = 0; i < subnetCount; i++) {
    //   new CfnRoute(this, `RouteToNAT${i}`, {
    //     routeTableId: privateRouteTables[i].ref,
    //     destinationCidrBlock: '0.0.0.0/0',
    //     natGatewayId: natgws[i].ref
    //   })
    // }
    // // 各Subnetに、NAT GWを置くパタン

    // 1Subnetに、NAT GWを置くパタン
    // publicSubnets[0] に、NAT GWを配置して
    const eip = new CfnEIP(this, 'EIPforNatGw1', { domain: 'vpc' })
    const natgw = new CfnNatGateway(this, `MyNAT1`, {
      allocationId: eip.attrAllocationId,
      subnetId: publicSubnets[0].ref,
      tags: [{ key: 'Name', value: `${p.name}-natgw` }],
    })
    natgw.addDependency(attachInternetGateway)

    // そのNAT GWを各Private SubnetのRouteTableにセットする
    for (let i = 0; i < subnetCount; i++) {
      new CfnRoute(this, `RouteToNAT${i}`, {
        routeTableId: privateRouteTables[i].ref,
        destinationCidrBlock: '0.0.0.0/0',
        natGatewayId: natgw.ref,
      })
    }
    // 1Subnetに、NAT GWを置くパタン
  }
}
bin/cdk-samples.ts
#!/usr/bin/env node
import 'source-map-support/register'
import * as cdk from 'aws-cdk-lib'
import { VPCStack } from '../lib/VPCStack'

const app = new cdk.App()

const vpcStack = new VPCStack(app, 'VPCStack')
cdk.json(主要な部分だけ)
{
  "app": "npx ts-node --prefer-ts-exts bin/cdk-samples.ts",
  ...
  "context": {
    ...
    "dev": {
      "name": "dev-20230815"
    }
  }
}

ちなみに上記の"dev":{"name": "dev-20230815"} によって
tags: [{ key: 'Name', value: `${p.name}-vpc` }],などのプレースホルダが
dev-20230815-vpc に置換されるようにしてあります。

実行してみる

コードを作ったら、では実行してみます。

$ yarn cdk deploy VPCStack
... しばらくかかります
$

ちゃんとできているか一応確認します。

$ aws ec2 describe-vpcs \
 --query "Vpcs[*].[(Tags[?Key=='Name'])[0].Value,VpcId,CidrBlock]" \
 --filters "Name=tag:Name,Values=dev-20230815-vpc" \
 --output table
-----------------------------------------------------------------
|                         DescribeVpcs                          |
+------------------+-------------------------+------------------+
|  dev-20230815-vpc|  vpc-0461b6f7baff8f8d1  |  192.168.0.0/16  |
+------------------+-------------------------+------------------+

$ aws ec2 describe-subnets \
--query "Subnets[*].[(Tags[?Key=='Name'])[0].Value,CidrBlock,SubnetId]" \
--filters "Name=vpc-id, Values=vpc-0461b6f7baff8f8d1" \
--output table
---------------------------------------------------------------------------------
|                                DescribeSubnets                                |
+--------------------------------+-----------------+----------------------------+
|  dev-20230815-public-subnet-0  |  192.168.0.0/24 |  subnet-0ec370f96cfb4e93b  |
|  dev-20230815-private-subnet-2 |  192.168.5.0/24 |  subnet-0f7dcb24813414db1  |
|  dev-20230815-private-subnet-1 |  192.168.3.0/24 |  subnet-03587fc0cf1fb9ae8  |
|  dev-20230815-public-subnet-1  |  192.168.2.0/24 |  subnet-0c05e26c010e2fa3c  |
|  dev-20230815-public-subnet-2  |  192.168.4.0/24 |  subnet-0e2cda5c21e1e6370  |
|  dev-20230815-private-subnet-0 |  192.168.1.0/24 |  subnet-0a5ec4312d172c4b1  |
+--------------------------------+-----------------+----------------------------+
$

ちゃんとできていそうですね。お疲れさまでした!

関連リンク

  1. 本番構成では各AZに置くべきやつです。

3
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
3
0