TGW 越しのセキュリティグループはなぜ CIDR ベースになるのか — SG・NACL・経路を多層で理解する
Transit Gateway でアカウントをまたいで通信させると、セキュリティグループの「SG 参照」が効かず CIDR ベースになる。その理由を前提から解き、NACL のステートレス性、パケットが通る順序、dev と SRE の責任分担まで整理します。
前提: 何の話か
マルチアカウント構成で、サービス間を Transit Gateway (TGW) で繋ぐ。DB 接続のような非 HTTP の通信も含む。CIDR は重複しないように採番している — そんな状況を想定します。
このとき、開発チームがよくつまずくのが「TGW 越しだとセキュリティグループの SG 参照が効かない。CIDR で書くしかない」という挙動です。これは仕様であって、理由を知らないと「なぜか繋がらない」で時間を溶かします。前提から順に解きます。
前提 1: セキュリティグループのソースは 2 通りで書ける
SG のインバウンドルールの「ソース」には、2 種類の書き方があります。
- CIDR:
10.20.0.0/16のような IP 範囲 - SG 参照 (SG-to-SG):
sg-0abc...という別のセキュリティグループ ID
# CIDR ベース
ingress 5432 from 10.20.0.0/16
# SG 参照
ingress 5432 from sg-app ← 「sg-app が付いたリソースからなら許可」
前提 2: SG 参照の「正体」は動的なメンバーシップ解決
from sg-app は名前マッチではありません。AWS が裏で「sg-app が付いている ENI の集合 = その時点の全プライベート IP」を動的に解決して許可しています。
インスタンスがスケールして IP が変わっても、AWS がメンバーシップを追跡して自動で効かせてくれる。つまり SG 参照は「IP の集合」を表す便利な抽象であり、AWS の管理機能に依存しています。ここが効くか効かないかの分かれ目です。
前提 3: メンバーシップ解決が効く「範囲」がある
SG 参照が成立するには、両端が「SG 参照できる関係」にいる必要があります。具体的には次の範囲です。
- 同一 VPC 内 — OK
- VPC ピアリング (同一リージョン) で繋いだ VPC 間 — OK (ピア先の SG を参照できる)
この範囲では、AWS が両 VPC 間で SG のメンバーシップ情報を共有しているので from sg-xxx が機能します。
本題: なぜ TGW 越しはダメなのか
TGW は純粋な L3 ルーターです。ルートテーブルを見て IP パケットを転送するだけ。設計として「スケールするシンプルな転送装置」であることを優先していて、送信元 ENI にどの SG が付いているかというメンバーシップ情報を運びません。
そのため、TGW を通って宛先 VPC に届いたパケットについて、宛先側の SG が知れるのは 送信元の IP アドレスだけです。from sg-app と書いても、sg-app のメンバーが誰なのかを宛先側から解決できない。結果、そのルールはマッチしようがなく、エラーにはならず、ただ通らない。
だから TGW 越しは、送信元を IP (CIDR) で書くしかありません。
# 宛先 (DB) 側の SG
ingress 5432 from 10.20.0.0/16 ← アプリ VPC の CIDR を許可(効く)
ingress 5432 from sg-app ← TGW 越しなので効かない
対比でまとめると、こうなります。
| 接続方法 | SG 参照 (from sg-xxx) | 備考 |
|---|---|---|
| 同一 VPC | 使える | |
| VPC ピアリング (同一リージョン) | 使える | ピア先 SG を参照可 |
| Transit Gateway | CIDR のみ | L3 ルーターで SG 情報を運ばない |
| VPN / Direct Connect / Cloud WAN | CIDR のみ | 同じく L3 経由 |
「TGW 越し = CIDR ベース」の根っこは、TGW が SG のメンバーシップ情報を運ばない L3 ルーターだから、の一点に尽きます。
もう一段外側の関所: Network ACL
ここまでは SG (ENI 単位) の話でした。TGW 構成ではもう一段外側、サブネット境界の NACL も効いてきます。SG との違いを押さえます。
| Security Group | Network ACL | |
|---|---|---|
| 適用単位 | ENI (インスタンス) | サブネット境界 |
| 状態 | ステートフル (戻りは自動許可) | ステートレス (戻りも明示許可が要る) |
| ルール | allow のみ | allow + deny 両方 |
| 評価 | 全ルールまとめて判定 | 番号順に上から、最初の一致で確定 |
| ソース指定 | CIDR または SG 参照 | CIDR のみ (常に) |
NACL は元々 CIDR ベースなので、TGW 越しの CIDR の世界と素直に噛み合います。そして SG にできない deny が書けるのが NACL の存在意義です。
最大のハマりどころ: ステートレス
SG は行きを許可すれば戻りは自動。でも NACL は戻りトラフィックを自分で許可しないと通りません。DB (5432) 接続ならこうなります。
# DB サブネットの NACL
Inbound : allow TCP 5432 from 10.20.0.0/16 (アプリ VPC)
Outbound : allow TCP 1024-65535 to 10.20.0.0/16 (★戻りのエフェメラルポート)
この Outbound のエフェメラル許可 (1024–65535) を忘れて接続がハングする、が定番事故です。NACL を触るならセットで必ず書きます。
使いすぎ注意
デフォルト NACL は全許可。多くの現場は NACL を開けたまま SG で制御しています。NACL を使う価値があるのは、SG で表現できない「粗い deny」「サブネット境界の防御」です。
- 既知の悪性 CIDR をブロックする
- 「この DB サブネットは、この数本の CIDR 以外とは一切話さない」をサブネット境界で強制する (多層防御)
逆に、SG のロジックを NACL に二重実装するのは避けます。メンテ地獄になる。細かい許可は SG、粗い遮断は NACL と粒度を分けるのがコツです。
パケットが通る順を一枚で
DB 宛のパケットが TGW 経由で届くとき、何が順番にチェックされるかを並べると、疎通トラブルの切り分けが一気に楽になります。
[アプリ ENI] --(SG outbound: 自動/ステートフル)
│
▼
[アプリサブネット ルートテーブル] 10.30.0.0/16 → tgw-xxxx ?
│
▼
[Transit Gateway ルートテーブル] 宛先 VPC への経路がある ?
│
▼
[DB サブネット ルートテーブル] 戻り経路 (アプリ VPC) がある ?
│
▼
[DB サブネット Inbound NACL] allow 5432 from アプリ CIDR ?
│
▼
[DB の SG inbound] allow 5432 from アプリ CIDR ? ← SG 参照は不可
│
▼
[DB 到達]
│ 戻り: SG=自動 / NACL Outbound=エフェメラル(1024-65535)を明示許可
▼
繋がらないときは、上から「ルート → NACL → SG」の順に潰します。AWS の Reachability Analyzer はこの経路を自動で辿ってどこで落ちるか教えてくれるので、最初に投げると速い。
dev と SRE の責任分担にきれいに乗る
この多層構造は、開発チームと SRE の役割分担にそのまま対応させられます。
- SG = 開発が持つ「許可」 — 自サービスに必要な最小の inbound を CIDR で書く
- NACL = SRE が持つ「ガードレール」 — 環境境界の deny、サブネット単位の遮断ポリシー
- TGW ルートテーブル / RAM 共有 / CIDR 採番 = SRE — 中央のネットワーク基盤
こうすると「開発が SG を緩めても、NACL とルートの境界は破れない」という二段構えになります。認証系のように爆発半径が大きい領域ほど、この分担が効きます。
開発チームが SRE に渡すべきは、実装可能な形の接続コントラクトです。
service: orders-api (prod, account 1234)
→ needs: payments-db (account 5678) : TCP 5432
direction: outbound only
source CIDR: 10.20.0.0/16
throughput: ~50GB/月 (TGW 処理コスト見積り用)
why: 注文確定時に決済台帳を参照
送信元 CIDR・宛先・ポート・方向・想定量・理由が揃っていれば、SRE は TGW ルート・NACL・SG を機械的に引けます。
CIDR 設計が効いてくる
「TGW 越し = CIDR ベース」ということは、CIDR 設計の質がそのまま SG / NACL ルールの質になるということです。CIDR が重複していたり雑だと、許可範囲も粗くなる。逆に綺麗に採番されていれば、SG はそのまま綺麗な許可リストになります。
許可元が増えて CIDR を並べるのが辛くなったら、マネージドプレフィックスリストに CIDR 群をまとめ、SG ではプレフィックスリストを 1 個参照します。さらにプレフィックスリストは AWS RAM で共有できるので、「許可対象 VPC の CIDR 一覧」を中央で管理し、各 DB の SG から参照する運用が組めます。これがマルチアカウントでの現実的なスケール方法です。
まとめ
- TGW は L3 ルーターで SG のメンバーシップ情報を運ばない。だから TGW 越しの SG は CIDR ベースになる (SG 参照は同一 VPC とピアリングでのみ有効)。
- NACL はステートレスなので、許可するなら戻りのエフェメラルポートも明示する。役割は「粗い deny / 境界の保険」。
- パケットは ルート → NACL → SG の順に通る。疎通トラブルはこの順で切り分け、Reachability Analyzer を併用する。
- SG = 開発の許可 / NACL・ルート = SRE のガードレール、と分担すると多層防御が自然に組める。
- CIDR 設計とプレフィックスリスト + RAM 共有が、CIDR ベース運用をスケールさせる鍵。