AWSCLIを使用してVPC・サブネットを作成

[別記事](https://qiita.com/tonkatsu_oishi/items/ee5d7f64a43ba7deb671)にて、AWSコンソール上から東京リージョンにVPC・パブリックサブネット・プライベートサブネットを構築する手順をご紹介しました。
AWSを利用していると、DR対応などで複数リージョンに似たような構成を構築する場面が多くあります。
こういった場合には、コンソール上での操作よりもawscliコマンドやCloudFormationテンプレート・Terraformテンプレートを使用しての環境構築の方が作業が効率化できます。

今回はawscliを利用して、VPC・パブリックサブネット・プライベートサブネットを構築する手順を確認していきます。

## 構成の確認
今回構築するリソースは下記構成図の内容です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/693fadb4-5477-093d-8891-60cf296c8c26.png)

今回は大阪リージョンに172.31.0.0/21の範囲でVPCを構築します。
VPCにはインターネットゲートウェイをアタッチします。
VPCの中には、パブリックサブネットを二つ、プライベートサブネットを二つ構築します。
パブリックサブネットにはNatGatewayを構築し、プライベートサブネットからNatGateway経由でインターネットアクセスを行えるように設定します。

※用語やコンソールでの構築手順については[別記事](https://qiita.com/tonkatsu_oishi/items/ee5d7f64a43ba7deb671)にて確認しています。VPCやサブネット、ルートテーブルの作成が初めてという方は、まずは[別記事](https://qiita.com/tonkatsu_oishi/items/ee5d7f64a43ba7deb671)の手順からご確認することをお勧めします。

## 構築
### CloudShellの起動
AWSコンソールにログイン後、コンソール左下の「CloudShell」のリンクを押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/316ce33b-1e5f-fe7d-fdc3-3096f9cb4eaa.png)

しばらく待機すると、CloudShellが立ち上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/6a8abe12-6000-bba2-b0d2-ec77b15edb27.png)

ここからコマンドを実行していきます。

### VPCの作成
#### VPCの作成
awscliのフィルターの使用方法などは[別記事](https://qiita.com/tonkatsu_oishi/private/3b33c473f5f476e2bb62)にてご紹介したため割愛し、今回は構築に使用したコマンドを中心に見ていこうと思います。

**基本の構文**

    aws ec2 create-vpc --cidr-block <CidrBlock>
[参考:awscliコマンドリファレンス（create-vpc)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-vpc.html#create-vpc)

**実行したコマンド**
今回は「172.31.0.0/21」のVPCを構築します。
後続の作業をやりやすくするために、awscliの返り値から「VPCID」の部分だけを抜き出して「VPC_ID」という変数に格納します。

    VPC_ID=$(aws ec2 create-vpc --cidr-block 172.31.0.0/21 --query "Vpc.VpcId" --output text)

下記コマンドを実行し、VPCIDを確認します。

    echo $VPC_ID


#### 作成したVPCにタグを付与
**基本の構文**

    aws ec2 create-tags --resources <リソースID> --tags Key=<タグのキー>,Value=<タグの値>

[参考:awscliコマンドリファレンス（create-tags)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-tags.html)

**実行したコマンド**
先程作成したVPCに対してタグを付与します。
今回は、「Name」タグに「HTTPS_DEMO_VPC」を、「Region」タグに「Osaka」を設定します。

    aws ec2 create-tags --resources $VPC_ID --tags Key=Name,Value=HTTPS_DEMO_VPC Key=Region,Value=Osaka

#### VPCが作成されていることを確認
先程作成したVPCが、通常通り作成されたことを確認します。

    aws ec2 describe-vpcs --vpc-ids $VPC_ID --query 'Vpcs[0].{CIDR:CidrBlock,VpcId:VpcId,Name:Tags[?Key==`Name`].Value|[0]}' --output table

[参考：awscliコマンドリファレンス(describe-vpcs)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-vpcs.html)

下記のような感じで結果が返ってくれば成功です。
    
    --------------------------------------------------------------
    |                        DescribeVpcs                        |
    +---------------+------------------+-------------------------+
    |     CIDR      |      Name        |          VpcId          |
    +---------------+------------------+-------------------------+
    |  172.31.0.0/21|  HTTPS_DEMO_VPC  |  vpc-*****************  |
    +---------------+------------------+-------------------------+
    
