AWSのネットワーク設計でつまずきやすいのがVPCとサブネットの構成だ。「とりあえず動く」状態を作るだけならデフォルトVPCをそのまま使えばいいが、実務で使えるセキュアな構成を自分で設計できるかどうかは別の話だ。
私がこのブログをAstro + S3 + CloudFrontで構築したときはサーバーレス構成だったので直接VPCは登場しないが、アプリケーションサーバーやRDSを使う業務システムでは必ずVPC設計が必要になる。実務で複数のシステムを設計してきた経験から、「なぜこの構成にするか」の理由まで含めて整理する。
VPCとは何か——AWSの仮想ネットワーク
VPC(Virtual Private Cloud)は、AWSクラウド内に作る論理的に隔離されたネットワーク空間だ。IPアドレス範囲(CIDRブロック)を自分で決め、そこにサブネット・ルートテーブル・ゲートウェイを組み合わせて構成する。
# VPCの作成(CIDRは10.0.0.0/16を指定)
aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=my-app-vpc}]'
CIDRブロックはあとから変更できないため、初期設計が重要だ。将来のサブネット分割・マルチアカウント接続(VPCピアリング)を見越して、/16程度の広めのレンジを取っておくのが安全だ。
パブリックサブネットとプライベートサブネットを分ける理由
VPC設計の核心はインターネットに直接さらすリソースとそうでないリソースを物理的に分けることだ。
パブリックサブネット
インターネットゲートウェイ(IGW)へのルートが設定されており、パブリックIPを持つインスタンスが直接インターネットと通信できる。
配置するもの:
- ALB(Application Load Balancer)
- NAT Gateway
- Bastion Host(踏み台サーバー)
アプリケーションサーバー自体はここに置かない。外部からの通信はALBが受け、後段のプライベートサブネットへ転送するのが基本パターンだ。
プライベートサブネット
インターネットゲートウェイへの直接ルートがない。外部へのアウトバウンド通信はNAT Gatewayを経由させる。
配置するもの:
- EC2アプリケーションサーバー
- RDS(データベース)
- ECS / Lambda(VPC内の場合)
データベースをプライベートサブネットに置くことで、仮にアプリサーバーが侵害されたとしてもDB直接アクセスのリスクを大幅に下げられる。
# パブリックサブネットの作成(AZ: ap-northeast-1a)
aws ec2 create-subnet \
--vpc-id vpc-xxxxxxxxxx \
--cidr-block 10.0.1.0/24 \
--availability-zone ap-northeast-1a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=public-subnet-1a}]'
# プライベートサブネットの作成
aws ec2 create-subnet \
--vpc-id vpc-xxxxxxxxxx \
--cidr-block 10.0.11.0/24 \
--availability-zone ap-northeast-1a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=private-subnet-1a}]'
典型的なサブネット構成パターン
本番環境では複数AZに同じ構成を並べるのが鉄則だ。
VPC: 10.0.0.0/16
├── パブリックサブネット (AZ-1a): 10.0.1.0/24 → ALB, NAT GW
├── パブリックサブネット (AZ-1c): 10.0.2.0/24 → ALB, NAT GW
├── プライベートサブネット (AZ-1a): 10.0.11.0/24 → App Server
├── プライベートサブネット (AZ-1c): 10.0.12.0/24 → App Server
├── DBサブネット (AZ-1a): 10.0.21.0/24 → RDS Primary
└── DBサブネット (AZ-1c): 10.0.22.0/24 → RDS Standby
DBサブネットをアプリ用プライベートサブネットとさらに分けることで、アプリサーバーとDBの間にもセキュリティグループで明示的な許可ルールを設けられる。
セキュリティグループとNACL——2つのファイアウォールの使い分け
VPCには2段階のファイアウォール機能がある。
セキュリティグループ(SG)
インスタンスレベルで動作するステートフルなファイアウォールだ。「このSGからの通信を許可する」という形でSGを参照できるのが強力で、IPアドレスのハードコードを避けられる。
// ALBからApp Serverへの通信を許可するセキュリティグループルール
{
"GroupId": "sg-app-server",
"IpPermissions": [
{
"IpProtocol": "tcp",
"FromPort": 8080,
"ToPort": 8080,
"UserIdGroupPairs": [
{ "GroupId": "sg-alb" }
]
}
]
}
ステートフルなので、インバウンドを許可すれば対応するアウトバウンドは自動的に許可される。実務ではセキュリティグループを中心に設計し、SGだけで通信制御を完結させるケースが多い。
NACL(ネットワークACL)
サブネットレベルで動作するステートレスなファイアウォールだ。ルールはルール番号順に評価され、最初にマッチした時点で処理が決まる。
ステートレスなので、インバウンドを許可してもアウトバウンドを明示的に許可しないと通信が成立しない。設定を間違えると「なぜか繋がらない」という状況になりやすく、デバッグが難しい。
| 比較項目 | セキュリティグループ | NACL |
|---|---|---|
| 動作レベル | インスタンス | サブネット |
| ステート | ステートフル | ステートレス |
| 許可/拒否 | 許可のみ | 許可・拒否両方 |
| 主な用途 | サービス間の通信制御 | サブネット単位のブロック |
NACLは「特定IPからの攻撃をサブネット全体でブロックしたい」ときのような、緊急対応用途で使うケースが多い。
実務でよくある設計ミス
ミス1:全アクセスをパブリックサブネットに集める
コストや構成の複雑さを嫌って、DBもEC2も全部パブリックサブネットに置いてしまうパターンがある。RDSをパブリックサブネットに置くことは原則として避けるべきだ。万が一セキュリティグループの設定ミスがあったとき、DBが直接インターネットにさらされることになる。
ミス2:NAT Gatewayを1つしか置かない
プライベートサブネットのアウトバウンド通信用にNAT Gatewayを1つだけAZ-1aに置き、AZ-1cのサブネットもそれを使う構成はコスト優先の選択として取られることがある。しかし、AZ-1aで障害が起きたときにAZ-1cのサーバーも外部通信不能になる。本番環境では各AZにNAT Gatewayを1つずつ置くのが基本だ。
ミス3:VPCフローログを有効にしていない
不審な通信の調査や、セキュリティグループのルール見直しにはVPCフローログが必須だ。あとから「あのときの通信ログが見たかった」では遅い。
# VPCフローログの有効化
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids vpc-xxxxxxxxxx \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-group-name /aws/vpc/flowlogs
治験システムのVPC設計——「個人情報が入る前提」で考える
医療系スタートアップで治験管理システムを設計したとき、VPCの設計方針を「個人情報と機密データが入る前提」で最初から組んだ。
最初に直面した判断は「DBサーバをどこに置くか」だった。前のシステムはコスト削減のためRDSをパブリックサブネットに置いており、セキュリティグループで絞ってはいたが、監査員に「なぜパブリックサブネットなのか」と指摘された。被験者の個人情報や投薬記録を保存するDBがインターネットから直接到達できるサブネットに存在すること自体がリスクだという話だ。
移行後の構成は、パブリックにALBのみ、プライベートにECS(アプリ)、独立したDBサブネットにRDS、という3層構成にした。この構成にしたことで、「なぜこの設計か」の説明がシンプルになり、監査でも「適切な分離がされている」と評価された。
セキュリティグループのSG参照も実務で効いた。治験施設(サイト)ごとにアクセス元IPが異なるが、IPアドレス直書きでルールを増やすと管理が破綻する。ECSのセキュリティグループを参照する形でRDSのインバウンドルールを書くことで、「アプリサーバからのみDB接続を許可する」という意図がコードで明確になった。
VPCフローログは「入れておいて正解だった」の典型だ。ある月、外部からの異常なアクセス試行がフローログで検出され、即座に対応できた。フローログがなければ事後的に確認する手段がなかった。
まとめ
VPC設計で押さえておくべきポイントをまとめると以下のとおりだ。
- 外向き通信を受けるリソースはパブリック、それ以外はプライベートに分ける
- DBは必ずプライベートサブネット(できれば専用DBサブネット)に置く
- セキュリティグループはSG参照で設計し、IP直書きを避ける
- NACLはシンプルに保ち、詳細な制御はセキュリティグループに任せる
- 本番環境はマルチAZ構成にし、NAT Gatewayも各AZに配置する
- VPCフローログは最初から有効にしておく
ネットワーク設計は一度作ると変更コストが高い。最初から「なぜこの構成にするか」を説明できる設計をしておくことが、長期運用での安心感につながる。