外部API連携型Webアプリケーション向けAWSインフラ設計:Public Subnetレス構成の実現
この構成図の対象と目的
対象システム
本構成は、以下の要件を持つ一般的なWebアプリケーションを対象としています。
想定する用途
- 外部APIを呼び出すWebアプリケーション(決済、地図、AI/ML等)
- インターネットからのHTTPS通信を受け付けるサービス
- OSパッチ取得、Dockerイメージpullが必要なコンテナ基盤
- データベースは閉域内に配置
適用できるケース
- インターネット向け通信(外向き)のみが必要
- プライベート接続(VPC Peering、Transit Gateway、Direct Connect等)が不要
適用できないケース
- オンプレミスとの接続が必要(Direct Connect、VPN)
- 他VPCとのプライベート接続が必要(Transit Gateway経由の閉域通信)
- VPC Peering経由での内部通信が必要
上記の場合は、Regional NAT Gatewayではなくゾーン別NAT Gatewayが必要です。
設計の目的
構造的なセキュリティ強化
- CloudFront VPC Origin:ALBを完全プライベート化
- Regional NAT Gateway:Public Subnetを完全排除
この2つの技術により、Public Subnetレス構成を実現し、
インターネット露出点をCloudFrontのみに限定することで、
攻撃対象領域(Attack Surface)を構造的に最小化しました。
アーキテクチャ全体像
設計の5つの軸
| 観点 | 方針 |
|---|---|
| セキュリティ | Public Subnetレス、構造的アクセス制御、多層防御 |
| 可用性 | Multi-AZ、Regional NAT Gateway(環境別) |
| コスト | 本番=可用性優先、検証=コスト優先(93%削減) |
| 運用保守性 | IaC徹底、自動化、Parameter Store一元管理 |
| 拡張性 | 疎結合、将来変更を前提とした設計 |
1. VPC・インターネット接続設計
1.1 VPC CIDR設計
選定:10.0.0.0/16
設計判断の根拠
将来的なVPC接続拡張に備えてCIDR設計を行いました。
- VPC Peering、Transit Gateway接続の可能性を考慮
- VPC間でCIDRが重複すると接続不可となるため、他環境と重複しない範囲を確保
- ECSタスクの充分なアドレス範囲(/16で約65,000アドレス)
- Lambda VPC統合の可能性に備える
- VPCエンドポイント(インターフェース型)展開時のENI消費に対応
注意点
現状はインターネット向け通信のみを想定しており、Regional NAT Gatewayを採用しています。将来Transit Gateway経由の閉域通信が必要になった場合は、ゾーン別NAT Gatewayへの切り替えが必要です。
サブネット分割
AZ構成:3AZ(ap-northeast-1a、1c、1d)
各AZごとに以下を配置:
- Private Subnet(Ingress):10.0.x.0/24(ALB配置)
- Private Subnet(Container):10.0.y.0/24(ECS配置)
- Private Subnet(DB):10.0.z.0/24(Aurora配置)
/24で各サブネット約250アドレスを確保し、層ごとに責務を分離しました。将来のサブネット追加に備えて空きCIDRも確保しています。
1.2 インターネット接続の全体像
本構成では、3つのコンポーネントでインターネット接続を実現しています。
【インバウンド】
Internet
↓
CloudFront(VPC Origin)
↓(AWS PrivateLink)
Private Subnet内のALB
【アウトバウンド】
Private Subnet内のECS
↓
Regional NAT Gateway
↓
Internet Gateway
↓
Internet
Internet Gatewayの役割
- CloudFront VPC Origin要件としてVPCにアタッチ
- Regional NAT Gatewayのインターネット出口として使用
1.3 CloudFront VPC Origin:Public Subnetレス構成の核心
従来構成の課題
従来の構成では、ALBをインターネット公開する必要があり、以下の課題がありました。
- ALBがインターネットに直接露出
- CloudFrontをバイパスした直接アクセスのリスク
- CloudFrontのIP範囲変更に追従する運用負荷
VPC Originによる解決
VPC Originの採用により、以下を実現しました。
- ALBへの直接アクセスが構造的に不可能
- Public Subnetが不要
- IP管理が不要(CloudFront Managed Prefix List)
技術的な詳細
VPC側で以下を実装しました。
- Internet Gatewayをアタッチ(VPCがインターネットトラフィックを受信可能であることを示すために必要)
- ALBをPrivate Subnetに配置
- セキュリティグループでCloudFront Managed Prefix Listからのみ許可(com.amazonaws.global.cloudfront.origin-facing)
1.4 CloudFront キャッシュ戦略
パス別のキャッシュポリシー設定
本構成では、コンテンツの性質に応じてキャッシュポリシーを使い分けました。
動的コンテンツ(ALB)
- パス:/ (デフォルト)、/api/、/users/ 等
- キャッシュポリシー:Managed-CachingDisabled
- オリジンリクエストポリシー:Managed-AllViewer
動的コンテンツは常にオリジンから最新を取得する必要があり、ユーザー認証やセッション管理のため、全てのViewer情報(Cookie、Header、Query String)をALBに転送します。
静的コンテンツ(S3)
- パス:/images/、/css/、/js/* 等
- キャッシュポリシー:Managed-CachingOptimized
- オリジンリクエストポリシー:Managed-CORS-S3Origin
画像、CSS、JavaScriptは長期キャッシュを行い、エッジロケーションでの配信によりレイテンシを削減しました。S3へのリクエスト数削減によるコスト最適化も実現しています。
リダイレクト(S3 Website)
- パス:/docs/*、/ (ルートパス)
- キャッシュポリシー:Managed-CachingDisabled
リダイレクトルールの即座反映のため、キャッシュを無効化し、S3 Websiteの柔軟なルーティング機能を活用しています。
キャッシュキーの設計思想
動的コンテンツのキャッシュキーには、URI、Cookie、Headerを含めることで、ユーザーごとに異なるコンテンツを正確に返すようにしました。静的コンテンツはURIのみをキャッシュキーとし、Cookie/Headerを除外することで、キャッシュヒット率を最大化しています。
レスポンスヘッダーポリシー
全レスポンスに以下のセキュリティヘッダーを自動付与しています。
- Strict-Transport-Security(HSTS)
- X-Content-Type-Options
- Referrer-Policy
- Content-Security-Policy
CloudFrontで一元管理することで、ALB側での個別設定を不要としました。
1.5 Regional NAT Gateway:Public Subnetレス構成の完成
AWS公式の設計判断基準
プライベート接続が必要な場合を除くすべてのユースケースでリージョナルNATゲートウェイの使用を検討してください。
リージョナルNATゲートウェイはプライベート接続を提供しないため、プライベートNATの利用ケースではゾーン別可用性モードでNATゲートウェイを使用することを推奨します。
設計判断の明確化
リージョナルNAT Gateway
用途:インターネット向け通信専用
- OSパッチ取得
- 外部API呼び出し
- Dockerイメージpull
- npm/pip等のパッケージ取得
特徴:
- Public Subnetが不要
- サブネット指定が不要
- AWSが自動的に各AZに展開
- ワークロードの存在に基づいて自動スケール
ゾーン別NAT Gateway(従来型)
用途:プライベート接続が必要な場合
- VPC Peering経由の通信
- Transit Gateway経由の通信
- Direct Connect/VPN経由の通信
- 閉域網内の通信
特徴:
- Public Subnetに配置が必要
- AZごとに作成が必要
- 経路制御が厳密に必要な場合
本構成での選択
本構成はインターネット向け通信のみが目的のため、リージョナルNAT Gatewayを採用しました。
技術的な詳細
リージョナルNAT Gatewayは以下の仕組みで動作します。
- VPCレベルのリソースとして、特定のサブネットに配置されない
- AWS側で自動的に各AZに展開
- 全Private Subnetで共通のルートテーブルが使用可能(Private Subnet → 0.0.0.0/0 → nat-xxxx)
- ワークロード(ENI)が存在するAZにのみ展開され、新AZへの展開には時間を要する場合があり、その間は既存AZ経由で通信されます
- Public Subnetが不要で、AWS管理リソースのため設定ミスのリスクが低減
構成図への記載
リージョナルNAT Gatewayは特定のサブネットに描かず、VPC境界付近に「Regional NAT Gateway」として記載します。
1.6 環境別のNAT戦略
本番環境:Regional NAT Gateway
- 可用性最優先
- AZ障害を自動で回避
- 運用負荷ゼロ
- コスト:約$150/月(推定)
検証環境:NATインスタンス
- コスト最優先
- 可用性は二の次(検証環境のダウンタイムは許容)
- コスト:約$10/月(t3.micro)
- 削減効果:93%削減
トレードオフの明確化
| 項目 | Regional NAT GW(本番) | NATインスタンス(検証) |
|---|---|---|
| 可用性 | ◎ 自動Multi-AZ | △ Single-AZ |
| 運用負荷 | ◎ AWS管理 | △ 自己管理(パッチ適用等) |
| コスト | △ $150/月 | ◎ $10/月 |
| Public Subnet | 不要 | 必要 |
2. ネットワーク・セキュリティ設計
2.1 サブネット構成
すべてPrivate Subnet構成(Public Subnetレス)としました。
Private Subnet(Ingress)
- Internal ALB配置
- CloudFront VPC Origin経由でのみアクセス可能
Private Subnet(Container)
- ECS Fargate配置
- パブリックIP無効化
- Regional NAT Gateway経由でインターネットアクセス
Private Subnet(DB)
- Aurora PostgreSQL配置
- 完全閉域(インターネットアクセス不可)
- VPC Endpointのみ許可
設計判断:なぜこの分離か
この分離により、以下を実現しました。
- セキュリティ境界の明確化:各層で異なるセキュリティ要件を適用し、侵害時の影響範囲を局所化
- ルートテーブルの責務分離:Container層はRegional NAT Gateway経由、DB層は完全閉域
- 将来の拡張性:新サービス追加時に適切な層に配置可能、ネットワークACLで層間通信を制御可能
2.2 セキュリティグループ設計:構造で守る
設計原則
以下の原則でセキュリティグループを設計しました。
- サービスごとにセキュリティグループを分離
- CIDR許可は使わず、必ずSG → SG参照
- 通信経路が一方向に読める設計
通信フロー
CloudFront Managed Prefix List
↓(443)
ALB SG
↓(アプリポート)
ECS SG
↓(5432)
Aurora SG
従来構成との比較
従来構成では、ALB SG、ECS SG、RDS SGすべてで0.0.0.0/0やVPC CIDRからの許可を行っており、ALBをバイパスしてECSに直接アクセス可能でした。設計意図が不明で、運用でセキュリティを担保する必要がありました。
改善後は、SG間参照により構造的にバイパスを不可能とし、SGを見れば設計意図が理解可能となりました。設計でセキュリティを担保する形に変更しました。
3. アカウント・認証基盤
3.1 AWS Organizations によるマルチアカウント構成
環境ごとにAWSアカウントを分離(stg/prd等)しました。
設計判断
- セキュリティ境界の明確化(検証環境の事故が本番に波及しない)
- 権限管理の簡素化(環境ごとのIAMポリシー)
- コスト可視化(アカウント単位での費用分離)
3.2 IAM Identity Center による SSO
設計判断
- 運用負荷削減(アカウントごとのIAMユーザー管理不要)
- 監査対応(アクセスログの一元追跡)
- セキュリティ強化(MFA強制、一時的な認証情報のみ)
4. コンピューティング基盤
4.1 ECS Fargate
設計判断
- 運用保守性最優先(ホストOS管理不要)
- セキュリティパッチ自動適用
- スケールの容易さ
Private Subnet配置の徹底
- パブリックIP無効化
- インターネットアクセスはRegional NAT Gateway経由のみ
4.2 ECS オートスケーリング
ターゲット追跡スケーリングを採用しました。
- CPU / メモリ使用率ベース
- スケールアウト:1〜3分(速く)
- スケールイン:5〜15分(慎重に)
5. データベース設計
5.1 Aurora PostgreSQL
採用理由
- ストレージ自動拡張
- 高速なフェイルオーバー
- 運用負荷の低さ
トレードオフ
- アプリ層:Multi-AZ
- DB層:コストを考慮し、Auroraの基本構成(Writer 1台)を採用(※ストレージはAuroraの仕組みにより冗長化)
6. CI/CD パイプライン
6.1 GitHub Actions + ecspresso
デプロイフロー
GitHub Actions
↓ (1) Dockerイメージビルド
ECR
↓ (2) ecspresso deploy
ECS Task定義更新
↓ (3) 新タスク起動
6.2 Parameter Store による情報共有
設計思想:Single Source of Truth
Terraform → Parameter Store → ecspresso / GitHub Actions
管理情報:
- VPC ID、サブネットID
- 最新イメージタグ
- その他設定値
6.3 DBマイグレーション
専用ECSタスクでマイグレーション実行後、アプリケーションデプロイを行います。
7. バッチ処理基盤
EventBridge Scheduler + ECS Task
- 日次バッチ処理(データ集計、レポート作成)
- Lambdaの15分制限を超える処理に対応
8. ストレージ・シークレット管理
8.1 S3 バケット設計
用途別分離
- アクセスログバケット(ALB、CloudFront)
- 静的コンテンツバケット(画像)
- Terraform Stateバケット
8.2 Certificate Manager
- CloudFront用:us-east-1(必須)
- ALB用:ap-northeast-1
8.3 Secrets Manager vs Parameter Store
| 用途 | サービス |
|---|---|
| パスワード/APIキー | Secrets Manager |
| リソースID/設定値 | Parameter Store |
9. 監視・通知基盤
9.1 CloudWatch Logs
原則:取得可能なログは全て取得
- ECS(アプリケーションログ)
- ALB(アクセスログ):S3保存
9.2 障害通知
CloudWatch Alarm → EventBridge → Lambda → SNS
Lambdaで読みやすい日本語メッセージに変換しました。
10. Route 53 とDNS設計
管理するレコード
- CloudFrontのAレコード(Alias)
- CloudFrontのAAAAレコード(IPv6)
- SESのDKIM設定(TXT)
- ACM検証用のCNAMEレコード
管理しないレコード
- ALB(VPC Origin使用のため不要)
11. Infrastructure as Code
11.1 Terraform
- S3バックエンド(バージョニング、暗号化)
11.2 ecspresso
Terraformとの分離により、デプロイの高速化とインフラ変更の分離を実現しました。
まとめ
この設計で最も重視したこと
- セキュリティは運用でなく設計で解決(Public Subnetレス、VPC Origin)
- トレードオフの明確化(環境別のコスト戦略)
- 明確な用途の定義(インターネット向け通信のみ)
設計判断の3つの教訓
- 適用範囲の明確化:インターネット向け通信のみか、プライベート接続が必要か
- 構造的なセキュリティ:運用でなく設計で解決
- トレードオフの可視化:コスト・可用性・運用性のバランス
この設計の強み
| 観点 | 実現内容 |
|---|---|
| セキュリティ | Public Subnetレス、構造的アクセス制御、多層防御 |
| 可用性 | Multi-AZ、Regional NAT Gateway自動拡張 |
| 運用性 | IaC徹底、自動化、Parameter Store一元管理 |
| コスト | 環境別最適化(検証環境93%削減) |
| 明確な用途 | インターネット向け通信専用構成 |