### IGWを作成しVPCに割り当てる
作成したVPCに対してIGWを割り当てます。
まずはIGWを作成します。
#### IGWの作成
**基本の構文**
    aws ec2 create-internet-gateway
[参考:awscliコマンドリファレンス（create-internet-gateway)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-internet-gateway.html)

**実行したコマンド*
後続の作業をやりやすくするために、awscliの返り値から「InternetGatewayId」の部分だけを抜き出して「IGW_ID」という変数に格納します。

    IGW_ID=$(aws ec2 create-internet-gateway --query InternetGateway.InternetGatewayId --output text)

#### IGWをVPCにアタッチ
作成したIGWを先ほど作成したVPCにアタッチします。
**基本の構文**

    aws ec2 attach-internet-gateway --internet-gateway-id <IGWのID> --vpc-id <VPCのID>

[参考:awscliコマンドリファレンス(attach-internet-gateway)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/attach-internet-gateway.html)

**実行したコマンド**
    
    aws ec2 attach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID

### IGWがVPCにアタッチされたことを確認

作成したIGWがVPCにアタッチされていることを確認します。

    aws ec2 describe-internet-gateways   --query "InternetGateways[*].{Name:Tags[?Key=='Name'].Value|[0],State:Attachments[0].State,VpcId:Attachments[0].VpcId}" --output table

下記のような形で結果が返ってくれば成功です。

    ---------------------------------------------------------
    |               DescribeInternetGateways                |
    +----------------+------------+-------------------------+
    |      Name      |   State    |          VpcId          |
    +----------------+------------+-------------------------+
    |  HTTP_DEMO_IGW |  available |  vpc-*****************  |
    +----------------+------------+-------------------------+

### サブネットの作成
先ほど作成したVPCに、サブネットを四つ追加します。
#### サブネットの作成
**基本の構文**

    aws ec2 create-subnet --vpc-id <VPCID> --cidr-block <CIDR> --availability-zone-id <AZのID>

[参考:awscliコマンドリファレンス（create-subnet)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-subnet.html)

**実行したコマンド**
今回はAZ3aとAZ3aそれぞれにプライベートサブネット・パブリックサブネットを一つずつ作成します。
そのため、四回「create-subnet」コマンドを実行しています。
後続の作業をやりやすくするために、作成したサブネットのサブネットIDを変数に格納しました。

    HTTPS_DEMO_SUB_PRV3a=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 172.31.1.0/24 --availability-zone-id apne3-az3 --query Subnet.SubnetId --output text)
    HTTPS_DEMO_SUB_PUB3a=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 172.31.0.0/24 --availability-zone-id apne3-az3 --query Subnet.SubnetId --output text)
    HTTPS_DEMO_SUB_PRV3c=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 172.31.5.0/24 --availability-zone-id apne3-az2 --query Subnet.SubnetId --output text)
    HTTPS_DEMO_SUB_PUB3c=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 172.31.4.0/24 --availability-zone-id apne3-az2 --query Subnet.SubnetId --output text)


下記のようにコマンドを実行し、サブネットIDを確認します。

    echo $HTTPS_DEMO_SUB_PRV3a
    echo $HTTPS_DEMO_SUB_PUB3a
    echo $HTTPS_DEMO_SUB_PRV3c
    echo $HTTPS_DEMO_SUB_PUB3c

#### サブネットにNameタグを付与
それぞれのサブネットにNameタグを付与します。

    aws ec2 create-tags --resources $HTTPS_DEMO_SUB_PRV3a --tags Key=Name,Value=HTTPS_DEMO_SUB_PRV3a Key=Region,Value=Osaka
    aws ec2 create-tags --resources $HTTPS_DEMO_SUB_PUB3a --tags Key=Name,Value=HTTPS_DEMO_SUB_PUB3a Key=Region,Value=Osaka
    aws ec2 create-tags --resources $HTTPS_DEMO_SUB_PRV3c --tags Key=Name,Value=HTTPS_DEMO_SUB_PRV3c Key=Region,Value=Osaka
    aws ec2 create-tags --resources $HTTPS_DEMO_SUB_PUB3c --tags Key=Name,Value=HTTPS_DEMO_SUB_PUB3c Key=Region,Value=Osaka

