Transit Gateway のアクセス制御を多層で設計する — ルートテーブル・NACL・セキュリティグループ
マルチアカウントを Transit Gateway で繋ぐとき、アクセス制御は単一の機能ではなく複数レイヤーの合わせ技になる。参加制御・TGW ルートテーブルのセグメンテーション・NACL・セキュリティグループまでを、入口から順に first principles で整理します。
出発点: TGW のアクセス制御は「単一機能」ではない
マルチアカウント構成で、サービス間を Transit Gateway (TGW) で繋ぐ。DB 接続のような非 HTTP の通信も含む。CIDR は重複しないように採番している — そんな状況を想定します。
まず大前提を押さえます。TGW 自身は L3 ルーターであり、その責務は「到達性 (ルーティング)」です。port や protocol、L7 のきめ細かい許可・拒否は TGW の外側で行う。つまり「TGW のアクセス制御」とは単一の機能ではなく、複数のレイヤーを入口から順に積むことを指します。ここを最初に分解しておくと、全体像が崩れません。
入口から順に: アクセス制御のファネル
通信が成立するには、次のレイヤーをすべて通過する必要があります。逆に言えば、どれか一つで止めれば遮断できます。
① 参加制御 : VPC を TGW にアタッチするか(+ RAM 共有 + 承認)
│ 繋がなければ到達性ゼロ。マルチアカウントの一次関門
▼
② 到達制御 : TGW ルートテーブル(アソシエーション/伝播/静的/blackhole)
│ ★ここが TGW 固有のアクセス制御の本体=セグメンテーション
▼
③ VPC 内ルート : 各サブネットのルートテーブル(行き・戻り両方)
│ TGW 側が許しても、VPC 内に TGW 向け経路が無ければ通らない
▼
④ (任意)集中検査: Inspection VPC(Network Firewall / GWLB)へ迂回
│ L7/IDS で許可・拒否(appliance mode 必須)
▼
⑤ NACL : サブネット境界。CIDR のみ・deny 可・ステートレス(戻り明示)
▼
⑥ SG : インスタンス単位。allow のみ・ステートフル
ソース = CIDR / SG 参照(条件付きで TGW 越し可)
各レイヤーが「何を制御できる / できないか」
| レイヤー | 制御できること | できないこと |
|---|---|---|
| ① アタッチ + RAM | このTGWに参加できるか / 接続要求を承認するか | 通信内容の制御 |
| ② TGW ルートテーブル | どの VPC がどの VPC へ到達できるか(経路の有無でセグメント化、blackhole で明示遮断) | port/protocol 単位の許可拒否(粗い) |
| ③ VPC ルート | 行き/戻りの経路成立 | フィルタリング |
| ④ 検査 VPC | L7・シグネチャでの許可/拒否 | (ここを通すと ⑥ の SG 参照が無効化される) |
| ⑤ NACL | サブネット境界での粗い allow / deny(CIDR) | SG 参照は不可・ステートフルでない |
| ⑥ SG | インスタンス単位の allow(port/proto) | deny は書けない |
ここで重要なのは、TGW 本体のアクセス制御は「到達できるか否か」という粗い許可だということ。TGW には deny ルールのようなファイアウォール機能はありません(あるのは経路を消す / blackhole にする、という粗い手段だけ)。きめ細かさは SG・NACL・検査 VPC が担います。
本体: TGW ルートテーブルによるセグメンテーション
TGW は複数のルートテーブル (RT) を持てます。各アタッチメントに対して、独立した 2 つの設定をする。これが混同の元なので、必ず分けて覚えます。
| 操作 | 何を決めるか | 個数 | 向き |
|---|---|---|---|
| アソシエーション | そのアタッチから来た通信がどの RT を使って宛先を引くか | 1 アタッチ = 1 つだけ | 出口(参照先) |
| 伝播 (propagation) | そのアタッチの VPC CIDR をどの RT に経路として自動で載せるか | 複数 OK | 入口(宣伝先) |
| 静的ルート / blackhole | 手動で経路追加 / 明示的にドロップ | 任意 | 上書き |
覚え方:
- アソシエーション = 自分が宛先を探すとき見る地図(1 枚だけ持てる)
- 伝播 = 自分の存在を、どの地図に載せてもらうか(何枚にでも載せられる)
この 2 つは独立しているので、「A は B に行けるが B は A に行けない」という非対称も作れます(これが戻り経路の事故の温床でもある)。
到達性はこう決まる
A から B が通る条件 = 「A のアソシエーション先 RT に、B の CIDR への経路が載っている」。B の CIDR がその RT に載るのは、B が伝播している か 静的に追加した とき。一言でいうと:
A の地図(アソシエーション)に B が宣伝(伝播)されている ⇔ A から B へ到達可
具体例: prod / dev / shared(DB) の 3 セグメント
アタッチメント: att-prod, att-dev, att-shared(shared に DB を置く)
TGW ルートテーブル: rt-prod, rt-dev, rt-shared
作りたい到達性: prod ⇄ shared は可 / dev ⇄ shared は可 / prod ⇄ dev は不可。
アソシエーション(各アタッチ = 1 枚):
att-prod → rt-prod
att-dev → rt-dev
att-shared → rt-shared
伝播(どの RT に自分を載せるか):
att-prod を rt-shared に伝播 (shared から prod へ戻れる)
att-dev を rt-shared に伝播 (shared から dev へ戻れる)
att-shared を rt-prod と rt-dev に伝播(prod/dev から shared へ行ける)
※ att-prod を rt-dev に伝播しない / att-dev を rt-prod に伝播しない
結果、各 RT に載る経路:
| RT | 載っている経路 | この地図を見る人が行ける先 |
|---|---|---|
| rt-prod (prod が見る) | shared CIDR | prod → shared のみ(dev は無い) |
| rt-dev (dev が見る) | shared CIDR | dev → shared のみ(prod は無い) |
| rt-shared (shared が見る) | prod CIDR, dev CIDR | shared → prod / dev 両方 |
prod の地図に dev が載っていないので、prod から dev はルート不在で到達不能。SG も NACL も書く前に、ネットワーク到達性のレベルで分離できています。これが TGW セグメンテーションの効きどころです。
落とし穴
- デフォルト RT の自動関連付け / 自動伝播を OFF にする。TGW 作成時に
defaultRouteTableAssociationとdefaultRouteTablePropagationを disable にして、全部を明示管理する。ON のままだと全アタッチが 1 枚の RT に乗ってフルメッシュになり、分離が崩れる。 - 非対称ルーティング。アソシエーションと伝播が独立ゆえ「行きは通るが戻りが無い」が起きる。必ず往復で経路を確認する。
- blackhole ルートで明示遮断できる。「ここは絶対通さない」を宣言的に書ける。
- ルート探索はロンゲストプレフィックスマッチ。広い静的ルートと細かい伝播ルートが混在すると意図とズレることがある。
- CIDR 重複は不可。重複する VPC はそもそも経路が伝播されない。これがマルチアカウントで CIDR 採番をケアすべき根本理由。
セキュリティグループ: CIDR か、SG 参照か
⑥ のインスタンス層に降りると、SG のソースの書き方が問題になります。ここは AWS のアップデートで状況が変わった部分なので、正確に。
- デフォルトの挙動: TGW 越しは CIDR ベースで書くのが基本。
- security group referencing を有効化すれば、同一 TGW にアタッチされた VPC 間で インバウンド限定の SG 参照(
from sg-xxxx)が使える。SG メンバーシップは動的に解決されるので、CIDR リストを維持しなくてよくなる。- TGW 本体とアタッチメントの両方で有効化して初めて効く(TGW 本体はデフォルト無効、アタッチメントはデフォルト有効なので、実務上は TGW 側を ON にするのがスイッチ)。追加料金なし。
- アウトバウンドの SG 参照は非対応(インバウンドのみ)。
- SG 参照が効かず CIDR に戻るケース:
- TGW ピアリング越し / クロスリージョン(両 VPC が同一 TGW にアタッチされている必要がある)
- 検査 VPC(Gateway Load Balancer / Network Firewall)を経由する経路
- PrivateLink エンドポイント宛
- VPN / Direct Connect 相手(そもそも VPC ではない)
つまり「TGW 越しは常に CIDR のみ」ではなく、「同一 TGW・機能 ON・インバウンドなら SG 参照可。検査やピアリングを挟むと CIDR」が正しい理解です。
なお NACL は常に CIDR ベースかつステートレスなので、許可するなら戻りのエフェメラルポート (1024–65535) も明示します。これを忘れて接続がハングするのが定番事故です。
検査 (Inspection) を挟む場合
全 East-West トラフィックをファイアウォールに通したいなら、各環境 RT のデフォルトルート (0.0.0.0/0) を Inspection VPC のアタッチメントに向け、Inspection VPC 側の RT で本来の宛先へ戻します。TGW の RT を「迂回路」として使う発想です。appliance mode が必須で、この経路では SG 参照は無効になる(CIDR 運用)点に注意。
段々絞る: ② → ⑤ → ⑥
実際の設計は、上のレイヤーで粗く分離し、下のレイヤーで細かく絞る、という流れになります。
② TGW ルート RT で「prod→dev は到達不能、prod→shared は可」を作る ← 粗い分離
↓ 到達可になった通信に対して
⑤ NACL で「shared サブネットは許可 CIDR 以外 drop」 ← 境界 deny
⑥ SG で「DB は :5432 をアプリ CIDR / SG 参照のみ許可」 ← 細かい allow
到達性 (②) → 境界 (⑤) → インスタンス (⑥) と段々絞る。② で切れているものは ⑤⑥ を書くまでもありません。疎通しないときも、この順で「ルート → NACL → SG」と上から潰すと切り分けが速い。AWS の Reachability Analyzer がこの経路を自動で辿ってどこで落ちるか教えてくれます。
dev と SRE の責任分担に乗せる
この多層構造は、開発チームと SRE の役割分担にそのまま対応します。
- TGW ルートテーブル / RAM 共有 / CIDR 採番 = SRE(中央のネットワーク基盤と到達性の設計)
- NACL = SRE が持つガードレール(環境境界の deny)
- SG = 開発が持つ許可(自サービスに必要な最小の inbound)
開発チームが 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 を機械的に引けます。
まとめ
- TGW は到達性 (ルート) の制御装置。きめ細かさは外側 (SG/NACL/検査) に積む多層防御。TGW 自体に deny ルールはない(blackhole という粗い手段はある)。
- 設計の主役は TGW ルートテーブルのセグメンテーション。アソシエーション(見る地図は 1 枚)と伝播(載る地図は複数)を分けて理解し、「どの地図に誰が載っているか」で到達性を設計する。
- デフォルト RT の自動関連付け / 伝播は OFF にして明示管理。非対称ルーティングと CIDR 重複に注意。
- SG 参照は同一 TGW・機能 ON・インバウンドなら使える。検査 VPC / ピアリング / PrivateLink を挟むと CIDR に戻る。NACL は常に CIDR・ステートレス(戻り明示)。
- 到達性 → 境界 → インスタンス と段々絞る。SG = 開発の許可 / ルート・NACL = SRE のガードレールで多層防御を組む。