AWSのネットワーク設計をサボらないでちゃんとやる

# 新規事業の立ち上げにAWSを選択する

こういう状況はままあるでしょう。最安というわけではないけれど、将来どんな開発が必要になるか全く想像できない新規事業立ち上げフェーズにおいて、多種多様なPaaSを提供してくれるAWSはとても魅力的。

さて、いざ、EC2インスタンスを立ち上げてアプリケーションをデプロイするわけだが、みなさん、ちゃんとネットワーク設計していますか？まさかデフォルトVPCでサービス運営なんてしてないですよね？

というわけでネットワーク設計をして、VPCを設定していくわけだが、何を作ればよいか決まっている事業フェーズならともかく、新規事業立ち上げフェーズでは「将来どんな機能が必要になるかわからない」という前提でネットワーク設計をしておかなければいけない。そこで、「例えばこんな設計はどうでしょう」という提案をしてみる。


# IPレンジ設計

まずはVPCとサブネットを使ってIPレンジを切る。

## VPC

VPCは最上段のプライベートネットワークになる。例えば、こんな感じに設計する。

|環境|IP|
|---:|:--:|
|Prod|10.0.0.0/16|
|Stg|10.1.0.0/16|
|Dev|10.2.0.0/16|

環境ごとに個別のネットワークにすべきなので、3環境用意するなら3つVPCを作ろう。
こうすると、2オクテット目が環境ごとに0、1、2となって分かりやすい。

## サブネット

VPCの中に作るのがサブネットで、機能毎にサブネットを作るのが理想的。
事業拡大に伴って提供する機能/サービスも増えていくので、サブネット自体の数が増えていく前提で設計する必要がある。

VPCは `/16` の範囲で作成したので、まずはこのプライベートネットワークで使える残りの16ビットの使い方を決める。例えばこうだ。

<table>
<thead>
<tr>
<td>クラス</td>
<td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>クラスA = 0</td>
<td colspan="3">機能ID</td>
<td colspan="2">AZ</td>
<td colspan="10">サブネット範囲</td>
</tr>
<tr>
<td>B</td>
<td colspan="2">クラスB = 10</td>
<td colspan="4">機能ID</td>
<td colspan="2">AZ</td>
<td colspan="8">サブネット範囲</td>
</tr>
<tr>
<td>C</td>
<td colspan="2">クラスC = 11</td>
<td colspan="6">機能ID</td>
<td colspan="2">AZ</td>
<td colspan="6">サブネット範囲</td>
</tr>
</tbody>
</table>

機能によって、大量のIPアドレスを必要とする場合もあれば、少数のIPアドレスで十分な場合もあるだろう。なので、3つのクラスに分けた。
クラスAは `/22` のサブネットになるので、1019IP使えるが、機能IDは3ビットしかないので8サブネットしか作れない。
クラスCは `/26` のサブネットになるので、59IPしか使えないが、機能IDが6ビットあるので64サブネット作れる。
クラスBはその中間になる。
このように決めておけば、将来どのようにIPを消費する新規機能が追加されるかわからなかったとしても、だいたいの用途には対応できるだろう。

また、AZ指定用のビットを設けている。例えば東京リージョンであれば、AZは1aと1cの2つがある(2016/01現在)ので、AZ指定用ビットはそれぞれ `00` と `01` と決める。

例えばとあるAZ分散したい機能をID=0とし、クラスCでサブネットを作成するとする。上記ルールに従えば、

- 1a: 10.0.192.0/26
- 1c: 10.0.192.64/26

の2つのサブネットとなる。

AZ指定用ビットがサブネット範囲の直前にあるのがポイントで、AZをまたいだ「この機能全体」を示すIPブロックが「10.0.192.0/24」と書ける。これはオイシイ。


# 機能の抽出

IPレンジ設計の次は機能を抽出する。機能の抽出ってのは即ち「どんなサブネットを作るか決める」ってこと。

例えば一般的なELB-App-RDSの3層構成を作るなら、こんな感じ。

|クラス|機能ID|AZ|IPブロック|Public/Private|機能概要|
|:--:|---:|:---|:---|:---|:---|
|C|0|1a|10.0.192.0/26|Public|踏み台・NATなどなど|
|C|1|1a|10.0.193.0/26|Private|App|
|C|1|1c|10.0.193.64/26|Private|App|
|C|2|1a|10.0.194.0/26|Private|RDS|
|C|2|1c|10.0.194.64/26|Private|RDS|
|B|0|1a|10.0.128.0/24|Public|ELB|
|B|0|1c|10.0.129.0/24|Public|ELB|

PublicかPrivateか意識すること。Privateなサブネットは以下のように運用することで、強固なネットワークになる。

- 配下のEC2インスタンスにはパブリックIPアドレスを付与しない
- NATインスタンスを用意しておく（[マウスポチポチでNAT立てられるようになったよ！](https://aws.amazon.com/jp/blogs/aws/new-managed-nat-network-address-translation-gateway-for-aws/)）
- Privateなサブネットはルートテーブルをいじり、内→外アクセスはNAT経由にする


# さいごに

こんな感じで、将来の拡張性を確保しつつ、強固なネットワークを構築できる。
さらにこれにセキュリティグループの運用を並行運用して、さらに強固な環境を構築していきたい。


# 2016-01-21 追記

はてブコメントをいくつかもらっていたので回答できそうなもの回答していきます。

> Qiitaでcolspan

HTML直書きしてますｗ

> サブネットでかすぎね？

サービス次第ですねー。ここで示した例ではでかすぎるケースも確かにありそうです。
その場合は機能IDに使うビット数を増やすなどして調整すれば良いと思います。
もしくは、「クラスA」と名付けたサイズのものは無しにして、2クラスにするなどもありですね。

> SecurityGroupで十分なのでは

おっしゃるとおりで、「SecurityGroupを細かく運用すること」ではできないけど「サブネットを細かく分けること」では実現できることというような明確な理由はほとんどないです。僕が見つけているのは、NAT運用ぐらいですかね。

ただ、相手はセキュリティであるということも重視したいと考えています。

SecurityGroupを正しく設定できていれば十分なセキュリティを担保できるかもしれませんが、人間なので設定をミスる可能性もあります。もしSecurityGroupの設定をミスったとしても、もしかしたらサブネット運用と併用していたら、インシデントを防げる **かも** しれません。

で、その僅かな可能性を拾いに行くかどうかは、結局のところサービス次第なので、一般的な「発生する頻度 × 発生した場合の損失」とかでリスクを見積もって決めれば良いと思います。その結果「SecurityGroupの運用だけで十分」という判断になるサービスもあるでしょう。

今回僕は、個人情報を扱うサービスの構築に携わったので、二重であってもこのサブネット構成とSecurityGroupの併用を選択しました。