#### サブネットが作成されていることを確認
サブネットが通常通り作成できてタグが付与できたことを確認します。

    aws ec2 describe-subnets \
      --filters "Name=tag:Name,Values=HTTPS_DEMO_*" \
      --query "Subnets[*].{SubnetId:SubnetId,CidrBlock:CidrBlock,Name:Tags[?Key=='Name'].Value|[0]}" \
      --output table
[参考:awscliコマンドリファレンス（describe-subnets)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-subnets.html)

### ルートテーブルの作成・アタッチ
今回はプライベートサブネット用・パブリックサブネット用で二つのルートテーブルを作成し、それぞれのサブネットにアタッチします。

#### ルートテーブル作成
**基本の構文**

    aws ec2 create-route-table --vpc-id <VPCID>

[参考:awscliコマンドリファレンス（create-route-table)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-route-table.html)

**実行したコマンド**
今回は先ほど作成したVPC（変数VPC_IDにVPCIDを格納）を指定してルートテーブルを作成します。
後続の作業をやりやすくするために、ルートテーブルIDを変数に格納します。


    HTTPS_DEMO_RTB_PUB=$(aws ec2 create-route-table --vpc-id $VPC_ID --query RouteTable.RouteTableId --output text)
    HTTPS_DEMO_RTB_PRV=$(aws ec2 create-route-table --vpc-id $VPC_ID --query RouteTable.RouteTableId --output text)

下記のようにコマンドを実行し、ルートテーブルIDを確認します。
    
    echo $HTTPS_DEMO_RTB_PUB
    echo $HTTPS_DEMO_RTB_PRV

#### ルートテーブルにタグを付与
先程作成したルートテーブルにNameタグ、Regionタグを付与します。

    aws ec2 create-tags --resources $HTTPS_DEMO_RTB_PUB --tags Key=Name,Value=HTTPS_DEMO_RTB_PUB Key=Region,Value=Osaka
    aws ec2 create-tags --resources $HTTPS_DEMO_RTB_PRV --tags Key=Name,Value=HTTPS_DEMO_RTB_PRV Key=Region,Value=Osaka

#### ルートテーブルが作成されていることを確認
ルートテーブルが通常通り作成できてタグも付与できたことを確認します。

    aws ec2 describe-route-tables --filters "Name=tag:Name,Values=HTTPS_DEMO_*" \
    --query "RouteTables[*].{RouteTableId:RouteTableId,Name:Tags[?Key=='Name'].Value|[0]}" --output table

[参考：awscliコマンドリファレンス（describe-route-tables)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-route-tables.html)

下記のような形で結果が返ってくれば成功です。
    
    -----------------------------------------------------------------------
    |                           DescribeSubnets                           |
    +---------------+------------------------+----------------------------+
    |   CidrBlock   |         Name           |         SubnetId           |
    +---------------+------------------------+----------------------------+
    |  172.31.5.0/24|  HTTPS_DEMO_SUB_PRV3c  |  subnet-*****************  |
    |  172.31.0.0/24|  HTTPS_DEMO_SUB_PUB3a  |  subnet-*****************  |
    |  172.31.4.0/24|  HTTPS_DEMO_SUB_PUB3c  |  subnet-*****************  |
    |  172.31.1.0/24|  HTTPS_DEMO_SUB_PRV3a  |  subnet-*****************  |
    +---------------+------------------------+----------------------------+

#### ルートテーブルをサブネットと紐づけ
作成したルートテーブルをサブネットに紐づけます。
**基本の構文**

    aws ec2 associate-route-table --route-table-id <ルートテーブルID> --subnet-id <サブネットID>
[参考：awscliコマンドリファレンス（associate-route-table)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/associate-route-table.html)

**実行したコマンド**

    aws ec2 associate-route-table --route-table-id $HTTPS_DEMO_RTB_PUB --subnet-id $HTTPS_DEMO_SUB_PUB3a
    aws ec2 associate-route-table --route-table-id $HTTPS_DEMO_RTB_PUB --subnet-id $HTTPS_DEMO_SUB_PUB3c
    aws ec2 associate-route-table --route-table-id $HTTPS_DEMO_RTB_PRV --subnet-id $HTTPS_DEMO_SUB_PRV3c
    aws ec2 associate-route-table --route-table-id $HTTPS_DEMO_RTB_PRV --subnet-id $HTTPS_DEMO_SUB_PRV3a


