はじめに
先日、EC2インスタンスからのアウトバウンド通信を特定のドメインのみに制限したいという要件がありました。セキュリティグループやネットワークACLではIPアドレスベースの制御はできますが、ドメイン名で制限したいケースでは対応できません。
そこで、AWS Network Firewall(NWFW)を使って、EC2インスタンスからのアウトバウンド通信を「このサイトだけ許可!」という形で指定したドメインのみに制限する方法を試してみました。この記事では、実際の構築手順とともに、ハマりポイントも含めて紹介します。
構成イメージ
今回は、AWS Network Firewall Workshop で紹介されている 分散モデル (Distributed Model) を参考に構築します。
このモデルでは、各アベイラビリティゾーン (AZ) にNetwork Firewallのエンドポイントを配置し、EC2インスタンスからのアウトバウンド通信をそれぞれのAZ内のエンドポイントを経由させる構成となります。

(出典: AWS Network Firewall Workshop – Setup Network Firewall in Distributed Model)
https://catalog.workshops.aws/networkfirewall/en-US/setup/distributedmodel
構築手順
既存の検証用VPCに必要なリソースを追加・設定していきます。
1. Network Firewall用サブネットの追加
既存のVPCに、Network Firewallのエンドポイントを配置するためのパブリックサブネットを異なるAZに作成します。
- otake-test-nwfw-subnet-public1-ap-northeast-1a
- otake-test-nwfw-subnet-public2-ap-northeast-1c


2. ファイアウォールポリシー の作成
Network Firewallのルールセットを定義するポリシーを作成します。





3. Network Firewall の作成
実際にトラフィックを検査・フィルタリングするNetwork Firewallを作成します。

1で作成したNWFW用サブネットを選択


ファイアウォールポリシーは2で作成したotake-test-nwfw-policyを関連付けます。


準備完了!

指定したAZ分のエンドポイントが作成されているのがわかります

ログも有効にします。今回はCloudWatch Logsを使用します。

4. ルートテーブルの設定
EC2インスタンスからの通信がNetwork Firewallを経由するように、ルートテーブルを設定します。
既存パブリックサブネット用ルートテーブルの変更
EC2インスタンスが配置されているパブリックサブネットに関連付けられているルートテーブルを編集します。
送信先のターゲットを、同じAZにあるNetwork Firewallのエンドポイントに変更します。

ap-northeast-1c用パブリックサブネットルートテーブルの新規作成と関連付け
別AZのパブリックサブネット用に、新しいルートテーブルを作成します。
otake-test-rtb-public と同様に、送信先のターゲットを、ap-northeast-1cのNetwork Firewallのエンドポイントに設定します。
このルートテーブルを ap-northeast-1c のパブリックサブネットに関連付けます。

Network Firewall Ingress ルートテーブルの作成
Network Firewallがインターネットゲートウェイからの戻りの通信を受け取れるように、専用のルートテーブルを作成します。

作成したルートテーブルの「Edgeの関連付けを編集」から、インターネットゲートウェイ を関連付けます。



ルートの追加
- 送信先: EC2インスタンスが存在する各パブリックサブネットのCIDR、ターゲット:対応するAZのNWFWエンドポイント
- 送信先 10.0.0.0/24 (ap-northeast-1aのパブリックサブネット)、ターゲット ap-northeast-1aのNWFWエンドポイント
- 送信先 10.0.16.0/24 (ap-northeast-1cのパブリックサブネット)、ターゲット ap-northeast-1cのNWFWエンドポイント

5. Network Firewall ルールグループの作成
いよいよ、通信を許可するドメインを指定するルールグループを作成します。今回はステートレスルールグループを使用します。
- タイプ: ステートフル
- ルールグループ設定
- ステートフルルールグループ
- ドメインリスト
- アクション: 許可
- プロトコル: HTTP, HTTPS
- ドメインリスト: 許可したいドメインを指定します。今回はAmazon関連のドメインのみを許可します。
.amazon.co.jp .amazon.com .aws.amazon.com # SSM接続に必要なエンドポイントも追加 .ec2messages.ap-northeast-1.amazonaws.com .ssm.ap-northeast-1.amazonaws.com .ssmmessages.ap-northeast-1.amazonaws.com



不足があったため後にドメインを追加

