AWSのVPC設計に取り組み始めたエンジニアが最初にぶつかる壁のひとつです。原因を調べていくと、セキュリティグループとは別に「Network ACL」というファイアウォールが存在することに気づきます。
この記事では、VPCのセキュリティを支えるNetwork ACL(NACL)とセキュリティグループ(SG)の違いと、2層防御として組み合わせる設計パターンを解説します。Amazon Linux 2023 / RHEL 9.4での実機確認コマンドも交え、「SGで許可したのに繋がらない」エラーの切り分け手順まで説明します。
この記事のポイント
・NACLはサブネット単位のステートレスFW、SGはインスタンス単位のステートフルFWで役割が異なる
・ステートレスのNACLはインバウンド許可だけでは不十分、アウトバウンドも明示的に設定が必要
・「NACL=サブネット境界の入口制限」「SG=インスタンス間のきめ細かい通信制御」で役割を分ける
・「SGで許可したのに繋がらない」の原因はNACLのエフェメラルポート未許可であることが多い
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜVPCには2種類のファイアウォールが必要なのか
VPCのセキュリティを理解するには、「どのレイヤーでトラフィックを制御するか」という視点が重要です。AWSのVPCには2つの独立したファイアウォールが存在します。
・Network ACL(NACL):サブネット単位で働く。サブネットに出入りするトラフィックをルール番号順に評価する
・セキュリティグループ(SG):EC2インスタンス(正確にはENI)単位で働く。「許可したトラフィックの戻りは自動で許可」するステートフルな動作
この2層構造は意図的な設計です。大企業の物理ネットワークでは「フロアごとのFW」と「端末ごとのFW」を組み合わせるのと同じ発想です。NACLが「建物の受付」なら、SGは「各部屋の鍵」です。
VPCの基本設計についてはAWSのLinux環境構築とVPC設計入門で解説しています。本記事では、そのセキュリティ設計層を深掘りします。
セキュリティグループ(SG)の設計──ステートフルの意味を理解する
セキュリティグループの最大の特徴は「ステートフル」であることです。インバウンドルールで許可したトラフィックに対する戻りのパケットは、アウトバウンドルールを設定していなくても自動的に許可されます。1. インバウンドルールの設計
SGのインバウンドルールは「このポートへの通信を誰から許可するか」を定義します。# セキュリティグループのインバウンドルールを確認する $ aws ec2 describe-security-groups \ --group-ids sg-0123456789abcdef0 \ --query 'SecurityGroups[*].IpPermissions' [ { "FromPort": 443, "IpProtocol": "tcp", "IpRanges": [ { "CidrIp": "0.0.0.0/0", "Description": "HTTPS from anywhere" } ], "ToPort": 443 }, { "FromPort": 22, "IpProtocol": "tcp", "IpRanges": [ { "CidrIp": "10.0.0.0/8", "Description": "SSH from private network only" } ], "ToPort": 22 } ]
2. アウトバウンドルールとSGのチェーン設計
SGのアウトバウンドルールのデフォルトは「全て許可(0.0.0.0/0)」です。セキュリティを強化する場合は、アウトバウンドを「必要な宛先のみ許可」に絞ります。SGの強力な機能のひとつが「SGを参照したルール(SGチェーン)」です。CIDRではなく別のSG IDを参照して許可を設定できます。
# DBサーバーのSGに「AppサーバーのSGからの接続のみ許可」を設定する例 $ aws ec2 authorize-security-group-ingress \ --group-id sg-db-xxxxxxxx \ --protocol tcp \ --port 3306 \ --source-group sg-app-xxxxxxxx # SGチェーンの確認 $ aws ec2 describe-security-groups \ --group-ids sg-db-xxxxxxxx \ --query 'SecurityGroups[*].IpPermissions[*].UserIdGroupPairs' [ [ { "GroupId": "sg-app-xxxxxxxx", "UserId": "123456789012" } ] ]
Network ACL(NACL)の設計──ステートレスの落とし穴を理解する
NACLはSGと大きく異なる「ステートレス」な動作をします。ステートレスとは「各パケットを独立して評価する」ということです。インバウンドでHTTPSを許可しても、それに対する応答(アウトバウンド)は別途許可が必要です。1. ルール番号と評価順序
NACLのルールは「番号の小さい順に評価」され、最初にマッチしたルールで通過・拒否が確定します。# NACLのルール一覧を確認する $ aws ec2 describe-network-acls \ --network-acl-ids acl-0123456789abcdef0 \ --query 'NetworkAcls[*].Entries[*].[RuleNumber,RuleAction,Protocol,PortRange,CidrBlock,Egress]' \ --output table ------------------------------------------------------------------- | Rule# | Action | Protocol | PortRange | CidrBlock | Egress | |-------|--------|----------|-----------|-----------|------------| | 100 | allow | 6(TCP) | 443-443 | 0.0.0.0/0 | False(IN) | | 32767 | deny | -1(ALL) | - | 0.0.0.0/0 | False(IN) | | 32767 | deny | -1(ALL) | - | 0.0.0.0/0 | True(OUT) | ------------------------------------------------------------------- # アウトバウンドルールが暗黙DENYのみ → レスポンスが返せない
2. エフェメラルポートを必ず許可する
NACLを使う際に最も多いトラブルが「エフェメラルポート(一時ポート)の未許可」です。クライアントがWebサーバーに接続するとき、クライアントは送信元ポートとして1024~65535番のランダムなポート(エフェメラルポート)を使います。NACLのアウトバウンドルールでこの範囲を許可していないと、WebサーバーからクライアントへのHTTPSレスポンスが届きません。
# エフェメラルポートの範囲をOS別に確認する # Amazon Linux 2023 / RHEL 9.4 $ cat /proc/sys/net/ipv4/ip_local_port_range 32768 60999 # NACLのアウトバウンドルールに追加する(安全側で1024-65535を許可) $ aws ec2 create-network-acl-entry \ --network-acl-id acl-0123456789abcdef0 \ --no-ingress \ --rule-number 100 \ --protocol tcp \ --rule-action allow \ --cidr-block 0.0.0.0/0 \ --port-range From=1024,To=65535
3. サブネット単位で適用する
NACLはサブネットに紐づきます。1つのNACLを複数のサブネットに関連付けることも、サブネットごとに独立したNACLを作ることも可能です。# サブネットとNACLの関連付けを確認する $ aws ec2 describe-subnets \ --subnet-ids subnet-0123456789abcdef0 \ --query 'Subnets[*].[SubnetId,Tags[?Key==`Name`].Value|[0]]' [ [ "subnet-0123456789abcdef0", "public-subnet-1a" ] ] # そのサブネットに紐づくNACLを確認する $ aws ec2 describe-network-acls \ --filters "Name=association.subnet-id,Values=subnet-0123456789abcdef0" \ --query 'NetworkAcls[*].NetworkAclId' [ "acl-0123456789abcdef0" ]
NACLとSGを組み合わせた2層防御パターン
NACLとSGをどう使い分けるか──実際の3層構成(パブリック・アプリ・DBサブネット)で設計します。1. 3層サブネット構成でのNACL設計方針
| サブネット | NACLの役割 | SGの役割 |
|---|---|---|
| パブリック(ALB配置) | インターネットからHTTPS(443)のみ許可、それ以外はDENY | ALBからEC2のHTTP 8080のみ許可(SGチェーン) |
| プライベート(Appサーバー) | パブリックサブネットCIDRからの通信のみ許可 | AppサーバーSGからDBへのMySQL 3306のみ許可 |
| プライベート(DB) | Appサブネット以外からの全通信をDENY | AppサーバーSGからの3306のみ許可(SGチェーン) |
2. NACL設計で実際に使うルールセット例
パブリックサブネット(ALB用)のNACL設定例です。# パブリックサブネットNACL(インバウンド) Rule 100: ALLOW TCP 443 from 0.0.0.0/0 # HTTPS(インターネット→ALB) Rule 200: ALLOW TCP 80 from 0.0.0.0/0 # HTTP(ALBでHTTPSへリダイレクト) Rule 32767: DENY ALL # 暗黙のDENY # パブリックサブネットNACL(アウトバウンド) Rule 100: ALLOW TCP 1024-65535 to 0.0.0.0/0 # エフェメラルポート(レスポンス) Rule 200: ALLOW ALL to 10.0.0.0/8 # VPC内部通信 Rule 32767: DENY ALL # 暗黙のDENY # DBサブネットNACL(インバウンド) Rule 100: ALLOW TCP 3306 from 10.0.2.0/24 # Appサブネット(10.0.2.0/24)のみ Rule 32767: DENY ALL # 他は全てDENY # DBサブネットNACL(アウトバウンド) Rule 100: ALLOW TCP 1024-65535 to 10.0.2.0/24 # エフェメラルポートでの応答 Rule 32767: DENY ALL
「SGで許可したのに繋がらない」エラーの切り分け手順
「SGの設定は正しいはずなのに繋がらない」という状況は、多くの場合NACLの設定が原因です。以下の手順で切り分けてください。1. NACLのルールを確認する
# 問題のサブネットに紐づくNACLを確認する $ aws ec2 describe-network-acls \ --filters "Name=association.subnet-id,Values=subnet-0123456789abcdef0" \ --query 'NetworkAcls[*].Entries[?Egress==`false`].[RuleNumber,RuleAction,Protocol,PortRange.From,PortRange.To,CidrBlock]' \ --output table # インバウンドの許可ルールにアクセスしたいポートが含まれているか確認 # アウトバウンドのエフェメラルポート(1024-65535)許可があるか確認 $ aws ec2 describe-network-acls \ --filters "Name=association.subnet-id,Values=subnet-0123456789abcdef0" \ --query 'NetworkAcls[*].Entries[?Egress==`true`].[RuleNumber,RuleAction,PortRange.From,PortRange.To]' \ --output table | Rule# | Action | PortFrom | PortTo | |-------|--------|----------|--------| | 32767 | deny | None | None | # アウトバウンドが暗黙DENYのみ → エフェメラルポート許可を追加する
2. エフェメラルポート(1024~65535)の許可を追加する
# アウトバウンドにエフェメラルポート許可ルールを追加する $ aws ec2 create-network-acl-entry \ --network-acl-id acl-0123456789abcdef0 \ --no-ingress \ --rule-number 100 \ --protocol tcp \ --rule-action allow \ --cidr-block 0.0.0.0/0 \ --port-range From=1024,To=65535 # 追加後の確認 $ aws ec2 describe-network-acls \ --network-acl-ids acl-0123456789abcdef0 \ --query 'NetworkAcls[*].Entries[?Egress==`true`].[RuleNumber,RuleAction,PortRange.From,PortRange.To]' \ --output table | Rule# | Action | PortFrom | PortTo | |-------|--------|----------|--------| | 100 | allow | 1024 | 65535 | | 32767 | deny | None | None | # ルール100でエフェメラルポートが許可された
3. LinuxのポートをSSHログイン後に確認する
NACLとSGの設定を修正しても繋がらない場合、Linux側でプロセスが正常にポートをリッスンしているかを確認します。EC2インスタンスにSSHでログイン後、以下を実行してください。# Linuxで待ち受けているポートを確認する(Amazon Linux 2023 / RHEL 9.4) $ ss -tlnp State Recv-Q Send-Q Local Address:Port Peer Address:Port Process LISTEN 0 128 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1234,fd=6)) LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=888,fd=3)) # 443番ポートでNginxがリッスンしていることを確認 # ポートがリッスンしていない場合はアプリ側の問題(AWSのFW設定ではない) $ systemctl status nginx Active: active (running) since Thu 2026-07-25 10:00:00 UTC; 1h ago
本記事のまとめ
Network ACLとセキュリティグループの違いと2層防御の設計パターンをまとめます。| 比較項目 | Network ACL(NACL) | セキュリティグループ(SG) |
|---|---|---|
| 適用単位 | サブネット | ENI(インスタンス単位) |
| ステート | ステートレス(IN・OUT独立評価) | ステートフル(応答は自動許可) |
| ルール評価 | 番号順(最初にマッチで確定) | 全ルールを評価(DENYルールなし) |
| DENY設定 | 可能 | 不可(許可ルールのみ) |
| 主な用途 | サブネット境界の不審IPブロック | インスタンス間の通信制御 |
| デフォルト動作 | 全許可(新規NACL作成時は全DENY) | インバウンド全拒否・アウトバウンド全許可 |
| よくある落とし穴 | エフェメラルポートのアウトバウンド未許可 | SGチェーン参照のSG ID誤り |
VPCの基本設計についてはAWSのLinux環境構築とVPC設計入門を、マルチAZ冗長構成の詳細はAWS冗長設計パターン入門も合わせて参照してください。
Network ACLの設定方法だけでなく、AWSを「実務の型」として身につけませんか?
aws ec2 create-network-acl-entry のコマンドは調べれば分かります。でも「NACLとSGをどう組み合わせて設計するのか」「エフェメラルポートをどの範囲で開けるべきか」を、自信を持って答えられますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:AWS ACMとRoute 53でHTTPS化する方法|無料SSL証明書の発行からALB適用・自動更新まで
- この記事の属するカテゴリ:AWS(Amazon Linux)へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます