上級 28分 Lesson 6

VPCセキュリティ — ネットワークの壁を何重にも積む

SG/NACL/VPC Endpoints/Network Firewallを、建物のセキュリティに例えて講義形式で解説

AWS VPC SCS-C03 Security

建物のセキュリティから始めよう

想像してください。金融機関の本社ビルです。エントランスには警備員がいて、全員の身分証をチェック。さらに各フロアのドアには暗証番号ロック。さらにさらに、重要な資料室へは別の警備員が控えている。こういう多層防御ですよね。AWSのVPCセキュリティも全く同じ考え方です。

実は多くのエンジニアが「セキュリティグループ(SG)だけ設定すればいいか」と思ってたりします。大間違いです。SG、NACL、VPC Endpoints、Network Firewall。ここが重要なんですが、最低でもこの4層を理解して、要件に応じて組み合わせます。今日はこの階層的な防御を一つ一つ解きほぐしていきましょう。

Security GroupとNACLの決定的な違い

ここまでで一番質問が多いのがこれです。「結局、SGとNACLって何が違うんですか」。簡潔に言います。

Security Group(SG)はインスタンス(サーバー)の玄関に立つ個人用の警備員です。あなたのEC2インスタンスだけを守ります。ステートフルで、往路のルールだけ設定すれば復路は自動で許可される。片方向の契約だと思ってください。「来たやつは帰していい」という暗黙の了解がある。往路で「TCP 443 許可」と設定したら、復路の 443 からの戻りパケットは自動で通す。わざわざ復路ルール作らなくていい。

NACL、つまりNetwork ACLはサブネット全体の入口に立つビル全体の警備員です。同じサブネット内の全インスタンスを守ります。ステートレスで、往路と復路を両方ルール作成しないと動きません。「来たやつは帰していい」という約束がない。一つ一つ明示的に指定する。往路で「TCP 443 許可」と設定しても、復路は別ルール。「TCP エフェメラルポート 49152-65535 許可」と書かないと、クライアントへの応答がブロックされます。

NACLはルール番号の順番に評価されます。100番でALLOWが出ても、その前の90番でDENYが出てたらそこで止まる。順番が命です。一方SGはすべてのALLOWルールを評価して、1つでも許可されたら通す。順番は関係ない。ここが試験に出ます。「SGはステートフルだから往路だけでいい。NACLはステートレスだから往路と復路両方必須」。これ忘れないでください。

実務的な例を出しましょう。あなたが EC2 を起動して、Web サーバー運用するとします。インターネット側からのアクセス受け付けたい。SG を作ります。インバウンド「TCP 80 0.0.0.0/0 許可」「TCP 443 0.0.0.0/0 許可」。これで充分。クライアントからリクエスト来る。ステートテーブルに記録。レスポンス返すときは自動で許可。復路ルール不要。

でも NACL 同じことやろうとすると。インバウンド「TCP 80 0.0.0.0/0 許可」「TCP 443 0.0.0.0/0 許可」「TCP エフェメラルポート 49152-65535 0.0.0.0/0 許可」。これだけじゃダメ。アウトバウンドも。「TCP 80 0.0.0.0/0 許可」「TCP 443 0.0.0.0/0 許可」「ホストへのシステムポート 1-1024 許可」。複雑ですね。

「どっちを使えばいいですか」という質問が来ます。迷わないでください。両方使うんです。SGで個別インスタンスのレベルで細かく制御。NACLでサブネット全体のレベルで大雑把な防御。例えば「このサブネットには外部の特定 IP アドレス範囲からのアクセス禁止」という場合、NACL の拒否ルールで一括制御。サブネット内の全インスタンスに効きます。多層防御です。

VPC Endpointsの二つの顔

今、あなたのEC2インスタンスからS3にアクセスしたいとします。通常のルートは何でしょう。インスタンスがインターネットゲートウェイ経由でAWSパブリック空間に出て、S3に接続します。つまり、社外に一度出ちゃうわけです。何か変ですよね。S3はAWSのサービスなのに、なぜ社外を経由しなきゃいけない。