作成したルールグループを、ファイアウォールポリシーのステートフルルールグループに追加します。

動作確認
設定が完了したら、EC2インスタンスにSSMなどで接続し、実際に通信が制御されているか確認します。
- 許可されていないドメインへのアクセス (Google)
NWFWによって通信がブロックされ、SSLハンドシェイク中にエラーが発生しました。想定通りの動作です。
[ec2-user@ip-10-0-4-184 ~]$ curl -v https://www.google.com/ * Host www.google.com:443 was resolved. * IPv6: 2404:6800:4004:820::2004 * IPv4: 142.251.222.36 * Trying 142.251.222.36:443... * Connected to www.google.com (142.251.222.36) port 443 * ALPN: curl offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /etc/pki/tls/certs/ca-bundle.crt * CApath: none * OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.google.com:443 * Closing connection curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.google.com:443 [ec2-user@ip-10-0-4-184 ~]$
- 許可されたドメインへのアクセス (Amazon)
許可されたドメインへのアクセスは成功しました。
[ec2-user@ip-10-0-4-184 ~]$ curl -v https://www.amazon.co.jp/ * Host www.amazon.co.jp:443 was resolved. * IPv6: 2600:9000:2142:d800:9:73fc:b895:4201, 2600:9000:2142:800:9:73fc:b895:4201, 2600:9000:2142:3a00:9:73fc:b895:4201, 2600:9000:2142:6600:9:73fc:b895:4201, 2600:9000:2142:9400:9:73fc:b895:4201, 2600:9000:2142:ea00:9:73fc:b895:4201, 2600:9000:2142:c600:9:73fc:b895:4201, 2600:9000:2142:6000:9:73fc:b895:4201 * IPv4: 3.168.249.224 * Trying 3.168.249.224:443... * Connected to www.amazon.co.jp (3.168.249.224) port 443 * ALPN: curl offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /etc/pki/tls/certs/ca-bundle.crt * CApath: none * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / RSASSA-PSS * ALPN: server accepted h2 * Server certificate: * subject: CN=www.amazon.co.jp * start date: Mar 15 00:00:00 2025 GMT * expire date: Feb 20 23:59:59 2026 GMT * subjectAltName: host "www.amazon.co.jp" matched cert's "www.amazon.co.jp" * issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2 * SSL certificate verify ok. # ... (HTMLコンテンツが表示される) ...
[ec2-user@ip-10-0-4-184 ~]$ curl -v https://www.amazon.com/
* Host www.amazon.com:443 was resolved.
* IPv6: 2600:9000:21c5:a400:7:49a5:5fd4:b121, 2600:9000:21c5:c000:7:49a5:5fd4:b121, 2600:9000:21c5:3200:7:49a5:5fd4:b121, 2600:9000:21c5:dc00:7:49a5:5fd4:b121, 2600:9000:21c5:fa00:7:49a5:5fd4:b121, 2600:9000:21c5:6e00:7:49a5:5fd4:b121, 2600:9000:21c5:ac00:7:49a5:5fd4:b121, 2600:9000:21c5:4600:7:49a5:5fd4:b121
* IPv4: 13.225.166.101
* Trying 13.225.166.101:443...
* Connected to www.amazon.com (13.225.166.101) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
* CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / RSASSA-PSS
* ALPN: server accepted h2
* Server certificate:
* subject: CN=www.amazon.com
* start date: Sep 13 00:00:00 2024 GMT
* expire date: Aug 23 23:59:59 2025 GMT
* subjectAltName: host "www.amazon.com" matched cert's "www.amazon.com"
* issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2
* SSL certificate verify ok.
# ... (HTMLコンテンツが表示される) ...
【注意】SSH接続ができなくなる場合の対処法
上記の設定を行うと、EC2インスタンスからのアウトバウンド通信はNWFWを経由するようになります。
しかし、これによりインターネット側からEC2インスタンスへのインバウンド通信ができなくなる場合があります。
これは、戻りのトラフィックがNWFWのルールによってブロックされる、またはIngressルートテーブルの設定が不十分な場合に発生します。
発生した問題:
❯ ssh -i .ssh/otake-test-key-sre3.pem ec2-user@XXXX ssh_dispatch_run_fatal: Connection to 18.183.73.107 port 22: Operation timed out
対策: SSH接続元IPを許可するステートフルルールを追加
この問題を解決するために、特定の送信元IPアドレスからの通信を明示的に許可するステートフルルールグループを作成し、ファイアウォールポリシーに追加します。
ステートフルルールは、ステートレスルールよりも先に評価(1)され、戻りの通信も自動的に許可してくれます。
(1)ファイヤーウォールポリシー作成時に、ステートレスデフォルトアクションを「ステートフルルールに転送」を選択したため
ステートフルルールグループの作成:
- ステートフル
- キャパシティ: 10
- ルールの追加 (標準ステートフルルール)
- アクション: パス
- プロトコル: TCP
- 送信元 CIDR: SSH接続元のグローバルIPアドレス/32
- 送信元ポート: 任意のポート
- 送信先: すべて(EC2インスタンス配置のサブネットCIDRも可能)
- 送信先ポート: 任意のポート
- トラフィックの方向: 転送



