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 ルート行き/戻りの経路成立フィルタリング
④ 検査 VPCL7・シグネチャでの許可/拒否(ここを通すと ⑥ の 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手動で経路追加 / 明示的にドロップ任意上書き

覚え方:

この 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 CIDRprod → shared のみ(dev は無い)
rt-dev (dev が見る)shared CIDRdev → shared のみ(prod は無い)
rt-shared (shared が見る)prod CIDR, dev CIDRshared → prod / dev 両方

prod の地図に dev が載っていないので、prod から dev はルート不在で到達不能。SG も NACL も書く前に、ネットワーク到達性のレベルで分離できています。これが TGW セグメンテーションの効きどころです。

落とし穴

  1. デフォルト RT の自動関連付け / 自動伝播を OFF にする。TGW 作成時に defaultRouteTableAssociationdefaultRouteTablePropagation を disable にして、全部を明示管理する。ON のままだと全アタッチが 1 枚の RT に乗ってフルメッシュになり、分離が崩れる。
  2. 非対称ルーティング。アソシエーションと伝播が独立ゆえ「行きは通るが戻りが無い」が起きる。必ず往復で経路を確認する。
  3. blackhole ルートで明示遮断できる。「ここは絶対通さない」を宣言的に書ける。
  4. ルート探索はロンゲストプレフィックスマッチ。広い静的ルートと細かい伝播ルートが混在すると意図とズレることがある。
  5. CIDR 重複は不可。重複する VPC はそもそも経路が伝播されない。これがマルチアカウントで CIDR 採番をケアすべき根本理由。

セキュリティグループ: CIDR か、SG 参照か

⑥ のインスタンス層に降りると、SG のソースの書き方が問題になります。ここは AWS のアップデートで状況が変わった部分なので、正確に。

つまり「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 の役割分担にそのまま対応します。

開発チームが 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 を機械的に引けます。

まとめ

← Back to all posts