これを解決するのがVPC Endpoints。AWSの内部ネットワークを通じてS3に直接接続できます。社内郵便で済ませる、ということです。VPC Endpointsは2種類あります。

Gateway EndpointsはS3とDynamoDBのみ対応です。ルートテーブルにエントリを追加するだけで動く。シンプル。コストもかかりません。「社内郵便室を一つ追加した」くらいのイメージ。実装も簡単で、本当に使いやすい。例えば、Private Subnet の Route Table で「ルール:0.0.0.0/0 向かいは IGW。でも S3 向かいは VPC Endpoint」と指定する。すると、S3 への通信だけが特別に扱われ、インターネットを経由せずに直接 AWS の内部ネットワーク経由で S3 に到達します。

Interface EndpointsはEC2、SQS、SNS、Secrets Manager、ほぼ全てのAWSサービス対応です。ENI(ネットワークインターフェース)を作成して、各サブネットに配置します。ちょっと複雑だけど、細かい制御ができます。「各フロアに専用の郵便受けを置いた」感じです。Interface Endpoint を作ると、プライベート IP アドレスが割り当てられます。例えば 10.0.1.50 とか。EC2 からはこの IP 宛に通信すると、自動的に AWS 内部経由で対象サービスに到達します。

ここが重要なんですが、VPC Endpointsを使うと、インターネットゲートウェイを経由しません。だから、エンドポイントのセキュリティグループやエンドポイントポリシーで制御できるんです。インターネット経由の攻撃の心配がない。プライベートサブネットのインスタンスが、インターネットアクセスなしにAWSサービスと通信できます。「AWSの外に出たくない」が実現できる。これは本当に大事です。試験でも出ます。

エンドポイントポリシーというのは、誰がエンドポイント経由でサービスにアクセスできるか、を制御します。例えば、S3 Gateway Endpoint のポリシーで「アカウント内のすべての EC2 は OK。でも特定の Lambda だけは OK」みたいに絞ることもできます。或いは「GetObject だけ許可。PutObject は拒否」みたいに、操作レベルで制御することも。セキュリティが強い環境では、これを使って「本番環境の EC2 だけが本番バケットにアクセス可能」という制御をします。

Network Firewallが登場する理由

「あ、VPC Endpoints分かったし、SGとNACLで十分じゃないですか」。いや、ちょっと待ってください。想像してみてください。あなたのアプリケーションに、定期的に同じIPアドレスから攻撃が来ているとします。SGとNACLで「このIPを完全にブロック」とやっても、攻撃者は別のIPに変えてくる。ステートレスなNACLで全IPを列挙するわけにもいかない。IP ベースの防御は「その時」には効いても、次々と新しい IP が出てくることに対応できません。

あるいは、不正なポート番号でスキャンを試みる攻撃。あるいは、マルウェアの既知シグネチャを検出したい。あるいは、特定のドメインへのアクセス全体を禁止したい。例えば「malware.com へのアクセスはすべてブロック」。これを IP アドレスで制御するのは不可能。ドメイン名は複数の IP に対応し、また変わる。こういういかにもセキュリティが必要な場面で、AWS Network Firewall が登場します。

Suricata(オープンソースの入侵検知・防止システム)を搭載した、VPCレベルのファイアウォール。VPCとインターネットゲートウェイの間に配置して、全トラフィックを検査します。アプリケーションレイヤーの問題(SQLインジェクション、XSS)を検出して、ブロック。具体的には「SELECT * FROM users WHERE id = 1; DROP TABLE users;」みたいな SQL インジェクションを検知。あるいは JavaScript ペイロードを含むリクエストを検知。

SGとNACLは「ネットワークレイヤーだけ」の防御です。Network Firewallは「複数レイヤーの検査」ができます。L4 のネットワークレイヤーだけじゃなく、L7 のアプリケーションレイヤーまで。ステートフル、ステートレス、両方対応。プロトコル異常も検出。例えば「HTTP リクエストのサイズが 10MB 超えてる」みたいな異常。ただし注意点として、Network Firewall はコストがかかります。VPC 単位での課金。本当に必要な環境でだけ使うんです。個人の検証環境には不要。金融・医療・大規模 SaaS なら必須です。コスト削減を優先すれば、SG/NACL だけで最初は足りるけど、セキュリティインシデント起きてから後悔するパターンですね。

