はじめに
AWS / Google Cloud / Azure の3クラウドで同じようなワークロードを動かしていると、コンピュートからインターネットへ Outbound 通信させるネットワーク設計が各クラウドで微妙に違うことに気付く。
Internet Gateway、NAT Gateway、SNAT/DNAT、Public/Private Subnet といった頻出用語と、それらが各クラウドでどう組み合わさるのかを改めて整理してみた。
本記事は AI に質問しながら勉強をしていたら、良い感じにまとまりそうだったのでそのまま記事にしたものです。
各クラウドの Outbound パターン早見表
3クラウドで取り得る Outbound ネットワーク設計を、Inbound 遮断レイヤとセットでまずは早見表で示す。表中で出てくる用語 (Internet Gateway / NAT Gateway / SNAT・DNAT / Public・Private Subnet 等) や、なぜこういうパターン差が生まれるのか、各パターンのトレードオフと選び方については、以降の章で順に解説していく。
| クラウド | パターン | Inbound遮断レイヤ |
|---|---|---|
| AWS(NATなし) | Public Subnet + コンピュートに Public IP 直結 + Security Group でガード | L4 (Security Group) |
| AWS(NATあり) | Private Subnet + NAT Gateway 集約 | L3 で到達不能 + L4 も併用 |
| Google Cloud | Private Subnet + Cloud NAT 集約 | L3 で到達不能 + L4 も併用 |
| Azure(NATなし) | Subnet + Microsoft 管理の暗黙 SNAT (default outbound access) で Outbound | L3 で到達不能 + L4 も併用 |
| Azure(NATあり) | Private Subnet + NAT Gateway 集約 (明示的 egress) | L3 で到達不能 + L4 も併用 |
AWS / Azure はそれぞれ NATあり / NATなし の 2 パターンが取れる。ただし Azure(NATなし)は AWS(NATなし)のように コンピュートに Public IP を直接付ける 方式ではなく、Microsoft 管理の共有プール経由で暗黙 SNAT する形 (内部実装は NAT 集約に近いが、ユーザから NAT デバイスが見えない)。Google Cloud は Cloud NAT 集約パターンが前提。
Internet Gateway と NAT Gateway とは
混乱しやすいが、Internet Gateway と NAT Gateway は代替関係ではなく前後関係にある。
| 項目 | Internet Gateway | NAT Gateway |
|---|---|---|
| 役割 | VPC とインターネット境界の「ドア」 | private IP → public IP の SNAT デバイス + 一方通行ドア |
| 方向 | Inbound + Outbound 両対応 | Outbound のみ(応答 Inbound だけ stateful に通す) |
| Public IP の保有 | Internet Gateway 自身は持たない | 自分で Public IP を持つ(SNAT 変換先として必須) |
| 利用条件 | 通信成立には Public IP が必要 (戻り経路の確保のため; Internet Gateway 自体は NAT せず単にルーティングする) | 利用者は private IP のままで OK |
| 課金 | 無料 | 時間課金 + データ処理課金 (~$32/月) |
NAT Gateway の Outbound も最終的には Internet Gateway を通って外に出る。「NAT Gateway = Internet Gateway + 翻訳機 + Inbound 遮断」と捉えるのが正しい。
Google Cloud / Azure には Internet Gateway に相当する明示的な Terraform リソースが存在しない。ただし機能としては常に存在しており、Google Cloud では VPC ルートのネクストホップ default-internet-gateway (作成不要・常に存在する特殊ホップ)、Azure では system route + Internet が同じ役割を担う。Cloud NAT / Azure NAT Gateway は Internet Gateway に相当するドアと一体化したアーキテクチャに見える。
SNAT と DNAT とは
NAT (Network Address Translation) はパケットのアドレスを書き換える仕組み。書き換える対象によって2種類に分かれる。
| 種類 | 書き換える対象 | 用途 | 代表的な実装 |
|---|---|---|---|
| SNAT (Source NAT) | パケットの送信元 IP/port | private IP を持つコンピュートが外部に出るとき、送信元を Public IP に翻訳する | NAT Gateway / Cloud NAT (※ Cloud NAT はデバイスではなく分散型 SNAT 機能) |
| DNAT (Destination NAT) | パケットの宛先 IP/port | 外部からの Inbound を内部リソースに振り分ける | Application Load Balancer / Application Gateway / Cloud Load Balancing 等 |
NAT Gateway は Outbound 専用なので SNAT のみ を行うデバイス。DNAT 機能を持たないため、外部からの新規 Inbound は内部に転送されない。
NAT Gateway における SNAT の動作
コンピュート 10.0.2.5 から 52.x.x.x:443 へ HTTPS 接続した場合のパケット書き換え:
[Outbound時]
コンピュート → NAT Gateway → インターネット
source = 10.0.2.5:50000 → SNAT → <NAT Public IP>:60000
dest = 52.x.x.x:443 → そのまま
[応答 Inbound時]
インターネット → NAT Gateway → コンピュート
source = 52.x.x.x:443 → そのまま
dest = <NAT Public IP>:60000 → state tableで逆引き → 10.0.2.5:50000
NAT Gateway は SNAT 時のマッピング (10.0.2.5:50000 ↔ <NAT Public IP>:60000) を state table に記録し、その応答に該当するパケットだけを内部に戻す。新規の Inbound 接続は state table にマッチしないため破棄される。これが「Outbound 専用、応答のみ Inbound」という挙動の実体。
stateful とは
state table で双方向のフローを追跡する挙動を一般に "stateful" と呼ぶ。NAT Gateway / Cloud NAT に加え、AWS Security Group / Azure NSG / Google Cloud VPC Firewall Rule も stateful な実装になっており、Outbound に対する応答 Inbound は 明示的な許可ルール無しで自動的に通る。
| 概念 | 挙動 |
|---|---|
| stateless (例: AWS Network ACL) | パケット単位で評価。Outbound を許可しても、その応答 Inbound は 別途 Inbound ルールで許可しないと通らない |
| stateful (例: SG / NSG / NAT Gateway) | フロー (5-tuple = src IP / src port / dst IP / dst port / protocol の組) 単位で state table に記録。Outbound を許可すれば、その応答 Inbound は自動的に通る |
「NAT Gateway は Outbound 専用」と言うときの「専用」が stateful な response 判定込みで成立している ことに注意。仮に stateless だったら応答も別途許可する必要があり、設定が煩雑になる。
Public Subnet と Private Subnet とは
VPC / VNet 内のサブネットは「インターネットへの直接ルートを持つか」で Public Subnet / Private Subnet と慣用的に呼び分ける。物理的なリソース種別ではなく、ルートテーブルの設定による区別である点に注意。
| 種別 | ルートテーブルの典型 | 用途 |
|---|---|---|
| Public Subnet |
0.0.0.0/0 → Internet Gateway などインターネット境界へ直接ルート |
Public IP を持つコンピュート、NAT Gateway、Public Load Balancer など「外への出口を持つ」リソースを置く (NAT Gateway は自身が外部と直接通信するわけではなく中継点だが、外に出る経路を持つという意味で同分類) |
| Private Subnet |
0.0.0.0/0 → NAT Gateway または default route なし |
private IP のみのコンピュートを置く。NAT 経由で Outbound するか、完全に外部隔離する |
NAT 集約パターン (AWS(NATあり)) では、同一 VPC 内に Public Subnet (NAT Gateway を置く) と Private Subnet (コンピュートを置く) が共存する。これにより「コンピュートは Private Subnet にいる → ルートで NAT Gateway へ → NAT Gateway は Public Subnet にいるので Internet Gateway 経由で外へ」という二段構造が成立する。
なぜ分けるのか
両者を分ける本質的な目的は 「ルーティング層 (L3) での構造的な防御を作ること」。SG/NSG (L4) は設定の世界なので人為的なミスで穴が開きうるが、Private Subnet に置いたリソースは そもそも default route が外に向いていない ため、L4 ルールを誤っても外部到達経路が物理的に存在しない。
主な理由:
| 観点 | 分けることで得られるもの |
|---|---|
| 多層防御 (Defense in Depth) | SG/NSG だけに頼らず、ルートテーブル (L3) のレイヤでも外部到達不可を担保 |
| 設定ミスのブラスト半径限定 | Public Subnet で SG ingress を誤って開けても、Private Subnet のリソースは構造的に影響を受けない |
| Outbound IP の固定化 | Private Subnet → NAT Gateway → 固定 Public IP の構造で、外向き通信元を1つに集約できる (allowlist 用途) |
| コンプライアンス要件 | PCI DSS / HIPAA などで「データストアは外部から到達不能なネットワークに置く」要求がある場合、subnet 分離が明示的な根拠になる |
| 役割の自己ドキュメント化 | subnet 名や Terraform リソース名から「ここは外向け / ここは内側専用」が読み取れ、レビュー時の認知コストが下がる |
逆に 「分けない (= 全部 Public Subnet)」が選ばれる場面 は、コンピュート 1 つ + 検証用途 + コスト最小化 のような単純構成 (例: AWS(NATなし))。リソース数が増えるほど分離した方が運用しやすくなるため、本番ガバナンス向きでは分離が前提になる。
クラウドごとの呼び分けの強さ
| クラウド | Public/Private 概念 | 実態の決まり方 |
|---|---|---|
| AWS | 明確に意識される |
aws_subnet リソース自体に属性は無く、ルートテーブルの紐付け (aws_route_table_association) で決まる |
| Google Cloud | 明示的な名称は無い | Cloud NAT の attach 状況や VPC Firewallで実質的に決まる。Subnet 単位で external IP を持てるため概念自体は存在するが、サブネット名で慣用的に区別する程度 |
| Azure | 明示的な名称は無い | UDR (User Defined Route; ユーザー定義のカスタムルート) + NAT Gateway + NSG の組み合わせで実態が決まる。サブネット名で慣用的に区別する程度 |
「Public Subnet / Private Subnet」は AWS 文脈で生まれた用語で、AWS が最も意識的に使い分ける。Google Cloud / Azure では同じ役割を「Cloud NAT を attach した subnet」「NAT Gateway を attach した subnet」のように 属性ベースの記述で表すことが多い。
3クラウドの Outbound アーキテクチャを比較する
AWS(NATなし): Public IP直結 + SGガード
最もシンプルで低コスト。Fargate タスクや EC2 の ENI (Elastic Network Interface; AWS VPC 内の仮想 NIC で、Public IP / private IP / SG をまとめて持つ単位) に Public IP を直接付与し、Security Group の Ingress 空 (= 新規 Inbound のみ deny; SG は stateful なので Outbound に対する応答 Inbound は通る) で Inbound 遮断する。
AWS(NATあり): Private Subnet + NAT Gateway 集約
コンピュートを Private Subnet に置き、NAT Gateway (Public Subnet) 経由で Outbound する。Outbound IP が固定でき、コンピュートに Public IP が無いので構造的に外部到達不可になる。本番ガバナンスでは一般的なパターン。
Google Cloud: Cloud NAT 集約
Cloud Router + Cloud NAT で Outbound を集約。マネージドコンピュート (Cloud Run, Cloud Functions, GKE Autopilot 等) は Public IP を直接持てないため、本パターンが前提となる。なお Cloud NAT は分散型 NAT 実装で、AWS / Azure の中間ホップ型 NAT (パケットが NAT デバイスを物理的に通過する方式) とは違い、パケットは Cloud NAT / Cloud Router の物理ホップを通らず VPC ネットワーク自体が SNAT を行う (Cloud Router は BGP の制御プレーンのみを担い、データプレーンには関与しない; 下図は概念上の経路)。
Azure(NATなし): default outbound access (Microsoft管理の暗黙SNAT) で Outbound
Azure の subnet には defaultOutboundAccess というフラグがあり、未指定 / true の状態では Microsoft 管理の共有プール経由で暗黙 SNAT されて Outbound できる。Terraform azurerm provider もこのフィールドを default = true で扱うため、明示的に egress を組まなくても ACI / ACA から外部疎通は成立する。AWS(NATなし)と同じく、検証用途やコスト最小化を目的に選択するのは合理的。
Azure(NATあり): NAT Gateway 集約 (明示的 egress)
NAT Gateway を VNet 内のサブネットに attach し、private IP のままのコンピュートから Outbound する。Outbound IP が固定 (NAT Gateway 用 Public IP) でき、allowlist 要件も満たせる。本番運用ではこちらが推奨。
なお NAT Gateway の代わりに Standard Load Balancer のアウトバウンド規則 (Outbound rules) で同じ目的を達成する構成も実務でよく使われる。LB の frontend Public IP を SNAT 変換先として再利用する形で、すでに LB を Inbound 用に使っているなら追加コストを抑えられる。
なぜパターンが分かれるのか
クラウド側の抽象化の哲学の差が根本原因。
| クラウド | コンピュートに Public IP を直接付けられるか | 取り得るパターン |
|---|---|---|
| AWS | ✓ Fargate タスク・EC2 ENI に直接付与可能 | NATあり (NAT Gateway) / NATなし (Public IP直結) どちらも可 |
| Google Cloud | △ GCE VM には付与可能だが、Cloud Run / Cloud Functions 等のマネージド系は不可 | Cloud NAT 集約が前提 |
| Azure | ✗ Container Instances / Container Apps に Public IP を直接付与する API がない | NATあり (NAT Gateway / Standard LB Outbound rules) / NATなし (default outbound access による暗黙SNAT) どちらも可 |
マネージドコンピュート抽象では Public IP 直結を許さない、というのが Google Cloud / Azure の共通方針。両クラウドは「コンピュートのネットワーク詳細は抽象化したい、Outbound は VPC / VNet レベルで明示的に決めろ」という設計思想を持つ。
AWS は ENI に Public IP を直接付与する抽象を提供しているため、コンピュート自身が Public IP を持つ NATなし パターンが取れる。Azure も NATなし 相当が取れるが、こちらは コンピュートが Public IP を持つのではなく、Microsoft 管理の共有プール経由で暗黙 SNAT される ため、AWS のように outbound IP を識別/固定することはできない。
Inbound 遮断のレイヤの違い
「Inbound 完全遮断、Outbound HTTPS のみ許可」を達成するレイヤは、コンピュートに Public IP が直結しているか否か で分かれる。NATあり/NATなし の軸ではなく、Public IP 直結の有無 が分かれ目。
| パターン | コンピュートに Public IP | Inbound 遮断レイヤ |
|---|---|---|
| AWS(NATなし) | ✓ 直接付与 (Fargate / EC2 ENI) | L4 (Security Group) |
| AWS(NATあり) | ✗ private IP のみ | L3 で到達不能 + L4 も併用 |
| Google Cloud | ✗ private IP のみ | L3 で到達不能 + L4 も併用 |
| Azure(NATなし) | ✗ private IP のみ (※ outbound は Microsoft 共有プール経由) | L3 で到達不能 + L4 も併用 |
| Azure(NATあり) | ✗ private IP のみ | L3 で到達不能 + L4 も併用 |
- Public IP 直結 (AWS(NATなし)のみ): L4 (Security Group) で遮断。Public IP は付いているので L3 ではパケットが ENI に届くが、SG が空 Ingress = 新規 Inbound のみ deny で drop する (Outbound 応答は stateful なので通る)。
- Public IP なし (それ以外の全パターン): L3 でそもそも到達経路が存在しない。Public IP がコンピュートに存在しないので、外部から宛先 IP として指せない。Azure(NATなし)も「outbound は Microsoft 共有プール経由」 で出ているだけで、コンピュート側に Public IP は無いためここに含まれる。
NATなし と NATあり のトレードオフ
NATなし は AWS と Azure で内部実装が違うので 3 列に分けて並べる:
| 観点 | AWS(NATなし) (Public IP 直結 + SG) |
Azure(NATなし) (default outbound 暗黙SNAT) |
NATあり (NAT集約; AWS / Google Cloud / Azure 共通) |
|---|---|---|---|
| Inbound 防御 | L4 (SG) 1 層 | L3 + L4 の 2 層 (Public IP無し) | L3 + L4 の 2 層 (Public IP無し) |
| Outbound IP | コンピュート毎にバラバラ (タスクの Public IP) | Microsoft 共有プールから払い出し (変動可能性あり) | 集約 NAT の固定 IP (allowlist 可) |
| コスト | NAT 代不要 (ただし Public IPv4 自体の利用料 ~$3.6/月; 2024-02 から課金開始) | NAT 代不要 + Public IP も不要 (= 最安) | NAT Gateway ~$32/月 + データ処理料金 |
| 設定ミスのブラスト半径 | SG Ingress 誤追加で即露出 | Public IP が無いので根本的に露出しない | Public IP が無いので根本的に露出しない |
| Outbound IP の allowlist | できない | できない | できる |
| SNAT ポート枯渇 | 起こりにくい (各コンピュートが自分の 65535 ポートを独占できる) | Microsoft プールが管理、ユーザは制御不可 | 1 Public IP のポートを複数コンピュートで分け合うため枯渇しやすい (※ クラウドにより上限・スケール挙動が異なる) |
| 設定の複雑さ | 単純 (Subnet 1 種類) | 単純 (Subnet 1 種類、default_outbound_access_enabled = true のみ) |
複雑 (Public / Private Subnet 2 種類 + ルートテーブル分割 + NAT リソース) |
AWS(NATなし)は SG に依存して低コスト、Azure(NATなし)は Microsoft プール任せで最安だが Outbound IP の制御不可、NATあり は構造で守って堅牢でコストはかかる、というトレードオフ。
なお NATあり 時の SNAT ポートの挙動はクラウドごとに異なる:
- AWS NAT Gateway: 約 55K〜64K / Public IP / 宛先ごと
- Cloud NAT: ポートを自動スケール (デフォルト割当 + 必要に応じて拡張)
- Azure NAT Gateway: 64K × attach した Public IP 数 (1024〜64512 を構成可能)
どのパターンを選ぶか
| ユースケース | 推奨パターン |
|---|---|
| 検証用途 / Inbound 不要の単機能ワーカー / コスト最小化 | AWS なら NATなし (Public IP 直結)、Azure なら NATなし (default outbound)、Google Cloud は NATなし 相当が無いので NATあり (Cloud NAT) |
| 本番運用 / Outbound IP allowlist 要件 / コンプライアンス監査 / 設定ミス耐性重視 | NATあり (AWS NAT Gateway / Google Cloud Cloud NAT / Azure NAT Gateway) |
| 高並列ワークロード (同一宛先への大量並列接続) | AWS なら NATなし で SNAT ポート枯渇回避、Azure / Google Cloud は NATあり で複数 Public IP を attach して水平分散 |
NAT Gateway の Public IP は危なくないのか
「Inbound 入れないのに Public IP 付けるの?」という違和感が出るが、NAT Gateway の Public IP は:
- Outbound 専用 (SNAT 変換先として必要)
- Inbound セッションを生成しない仕様(state table に無いパケットは破棄される)
- 外部から
curl http://<NAT IP>しても応答すらしない
「Public IP = Inbound 可能」という直感はアタッチ先のリソースで決まる仕様であって、Public IP 自体は単なるアドレス資源。NAT Gateway は Outbound 専用なので安全。
これは AWS NAT Gateway, Google Cloud NAT, Azure NAT Gateway すべて共通の設計。
(参考) Inbound 経路の整理
本文は Outbound 中心の議論だが、対称的に Inbound を受け入れたい場合のパターンを参考までに整理する。
Inbound パターンの2択
| パターン | 構造 | 例 |
|---|---|---|
| Compute 直結 | コンピュートに Public IP を付け、SG/NSG で必要なポートを開けて Inbound を受ける | Public IP 付きの EC2 で SG ingress 80/443 開放、Azure VM with Public IP 等 |
| Load Balancer 経由 | Load Balancer が Public IP を持ち、backend のコンピュートは private IP のまま | Application Load Balancer / Application Gateway / Cloud Load Balancing |
Compute 直結:
Load Balancer 経由:
Outbound 側で見た「コンピュートに Public IP 直結 vs Public IP なし」 の軸と対称的な構造。Compute 直結は手軽だが各 compute が外部公開される、Load Balancer 経由は backend を private に保てるが LB の維持コストがかかる、というトレードオフも対称的。
Load Balancer は DNAT デバイス
NAT Gateway が Outbound 用の SNAT デバイスだったのに対し、Load Balancer は Inbound 用の DNAT デバイスとして動く。
[Inbound 時のパケット書き換え]
インターネット → Load Balancer → backend Compute
source = <Client IP>:50000 → そのまま (L4 LB) / SNAT され元 IP は X-Forwarded-For ヘッダ (L7 LB が元 client IP を保持するための HTTP ヘッダ) に記録 (L7 LB)
dest = <LB Public IP>:443 → DNAT → 10.0.2.5:80 (backend private IP)
LB が宛先を backend の private IP に書き換えることで、backend は Public IP を持たずに外部からのリクエストを受けられる。SNAT と DNAT セクションで触れた DNAT がここで実体化する。
| 用途 | デバイス | 行う変換 |
|---|---|---|
| Outbound | NAT Gateway / Cloud NAT | SNAT (送信元書き換え) |
| Inbound | Load Balancer / Application Gateway | DNAT (宛先書き換え) |
3クラウドの Inbound デバイス比較
| 層 | AWS | Google Cloud | Azure |
|---|---|---|---|
| L4 (TCP/UDP) | Network Load Balancer | TCP/UDP Load Balancing | Azure Load Balancer |
| L7 (HTTP/HTTPS) | Application Load Balancer / API Gateway | HTTP(S) Load Balancing | Application Gateway |
| エッジ (CDN/WAF) | CloudFront | Cloud CDN / Cloud Armor | Azure Front Door |
Outbound 側ではマネージドコンピュートが Public IP 直接保有不可で NAT 集約に強制される構造だったが、Inbound 側もマネージドコンピュート (Cloud Run / Container Apps 等) は endpoint が自動付与されるか LB 経由が前提 となっており、コンピュートに直接 Public IP を付ける選択肢はそもそも存在しない。「マネージド = Public IP の直接保有不可」という制約は Outbound と Inbound で共通。
ALB と NLB の違い
AWS の Inbound LB には ALB (Application Load Balancer; L7) と NLB (Network Load Balancer; L4) があり、動作するレイヤと判定軸が本質的に違う。同じ L4 / L7 の区分は Google Cloud (HTTP(S) Load Balancing / TCP/UDP Load Balancing) や Azure (Application Gateway / Azure Load Balancer) でも踏襲されている。
前提として、ALB / NLB はどちらも 複数 backend へのリクエスト/接続分散 (= 負荷分散) を本来の主機能として持つデバイス。違いは「どのレイヤで判定して、どの判定軸で振り分けるか」(= Routing 部分) にある。
| 項目 | ALB (L7) | NLB (L4) |
|---|---|---|
| 主機能 | 複数 target への HTTP/HTTPS リクエスト分散 | 複数 target への TCP/UDP 接続分散 |
| 分散アルゴリズム | Round Robin (default) / Least Outstanding Requests / 重み付けターゲット | Flow Hash (default; 5-tuple ベース) |
| 動作層 | L7 (HTTP/HTTPS) | L4 (TCP/UDP) |
| ルーティング判定 | パス / ホスト名 / HTTP ヘッダ | port |
| TLS 終端 | LB で実施 (中身を読める) | 通常 backend で実施 (passthrough) |
| クライアント IP の扱い | SNAT され、元 IP は X-Forwarded-For ヘッダで保持 |
preserve (SNAT しない、backend から直接見える) |
| 静的 IP | 固定 IP をユーザが制御できない (内部的には IP を持つが Auto Scaling 等で変動する; アクセスは DNS 名経由) | 各 AZ ごとに 1 つ持てる |
| WebSocket / gRPC | サポート (HTTP/2 対応) | TCP として透過的に通る |
| 用途 | Web アプリ、HTTP API、パスベース振り分け、WAF 統合 | TCP/UDP プロトコル全般、超低遅延、IP allowlist 要件 |
「HTTP のパスやホスト名で振り分けたい → ALB (L7)」「生の TCP/UDP のまま振り分けたい / クライアント IP を backend にそのまま見せたい → NLB (L4)」と覚えておくと使い分けに困らない。
おわりに
3クラウドの Outbound ネットワーク設計を、Internet Gateway / NAT Gateway / SNAT・DNAT / Public・Private Subnet といった基礎概念から、各クラウドのアーキテクチャパターンとトレードオフまで整理してみた。
「AWS と Azure はそれぞれ NAT 無しが取れるが、その仕組みが違うのはなぜか」「Google Cloud だけ Cloud NAT 集約が事実上必須なのはなぜか」 といった違いの裏にあるクラウドベンダーの設計哲学が見えてくると、各クラウドでのネットワーク設計判断がより自然に行えるようになるはず。クラウドネットワーク設計を整理する一助になれば嬉しい。