#### ルートテーブルとサブネットの紐づけ確認
ルートテーブルを各サブネットに紐づけられたことを確認します。

    aws ec2 describe-route-tables --filters "Name=tag:Name,Values=HTTPS_DEMO_*" --query "RouteTables[*].{Name:Tags[?Key=='Name'].Value|[0],Subnet:Associations[].SubnetId}" --output table

[参考：awscliコマンドリファレンス（describe-route-tables)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-route-tables.html)

下記のような形で結果が返ってくれば成功です。

    --------------------------------
    |      DescribeRouteTables     |
    +------------------------------+
    |             Name             |
    +------------------------------+
    |  HTTPS_DEMO_RTB_PUB          |
    +------------------------------+
    ||           Subnet           ||
    |+----------------------------+|
    ||  subnet-*****************  ||
    ||  subnet-*****************  ||
    |+----------------------------+|
    |      DescribeRouteTables     |
    +------------------------------+
    |             Name             |
    +------------------------------+
    |  HTTPS_DEMO_RTB_PRV          |
    +------------------------------+
    ||           Subnet           ||
    |+----------------------------+|
    ||  subnet-*****************  ||
    ||  subnet-*****************  ||
    |+----------------------------+|

※いろいろと試してみたのですが、table形式できれいに横長の表を出すことができませんでした。すみません。

### NGW作成
プライベートサブネットからインターネットにアクセスできるよう、NATGatewayを作成します。
#### ElasticIP作成
まずはEIPを作成します。

**基本の構文**

    aws ec2 allocate-address

**実行したコマンド**
NATGatewayを作成する際にEIPのallocation-idを指定する必要があるため、出力結果から[allocation-id]を抜き出して変数に格納します。

    EIP_ID=$(aws ec2 allocate-address --query AllocationId --output text)

allocation-idを確認します。

    echo $EIP_ID

#### EIPにNameタグを付与
EIPにNameタグ、Regionタグを付与しておきます。
    
    aws ec2 create-tags \
      --resources $EIP_ID \
      --tags Key=Name,Value=HTTPS_DEMO_NAT_IP Key=Region,Value=Osaka

#### NGWの作成
**基本の構文**

    aws ec2 create-nat-gateway --subnet-id <サブネットID> --allocation-id <EIPのallocation-id>

[参考：awscliコマンドリファレンス（create-nat-gateway)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-nat-gateway.html)

**実行したコマンド**
今回はAZ3aのパブリックサブネットを指定してNATGatewayを作成します。
後続の作業のため、作成したNATGatewayのIDを変数に格納します。

    NGW_ID=$(aws ec2 create-nat-gateway --subnet-id $HTTPS_DEMO_SUB_PUB3a --allocation-id $EIP_ID --query NatGateway.NatGatewayId --output text)

NATGatewayのIDを確認します。

    echo $NGW_ID

#### NatGatewayにタグを付与
NATGatewayにNameタグ、Regionタグを付与します。

    aws ec2 create-tags --resources $NGW_ID --tags Key=Name,Value=HTTPS_DEMO_NAT3a


#### NatGatewayが作成されたことを確認
NATGatewayが作成できてタグも付与できたことを確認します。

    aws ec2 describe-nat-gateways --filter "Name=tag:Name,Values=HTTPS_DEMO_*" \
    --query "NatGateways[*].{Id:NatGatewayId,Name:Tags[?Key=='Name'].Value|[0]}" --output table

下記のような形で結果が返ってくれば成功です。
    
    -----------------------------------------------
    |             DescribeNatGateways             |
    +------------------------+--------------------+
    |           Id           |       Name         |
    +------------------------+--------------------+
    |  nat-***************** |  HTTPS_DEMO_NAT3a  |
    +------------------------+--------------------+

### ルートテーブルにルートを作成
パブリックサブネット用のルートテーブル・プライベートサブネット用のルートテーブルそれぞれにルート情報を設定します。

#### パブリックサブネットのルートテーブルにルートを設定
パブリックサブネット用のルートテーブルには、「0.0.0.0/0(デフォルトルート）」でインターネットゲートウェイを指定します。
##### パブリックサブネット用ルートテーブルのルート情報を確認
まずは現在のルート情報を確認してみます。

    aws ec2 describe-route-tables \
      --route-table-ids $HTTPS_DEMO_RTB_PUB \
      --query "RouteTables[*].Routes" \
      --output table

[参考：awscliコマンドリファレンス（describe-route-tables)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-route-tables.html)