PrivateLinkと「内部通信の外部公開」

ここからはちょっと応用編です。あなたのVPC内に作ったマイクロサービスがあるとします。別のVPCのチームに使わせたい。でも、その別VPCは他社のVPC。信用できるけど、インターネットに出すのは怖い。PrivateLinkを使えば、VPC間でプライベートな通信路を作れます。インターネット経由しない、直線。

実装としては、サービス提供者側がNetwork Load Balancer(NLB)を作って、その背後に置きます。利用者側がEndpointを作成。NLBに「このEndpointからのトラフィックを許可」という設定をして、互いのセキュリティグループを許可し合う。PrivateLinkは「VPCから出さずにサービス提供」です。内部向けSaaSを考えている企業には本当に重宝する機能です。

PrivateLink詳細:組織間セキュアサービス提供

応用編をもう一つ。大企業 A が API サービス提供する。その API を提携企業 B が使いたい。でも、インターネット経由は危ない。PrivateLink を使えば、VPC 間でプライベート通信路を確立できます。インターネット経由しない、直線。

実装としては、サービス提供者側(企業 A)が Network Load Balancer(NLB)を作ります。その背後に API サーバーを配置。NLB に対して「エンドポイントサービス」を設定。これで「うちの NLB を通じてサービス提供する」と公開。

利用者側(企業 B)は VPC Endpoint を作成。そのエンドポイント経由で、企業 A の NLB に接続。自動的に企業 A のサービスに到達。トラフィックはプライベート。

ここが重要な点。VPC の IP アドレス空間が重複していても大丈夫。例えば企業 A が 10.0.0.0/16、企業 B も 10.0.0.0/16。普通は「IP ぶつかる」と接続できない。でも PrivateLink は「IP アドレス空間」を見ない。単に「接続路」を提供。

PrivateLink は「VPC から出さずにサービス提供」です。内部向け SaaS を考えている企業には本当に重宝する機能です。

Transit Gatewayで複雑な接続を整理する

話が進んできました。あなたの企業が大きくなって、VPC が 10 個、20 個になってきたとします。開発環境、ステージング、本番、各プロジェクト。これを全部つなげたい。VPC Peering だけじゃ、接続マトリックスが爆発します。Transit Gateway です。全 VPC の中央ハブ。全部ここに繋ぎ込めます。

イメージとしては「駅」です。各 VPC が電車の線路だとしたら、Transit Gateway が中央駅。全線が乗り入れて、乗り換えできる。Transit Gateway 経由で、VPC 間通信。オンプレとの接続(Site-to-Site VPN、Direct Connect)。複数リージョン間の接続。全部可能です。

具体例。本番 VPC が 10 個。各本番 VPC 同士、データベースレプリケーション通信が必要。VPC Peering だけだと「VPC A ~ VPC B」「VPC B ~ VPC C」「VPC C ~ VPC A」みたいに全組み合わせ。メッシュになる。ルーティング管理地獄。でも Transit Gateway 使うと「全本番 VPC を TGW にアタッチ」。そして「本番用ルーティング表」を作って「本番 VPC 同士通信は全部許可」。シンプル。新規本番 VPC が増えても「TGW にアタッチして、ルーティング表に追加」。終わり。

重要なのはアタッチメント。各 VPC のサブネットを TGW にアタッチして、Route Table でトラフィックを指向します。アタッチメント毎にセキュリティグループを設定できるので、「開発 VPC から本番 VPC へのアクセスは許可しない」みたいな制御も可能。開発と本番を完全に隔離。

Transit Gateway は「ネットワークトポロジーを集中管理できる中央ハブ」です。ただし、これもコストがかかります。アタッチ毎に料金。通信量でも料金。大規模な場合の選択肢です。

フローログで「何が起きたか」を追跡する