ファイアウォールポリシー への追加
- 作成したステートフルルールグループをファイアウォールポリシーのステートフルルールグループセクションに追加します。
- このSSH許可ルールが他のルールよりも先に評価されるように、ルールグループ内の優先度を最も高く設定することが重要です。

この設定により、指定したIPアドレスからのSSH接続は、ドメインフィルタリングの影響を受けずに許可されるようになります。
再度動作確認
SSH接続
❯ ssh -i .ssh/otake-test-key-sre3.pem ec2-user@XXXX
A newer release of "Amazon Linux" is available.
Version 2023.6.20250128:
Version 2023.6.20250203:
Version 2023.6.20250211:
Version 2023.6.20250218:
Version 2023.6.20250303:
Version 2023.6.20250317:
Version 2023.7.20250331:
Version 2023.7.20250414:
Run "/usr/bin/dnf check-release-update" for full release and version update info
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
Last login: Wed Apr 23 08:07:42 2025 from XXXX
[ec2-user@ip-10-0-4-184 ~]$
[ec2-user@ip-10-0-4-184 ~]$
指定したドメインのみ接続が可能!
Googleへは接続不可
[ec2-user@ip-10-0-4-184 ~]$ curl -v https://www.google.com * Host www.google.com:443 was resolved. * IPv6: 2404:6800:4004:818::2004 * IPv4: 142.251.42.196 * Trying 142.251.42.196:443... * Connected to www.google.com (142.251.42.196) port 443 * ALPN: curl offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /etc/pki/tls/certs/ca-bundle.crt * CApath: none * OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.google.com:443 * Closing connection curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to www.google.com:443 [ec2-user@ip-10-0-4-184 ~]$
Amazonは接続が可能!
[ec2-user@ip-10-0-4-184 ~]$ curl -v https://www.amazon.com * Host www.amazon.com:443 was resolved. * IPv6: 2600:9000:27b9:f200:7:49a5:5fd4:b121, 2600:9000:27b9:3e00:7:49a5:5fd4:b121, 2600:9000:27b9:2000:7:49a5:5fd4:b121, 2600:9000:27b9:c200:7:49a5:5fd4:b121, 2600:9000:27b9:5800:7:49a5:5fd4:b121, 2600:9000:27b9:5400:7:49a5:5fd4:b121, 2600:9000:27b9:f000:7:49a5:5fd4:b121, 2600:9000:27b9:e800:7:49a5:5fd4:b121 * IPv4: 23.62.102.143 * Trying 23.62.102.143:443... * Connected to www.amazon.com (23.62.102.143) port 443 * ALPN: curl offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /etc/pki/tls/certs/ca-bundle.crt * CApath: none * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
まとめ
AWS Network Firewall を利用することで、従来のIPアドレスベースの制御に加え、より柔軟なドメインベースでのアウトバウンド通信制御が可能になります。
「このサイトだけにアクセスさせたい」という具体的な要件も、ドメインリスト機能を使えば簡単に実現できます。
一方で、ルートテーブルの設定やルール評価順序など、理解しておくべきポイントがいくつかあります。
私自身、最初はIngressルートテーブルの設定を忘れて、戻りの通信が届かずに少し時間を費やしました。
しかし、これらを適切に設定することで、EC2インスタンスのセキュリティを大幅に向上させることができます。ぜひ、実際のセキュリティ要件に合わせて活用してみてください!