現在はまだローカルの情報しか登録されていないため、下記のような内容が出力されるはずです。
    
    ---------------------------------------------------------------------
    |                        DescribeRouteTables                        |
    +-----------------------+------------+--------------------+---------+
    | DestinationCidrBlock  | GatewayId  |      Origin        |  State  |
    +-----------------------+------------+--------------------+---------+
    |  172.31.0.0/21        |  local     |  CreateRouteTable  |  active |
    +-----------------------+------------+--------------------+---------+

ここに、IGWに対するデフォルトルートを追加します。

#### パブリックサブネットへのルート追加
**基本の構文**

    aws ec2 create-route --route-table-id <RouteTableID> \
      --destination-cidr-block <CIDR> \
      --gateway-id <IGWID>

**実行したコマンド**
パブリックサブネット用ルートテーブルを指定し、IGWに対するデフォルトルートを追加します。

    aws ec2 create-route --route-table-id $HTTPS_DEMO_RTB_PUB \
      --destination-cidr-block 0.0.0.0/0 \
      --gateway-id $IGW_ID

再度ルートテーブルのルート情報を確認してみます。

    aws ec2 describe-route-tables \
      --route-table-ids $HTTPS_DEMO_RTB_PUB \
      --query "RouteTables[*].Routes" \
      --output table

今度はIGWあてのデフォルトルートが追加されています。

    ---------------------------------------------------------------------------------
    |                              DescribeRouteTables                              |
    +----------------------+-------------------------+--------------------+---------+
    | DestinationCidrBlock |        GatewayId        |      Origin        |  State  |
    +----------------------+-------------------------+--------------------+---------+
    |  172.31.0.0/21       |  local                  |  CreateRouteTable  |  active |
    |  0.0.0.0/0           |  igw-*****************  |  CreateRoute       |  active |
    +----------------------+-------------------------+--------------------+---------+

#### プライベートサブネットへのルート追加
プライベートサブネットサブネット用のルートテーブルには、「0.0.0.0/0(デフォルトルート）」でNatGatewayを指定します。

##### プライベートサブネット用ルートテーブルのルート情報を確認
まずは現在のルート情報を確認してみます。

    aws ec2 describe-route-tables \
      --route-table-ids $HTTPS_DEMO_RTB_PRV \
      --query "RouteTables[*].Routes" \
      --output table

[参考：awscliコマンドリファレンス（describe-route-tables)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-route-tables.html)

現在はまだローカルの情報しか登録されていないため、下記のような内容が出力されるはずです。
    
    ---------------------------------------------------------------------
    |                        DescribeRouteTables                        |
    +-----------------------+------------+--------------------+---------+
    | DestinationCidrBlock  | GatewayId  |      Origin        |  State  |
    +-----------------------+------------+--------------------+---------+
    |  172.31.0.0/21        |  local     |  CreateRouteTable  |  active |
    +-----------------------+------------+--------------------+---------+

ここに、NatGatewayに対するデフォルトルートを追加します。

#### プライベートサブネットへのルート追加
**実行したコマンド**

    aws ec2 create-route \
      --route-table-id $HTTPS_DEMO_RTB_PRV \
      --destination-cidr-block 0.0.0.0/0 \
      --nat-gateway-id $NGW_ID

再度ルートテーブルのルート情報を確認してみます。

    aws ec2 describe-route-tables \
      --route-table-ids $HTTPS_DEMO_RTB_PRV \
      --query "RouteTables[*].Routes" \
      --output table

今度はNatGatewayへのデフォルトルートが追加されています。

    ----------------------------------------------------------------------------------------------
    |                                     DescribeRouteTables                                    |
    +-----------------------+------------+-------------------------+-------------------+---------+
    | DestinationCidrBlock  | GatewayId  |      NatGatewayId       |      Origin       |  State  |
    +-----------------------+------------+-------------------------+-------------------+---------+
    |  172.31.0.0/21        |  local     |                         |  CreateRouteTable |  active |
    |  0.0.0.0/0            |            |  nat-*****************  |  CreateRoute      |  active |
    +-----------------------+------------+-------------------------+-------------------+--------

今回ご紹介する手順は以上となります。
次回は、awscliを使用したEC2の作成手順をご紹介します。