ここまでで防御の構造を理解しました。でも実際のセキュリティ事件が起きたとき、「何が起きたのか」を追跡できないと意味がない。VPC Flow Logs です。VPC、サブネット、ENIのレベルで、全トラフィックをログに記録。CloudWatch Logsか S3に出力します。

形式は固定です。ソースIP、ディスティネーションIP、ポート、プロトコル、成功/失敗フラグ。シンプルだけど、これで大抵の疑問が解ける。例えば「3月15日午後3時、データベースサーバーに外部から不正アクセスがあった」。Flow Logs を見ると「その時刻に 203.0.113.0 からポート 3306 への REJECT が大量に記録されてる」。あ、ファイアウォールは防いでた、と分かる。あるいは「許可されてた」と分かったら、さらに詳しく調査。インシデント対応の基本です。

「毎秒何十万パケットありますよ。ログが肥大化しませんか」という質問が来ます。その通りです。本番環境では特定のポート(例えば22番とか443番)だけログに取るとか、SAMPLE レートを 10% とかにします。コストとの兼ね合いですね。「すべてをログ」は費用が跳ね上がる。「重要なトラフィックだけ」と「定期的に全体の 10% サンプル」を組み合わせるのが実務的。

CloudWatch Logs に出力したら、CloudWatch Insights でクエリ。「昨日の 14 時から 15 時でこの ENI からブロックされたトラフィックは何件」とか。S3 出力なら、Athena で SQL。セキュリティ事件が起きたとき、Flow Logs なしに調査はできません。本当に。必ず有効にしてください。最低でも Subnet レベルで。試験にも出ます。

実務シナリオ。東京リージョンで、EC2 が突然外部との通信を大量に始めた。マルウェア感染?それとも不正アクセス?Flow Logs を見ると「10.0.1.50(感染疑いの EC2)から 203.0.113.0:8080 に大量の TCP SYN 送信」。あ、C&C サーバーと通信してるな、と分かる。その IP をブロック。EC2 を隔離。Flow Logs がなかったら「何が起きたか分かりませんでした」。後の調査も困難。

エフェメラルポート問題で引っかかるな

最後に、よくある事故を一つ。セキュリティグループで「このサーバーのポート 443 は許可」と設定しました。でも通信が失敗する。なぜ。

原因は往路は許可されたけど、復路が NACL でブロックされてるんです。ネットワーク通信は往復です。HTTP/HTTPS なら、クライアントがポート 1024~65535 の間のエフェメラルポート(一時的なポート)を使って、サーバーのポート 443 に接続します。往路は OK だけど、戻ってくるときのリプライは、このエフェメラルポートに返ってくる。

SG はステートフルだから「往路許可」で自動的に復路も許可。だから SG だけなら問題ない。でも NACL はステートレス。往路「TCP 443 許可」しても、復路は別ルール。「TCP エフェメラルポート 49152-65535 許可」と書かないと、クライアントへの応答がブロックされる。

「Connection reset by peer」で失敗します。実務だと「あ、NACL を変更したら通信が壊れた」ってなる。NACLのエフェメラルポート設定を忘れるな。最低でも 1024~65535。だけど実務では Windows と Linux でエフェメラルポート範囲が違う場合もあります。Linux は 49152-65535。Windows は 1024-65535。環境によって異なります。念のため広めに設定(1024-65535)するのが無難。

でも NACL を触るなら、必ず思い出してください。試験の落とし穴です。「SG と NACL 両方設定したのに、通信失敗。原因は何か」という問題で「NACL のエフェメラルポート漏れ」が答え。

実務シナリオ:東京と大阪のデータセンター接続

あなたがECサイトのセキュリティ担当だとしましょう。東京リージョンにEC2、RDS。大阪リージョンにもレプリカがある。両リージョン間でプライベート通信したい。「インターネット経由は避けたい」という要件が出た場合、何を使いますか。

答えはTransit Gateway です。東京VPCのサブネットをTGWにアタッチ。大阪VPCのサブネットをTGWにアタッチ。Route Tableで「大阪行きはTGW経由」と指定。これで自動的にプライベート接続が完成。間にNACLやSGを挟んで、通信を制御。シンプルで管理しやすい。

