セキュリティグループ vs ネットワークACL:AWSの2つのファイアウォールを使い分ける
概要
AWSのVPCには、トラフィックを制御する仕組みが2種類あります。セキュリティグループ(Security Group, SG) と ネットワークACL(Network ACL, NACL) です。どちらも「ファイアウォール」と説明されるため、初めて触れると「どちらを使えばいいのか」「両方必要なのか」で必ず迷います。
結論から言うと、両者は適用される層・動作モデル・ルールの表現力がすべて異なります。本記事では、両者の違いを整理し、実務でどう使い分けるかを解説します。
前提環境
- Amazon VPC(デフォルトVPCおよびカスタムVPCの双方)
- 対象: EC2、RDS、ALB など ENI(Elastic Network Interface)を持つリソース全般
発生しがちな問題
インフラ構築では、以下のような混乱がよく起きます。
- セキュリティグループで許可したのに通信できない(実はNACLで戻りが弾かれている)
- NACLでインバウンドを許可したのに応答が返らない(ステートレスの落とし穴)
- 「拒否ルールを書きたい」のにSGに拒否が書けなくて困る
- どちらの層で制御すべきか設計方針が定まらない
これらはすべて、2つの仕組みの動作モデルの違いを理解していないことに起因します。
両者の本質的な違い
1. 適用される層が違う
| 観点 | セキュリティグループ | ネットワークACL |
|---|---|---|
| 適用単位 | ENI(インスタンス)単位 | サブネット単位 |
| 適用範囲 | 紐づけたリソースにのみ作用 | サブネット内の全リソースに一律作用 |
セキュリティグループは「そのリソースの直前」に立つ門番、ネットワークACLは「サブネットの入口」に立つ門番、とイメージするとよいでしょう。
2. ステートフル vs ステートレス(最重要)
これが最大の違いであり、最もハマるポイントです。
- セキュリティグループ = ステートフル
インバウンドで許可した通信の戻り(レスポンス)は自動的に許可されます。戻りのルールを書く必要がありません。
- ネットワークACL = ステートレス
行きと戻りを別々に評価します。インバウンドを許可しても、アウトバウンド(戻り)を許可しなければ応答が返りません。
3. 許可ルール / 拒否ルール
- SG: 許可(allow)ルールのみ。書いていないものは暗黙拒否です。「特定IPだけ拒否」はSGでは書けません。
- NACL: 許可・拒否の両方を書けます。特定IPをブロックしたい場合はNACLの出番です。
4. ルールの評価順序
- SG: すべてのルールを評価し、いずれか1つでもマッチすれば許可。順序の概念はありません。
- NACL: ルール番号の小さい順に評価し、最初にマッチしたルールで確定します(以降は見ません)。順序が挙動を左右します。
実務での使い分け
基本方針:主役はセキュリティグループ
実務ではセキュリティグループを主たる制御手段とし、NACLは補助的に使うのが定石です。理由は以下の通りです。
- ステートフルなので設定が直感的でミスが起きにくい
- ENI単位なので「このリソースだけ」の制御が正確にできる
- SG同士を参照(SGをソースに指定)できるため、IPを固定しない動的な構成に強い
NACLを使う場面
NACLは以下のような「サブネット全体に効かせたい」「明示的に拒否したい」ケースで使います。
- 特定のIPアドレス(レンジ)をサブネット全体からブロックしたい
- サブネット単位で最低限のガードレールを敷きたい(多層防御)
- 誤設定されたSGの保険として、粗い網をかけておきたい
実装例
セキュリティグループ(ステートフルなので戻り不要)
Webサーバ用SG。80/443を全世界から、SSHは管理用IPのみ許可する例です。
# インバウンド Type Protocol Port Source HTTP TCP 80 0.0.0.0/0 HTTPS TCP 443 0.0.0.0/0 SSH TCP 22 203.0.113.10/32 # 管理用IPのみ # アウトバウンド(デフォルトの全許可のまま。戻りは自動許可されるため個別指定不要) All All All 0.0.0.0/0
RDS用SGで「WebサーバのSGからのみ」を許可する例(IPではなくSGを参照)。
# インバウンド Type Protocol Port Source MySQL/Aurora TCP 3306 sg-0123web... # WebサーバのSGを直接指定
SGをソースに指定できるのがSGの強力な点です。オートスケールでIPが変わっても設定を変えずに済みます。
ネットワークACL(ステートレスなので戻りを明示)
同じくHTTP/HTTPSを許可する場合、戻り用のエフェメラルポートを別途許可する必要があります。
# インバウンド(ルール番号順に評価、最初にマッチで確定) Rule# Type Protocol Port Source Allow/Deny 100 HTTP TCP 80 0.0.0.0/0 ALLOW 110 HTTPS TCP 443 0.0.0.0/0 ALLOW 120 Custom TCP 1024-65535 0.0.0.0/0 ALLOW # 戻り(エフェメラル)受信用 * All All All 0.0.0.0/0 DENY # 暗黙のdeny # アウトバウンド(戻りを返すために必須) Rule# Type Protocol Port Dest Allow/Deny 100 Custom TCP 1024-65535 0.0.0.0/0 ALLOW # クライアントへの応答 110 HTTP TCP 80 0.0.0.0/0 ALLOW # 外部への発信が必要なら * All All All 0.0.0.0/0 DENY
エフェメラルポート(一時ポート)の範囲はOS/クライアントにより異なるため、1024-65535 と広めに開けるのが一般的です。ここを開け忘れると「SGは正しいのに応答が返らない」という典型的なハマりが発生します。
特定IPをブロックする例(NACLならでは)。DENYを許可ルールより小さい番号に置きます。
Rule# Type Protocol Port Source Allow/Deny 90 All All All 198.51.100.5/32 DENY # このIPを先に拒否 100 HTTP TCP 80 0.0.0.0/0 ALLOW
確認方法
- SGの確認: EC2コンソール → セキュリティグループ、または
aws ec2 describe-security-groups - NACLの確認: VPCコンソール → ネットワークACL、または
aws ec2 describe-network-acls - 通信不達の切り分け: VPC Flow Logs を有効化し、
ACCEPT/REJECTを確認する。SGでREJECTされたのかNACLでされたのかはFlow Logsだけでは直接判別できないため、両方の設定を突き合わせます
注意点
- NACLのステートレス性を常に意識する。インバウンドを開けたらアウトバウンドの戻り(エフェメラル)も開ける、を必ずセットで考える
- デフォルトNACLは全許可。何もしなければNACLは実質無効なので、まずSGで組み、必要ならNACLを足す
- NACLのルール番号は間隔を空けて採番する(100, 110, 120…)。後から間に挿入できるようにするため
- SGには拒否が書けない。「特定IPを弾く」要件が出たら設計段階でNACLを検討する
まとめ
| 観点 | セキュリティグループ | ネットワークACL |
|---|---|---|
| 適用層 | ENI(インスタンス) | サブネット |
| 状態管理 | ステートフル(戻り自動許可) | ステートレス(戻り要明示) |
| ルール | 許可のみ | 許可・拒否 |
| 評価 | 全ルール評価 | 番号順・最初のマッチで確定 |
| SG参照 | 可能 | 不可(CIDRのみ) |
| 主な役割 | メインの制御 | 補助・多層防御 |
まずセキュリティグループで組む。拒否要件やサブネット単位のガードが必要になったらネットワークACLを足す。 これが実務での鉄則です。ネットワークACLの「ステートレス=戻りを別に開ける」という点だけは、頭に叩き込んでおくと事故が激減します。