もし単純なS3アクセスだけなら、Gateway Endpointで十分。でも複数のAWSサービスが必要なら、Interface Endpoints。VPCが複数あるなら、Transit Gateway。要件で使い分けるんです。

よくあるトラブルシューティング

実務では、こんな問題がよく出ます。

「Private Subnet から S3 にアクセスしたいのに、タイムアウトする」。原因は?VPC Endpoint が 404 Not Found。あ、Gateway Endpoint を作ったはずが、Route Table に登録されてない。又は、エンドポイントポリシーで S3 アクセスが拒否されてる。確認してみると「getObject は許可、putObject は拒否」。あ、読み取りのみ許可で、アプリケーションが PUT しようとしてた。終わり。

「セキュリティグループで インバウンド 443 許可したのに、SG 内の EC2 間で HTTPS 通信が失敗」。原因は?SG は「外部からの接続」は許可したけど、「自分たち内部での通信」を許可してない。SG に「インバウンド 443 from SG 自身」という自己参照ルール追加。終わり。

「Transit Gateway 経由で VPC 間通信したいのに、できない」。Route Table で「TGW への route」が設定されてない。あ、TGW にアタッチしたけど、Route Table で「この CIDR は TGW 経由」と指定してない。ルーティング設定不完全。Route Table を確認。終わり。

こういう細かい設定漏れが、本番で大惨事になります。テスト環境で必ず一度やってみる。「あ、こういう手順が必要なんだ」と体で覚えておくと、本番で引っかかりません。

多層防御の設計パターン

本番環境で実装すべき「型」を一つ提示しましょう。

インターネット側からのアクセス。Internet Gateway → Network Firewall(L7 検査)→ VPC → Public Subnet → SG(インバウンド 443)→ Web サーバー。ここまで。

Web サーバーから Database サーバーへ。SG(アウトバウンド 5432)→ Private Subnet → NACL(インバウンド 5432、アウトバウンドエフェメラルポート)→ SG(Database, インバウンド 5432)→ RDS。

この流れの中で、複数のレイヤーで検査・制御される。インターネットからの攻撃が来ても、Network Firewall で既知シグネチャの SQL インジェクション検知。SG で許可されたポート以外ブロック。NACL で追加制御。多層防御。一つのレイヤーが突破されても、後ろに守りがある。

実務での問題シナリオ。攻撃者が Web サーバーを乗っ取った。でも Database へのアクセスは失敗。何故?

Web サーバーの SG は「アウトバウンド全許可」かもしれない。でも Database の SG は「Web サーバー SG からのみ許可」。そして NACL で追加制御。3 層で守られてる。乗っ取られた Web サーバーから Database を操ろうとしても、複数のレイヤーで引っかかる。被害最小化。

VPC Flow Logs で「何がブロックされたか」を確認。「Web サーバーが Database ポート 5432 にアクセス試みたけど、SG で拒否」。あ、乗っ取られた、と判明。SG ルール確認。「あ、Web サーバー SG とは別の SG からアクセスしようとしてた」。何だ、内部犯行か。調査対象を絞れます。

まとめ——多層防御は「型」を決めること

VPCセキュリティの全体像です。Security Groupで個別インスタンス。NACLでサブネット。Network Firewallで VPCとインターネットの境界。PrivateLinkで組織間の通信。Transit Gatewayで複数VPCの一元管理。Flow Logsで「何が起きたか」の追跡。どれが正解ではなく、どれを組み合わせるかが問題です。要件ごとに異なります。

ただし一つの「型」として覚えておいてください。本番環境なら、少なくともこれ。SG で基本ルール。NACL で第二防衛線。Network Firewall で既知攻撃シグネチャの検出。Flow Logs で監査。ここまであれば、よほどのことがない限り安心です。

最後に、一番大事なのは「変更は必ずテスト環境で」。ネットワークルールの変更は、アプリケーションが一瞬つながらなくなる可能性がある。本番直前で「あ、SG の設定間違えた」は、本当に洒落にならない。ネットワークは信頼性が全ての世界です。では次のトピックに進みましょう。