[アップデート] AWS Network Firewall のファイアウォールポリシーで Suricata IPS互換ルールの HOME_NET をオーバーライドできるようになりました

マネージドルールが使いやすくなりました
2023.05.08

マネージドルールグループのHOME_NETを設定するためにマネージドルールグループをコピーするの面倒だな

こんにちは、のんピ(@non____97)です。

皆さんはAmazon Network FirewallでマネージドルールグループのHOME_NETを設定するために、マネージドルールグループをコピーするの面倒だなと思ったことはありますか? 私はあります。

Network FirewallでSuricata互換のIPSルールを一から自分で定義するのは中々大変です。そのような場合は、マネージドのSuricata互換のIPSルールであるAWS Managed Threat Signaturesを使うことで負荷の軽減ができます。

ただし、こちらのマネージドなルールグループはルール変数を自ら定義することができません。

ルールグループ内で使用される、自ネットワークを示す時に使用される変数HOME_NETはデフォルトではNetwork Firewallが配置されているVPCのCIDRとなります。

To use domain name filtering for traffic from outside the VPC where you've deployed Network Firewall, you must manually set the HOME_NET variable for the rule group. The most common use case for this is a central firewall VPC with traffic coming from other VPCs through a transit gateway.

By default, domain list inspection uses a HOME_NET that is set to the CIDR range of the VPC where Network Firewall is deployed. Only traffic from that range is passed through the domain list filtering. To filter traffic from outside the deployment VPC, you must provide a HOME_NET setting that includes the other CIDR ranges that you want to inspect, along with the CIDR range of the VPC where Network Firewall is deployed.

(以下機械翻訳)

Network Firewall を導入した VPC の外部からのトラフィックに対してドメイン名フィルタリングを使用するには、ルールグループの HOME_NET 変数を手動で設定する必要があります。最も一般的な使用例は、セントラルファイアウォールのVPCで、他のVPCからトランジットゲートウェイを経由してくるトラフィックです。

デフォルトでは、ドメインリスト検査は、Network Firewallが配置されているVPCのCIDR範囲に設定されたHOME_NETを使用します。その範囲からのトラフィックのみが、ドメインリスト検査に通過します。展開VPC外からのトラフィックをフィルタリングするには、Network Firewallが展開されているVPCのCIDR範囲に加えて、検査したい他のCIDR範囲を含むHOME_NET設定を提供する必要があります。

Stateful domain list rule groups in AWS Network Firewall - AWS Network Firewall

Network Firewallを以下AWS公式ブログで紹介しているような1つのVPCに集約している場合はHOME_NETをNetwork FirewallのVPCと接続しているVPCのCIDRを設定したいところです。

しかし、先述の制限があるためマネージドルールグループを使うためには、マネージドルールグループをコピーしてHOME_NETを設定してあげる必要がありました。

今回、アップデートによりAWS Network Firewall のファイアウォールポリシーで Suricata IPS互換ルールのHOME_NETをオーバーライドできるようになりました

API Referenceを確認すると、PolicyVariablesというData Typeも増えていました。

これにより先述の問題が解消されました。

試してみたので紹介します。

いきなりまとめ

  • ポリシー変数でHOME_NETをオーバーライドできるようになった
    • マネージドルールのHOME_NETをカスタマイズしたいがために、マネージドルールのコピーを行う必要がなくなった
  • ポリシー変数とルール変数どちらもHOME_NETをオーバーライドしている場合、ルール変数の値が優先される
  • ポリシー変数のオーバーライドをするタイミングでダウンタイムが発生する

やってみた

検証環境

検証環境は以下の通りです。

AWS Network Firewall のファイアウォールポリシーで Suricata IPS互換ルールの HOME_NET をオーバーライドできるようになりました検証環境構成図

Network FirewallではHOME_NETからdev.classmethod.jpへのHTTPの通信をドロップするようなSuricata互換IPSルールを定義しています。

drop http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:"dev.classmethod.jp"; endswith; msg:"Allowed HTTP domain"; sid:892120; rev:1;)

Spoke VPC上のEC2インスタンスにSSMセッションマネージャーで接続し、curl でdev.classmethod.jpへのHTTPの通信をしてみます。そして、ルール変数やポリシー変数の設定に応じてドロップされるのかを確認します。

全てのリソースはAWS CDKでデプロイしています。使用したコードは以下リポジトリに保存しています。

ルール変数でHOME_NETをオーバーライド

まず、本題のアップデートを紹介する前に、ルール変数であってもHOME_NETをオーバーライドできることを確認します。

と、その前にHOME_NETはデフォルトではNetwork Firewallが配置されているVPCのCIDRであることを確認します。

EC2インスタンスからdev.classmethod.jpへHTTPの通信をしようとしてみます。

$ curl -I -m5 http://dev.classmethod.jp
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Mon, 08 May 2023 04:40:04 GMT
Content-Type: text/html
Content-Length: 134
Connection: keep-alive
Location: https://dev.classmethod.jp:443/

Suricata互換のIPSルールにマッチするのであればタイムアウトするところが、タイムアウトせずにステータスコード301が返ってきましたね。

このことから、確かにNetwork Firewallを1つのVPCに集約している場合はHOME_NETをNetwork FirewallのVPCと接続しているVPCのCIDRを設定する必要があることが分かります。

それではルール変数の設定を行い、通信がドロップされることを確認します。

ルールグループのルール変数の編集をクリックします。

ルール変数の編集

IPセット変数でHOME_NET10.0.0.0/8となるように定義します。

ルール変数の編集2

この状態でEC2インスタンスからdev.classmethod.jpへHTTPの通信をしようとしてみます。

$ curl -I -m5 http://dev.classmethod.jp
curl: (28) Operation timed out after 5000 milliseconds with 0 bytes received

今度はタイムアウトになりましたね。

Network Firewallのログを確認すると、確かに設定したSuricata互換のIPSルールでドロップしていることが分かります。

{
    "firewall_name": "network-firewall",
    "availability_zone": "us-east-1a",
    "event_timestamp": "1683521005",
    "event": {
        "tx_id": 0,
        "app_proto": "http",
        "src_ip": "10.0.2.7",
        "src_port": 35508,
        "event_type": "alert",
        "alert": {
            "severity": 3,
            "signature_id": 892120,
            "rev": 1,
            "signature": "Allowed HTTP domain",
            "action": "blocked",
            "category": ""
        },
        "flow_id": 460961625234767,
        "dest_ip": "13.248.175.13",
        "proto": "TCP",
        "http": {
            "hostname": "dev.classmethod.jp",
            "url": "/",
            "http_user_agent": "curl/7.88.1",
            "http_method": "HEAD",
            "protocol": "HTTP/1.1",
            "length": 0
        },
        "dest_port": 80,
        "timestamp": "2023-05-08T04:43:25.231126+0000"
    }
}

ルール変数でHOME_NETをオーバーライド × ポリシー変数でHOME_NETをオーバーライド

加えてポリシー変数でもHOME_NETをオーバーライドします。

ポリシー変数でHOME_NETをオーバーライドする際はファイアウォールポリシーの詳細タブからPolicy variablesの編集から行います。

Policy variablesの編集

HOME_NETをオーバーライドしたい値を入力して保存をクリックします。今回は10.0.1.0/24としました。

Policy variablesの編集2

設定が完了したことを確認します。

HOME_NET 変数のオーバーライド値の確認

この後、EC2インスタンスからdev.classmethod.jpへHTTPの通信をしようとしてみます。

$ curl -I -m5 http://dev.classmethod.jp
curl: (28) Operation timed out after 5001 milliseconds with 0 bytes received

タイムアウトしてしまいました。

時間を置いてチャレンジしてみましたが、結果は変わらずでした。

ルール変数とポリシー変数の両方を指定している場合ルール変数が優先されるようですね。

ポリシー変数でHOME_NETをオーバーライド

次にポリシー変数でのみHOME_NETをオーバーライドするパターンを試します。

ルール変数は削除しておきます。

ルールグループからルール変数を削除

ポリシー変数の設定が反映されたことが分かりやすいよう、このタイミングでもEC2インスタンスからdev.classmethod.jpへHTTPの通信をしようとしてみます。

$ curl -I -m5 http://dev.classmethod.jp
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Mon, 08 May 2023 04:55:00 GMT
Content-Type: text/html
Content-Length: 134
Connection: keep-alive
Location: https://dev.classmethod.jp:443/

通信できるようになりましたね。

それでは、ポリシー変数を設定します。ポリシー変数は10.0.0.0/8としました。

HOME_NET 変数のオーバーライド値を変更

ポリシー変数を設定変更すると、3分弱ほどSSMセッションマネージャーからEC2インスタンスの操作を受け付けなくなりました。

もしかすると、ポリシー変数変更時にはダウンタイムがあるのかも知れません。

最初にポリシー変数を設定した際にはこちらの事象は発生しませんでした。しかし、その時は10.0.1.0/24とNetwork Firewallが存在するVPCと同じCIDRを指定しました。そのため、内部的にポリシー変数をオーバーライドする必要がないと判断し、ダウンタイムが発生しなかったのではと推測します。

しばらくするとSSMセッションマネージャーでEC2インスタンスに接続できるようになりました。

この状態でEC2インスタンスからdev.classmethod.jpへHTTPの通信をしようとしてみます。

$ curl -I -m5 http://dev.classmethod.jp
curl: (28) Operation timed out after 5000 milliseconds with 0 bytes received

タイムアウトとなりました。ポリシー変数によるHOME_NETのオーバーライドがしっかり効いていることが分かります。

ポリシー変数でHOME_NETをオーバーライドするタイミングで本当にダウンタイムが発生するのか確認

最後にポリシー変数でHOME_NETをオーバーライドするタイミングで本当にダウンタイムが発生するのかを確認します。

5秒間隔でpingを叩くsystemd-timerを作成し、ポリシー変数でHOME_NETをオーバーライドするタイミングで通診断が発生しているのかチェックします。

# serviceの作成
$ sudo tee /etc/systemd/system/ping-test.service << EOF > /dev/null
[Unit]
Description=ping test

[Service]
User=ec2-user
Group=ec2-user
Type=oneshot

ExecStart=/usr/bin/ping -c 1 -q 1.1.1.1

[Install]
WantedBy=multi-user.target
EOF

# timerの作成
$ sudo tee /etc/systemd/system/ping-test.timer << EOF > /dev/null
[Unit]
Description=Runs every 5 seconds

[Timer]
OnBootSec=10s
OnUnitActiveSec=10s
AccuracySec=100ms

[Install]
WantedBy=timers.target
EOF

# timerの起動
$ sudo systemctl start ping-test.timer

# timserが起動していることを確認
$ systemctl status ping-test.timer
● ping-test.timer - Runs every 5 seconds
     Loaded: loaded (/etc/systemd/system/ping-test.timer; disabled; preset: disabled)
     Active: active (running) since Mon 2023-05-08 06:14:17 UTC; 27ms ago
      Until: Mon 2023-05-08 06:14:17 UTC; 27ms ago
    Trigger: n/a
   Triggers: ● ping-test.service

May 08 06:14:17 ip-10-0-2-7.ec2.internal systemd[1]: Started ping-test.timer - Runs every 5 seconds.

この状態でポリシー変数を10.0.2.0/24に変更します。

$ journalctl -u ping-test -n 30 -S "May 08 06:14:49"
May 08 06:14:58 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 06:15:08 ip-10-0-2-7.ec2.internal ping[8911]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 06:15:08 ip-10-0-2-7.ec2.internal ping[8911]: --- 1.1.1.1 ping statistics ---
May 08 06:15:08 ip-10-0-2-7.ec2.internal ping[8911]: 1 packets transmitted, 0 received, 100% packet loss, time 0ms
May 08 06:15:08 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Main process exited, code=exited, status=1/FAILURE
May 08 06:15:08 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Failed with result 'exit-code'.
May 08 06:15:08 ip-10-0-2-7.ec2.internal systemd[1]: Failed to start ping-test.service - ping test.
May 08 06:15:08 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 06:15:08 ip-10-0-2-7.ec2.internal ping[8915]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 06:15:08 ip-10-0-2-7.ec2.internal ping[8915]: --- 1.1.1.1 ping statistics ---
May 08 06:15:08 ip-10-0-2-7.ec2.internal ping[8915]: 1 packets transmitted, 1 received, 0% packet loss, time 0ms
May 08 06:15:08 ip-10-0-2-7.ec2.internal ping[8915]: rtt min/avg/max/mdev = 4.004/4.004/4.004/0.000 ms
May 08 06:15:08 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Deactivated successfully.
May 08 06:15:08 ip-10-0-2-7.ec2.internal systemd[1]: Finished ping-test.service - ping test.
May 08 06:15:18 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 06:15:18 ip-10-0-2-7.ec2.internal ping[8917]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 06:15:18 ip-10-0-2-7.ec2.internal ping[8917]: --- 1.1.1.1 ping statistics ---
May 08 06:15:18 ip-10-0-2-7.ec2.internal ping[8917]: 1 packets transmitted, 1 received, 0% packet loss, time 0ms
May 08 06:15:18 ip-10-0-2-7.ec2.internal ping[8917]: rtt min/avg/max/mdev = 4.408/4.408/4.408/0.000 ms
May 08 06:15:18 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Deactivated successfully.
May 08 06:15:18 ip-10-0-2-7.ec2.internal systemd[1]: Finished ping-test.service - ping test.
May 08 06:15:28 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 06:15:28 ip-10-0-2-7.ec2.internal ping[8972]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 06:15:28 ip-10-0-2-7.ec2.internal ping[8972]: --- 1.1.1.1 ping statistics ---
May 08 06:15:28 ip-10-0-2-7.ec2.internal ping[8972]: 1 packets transmitted, 1 received, 0% packet loss, time 0ms
May 08 06:15:28 ip-10-0-2-7.ec2.internal ping[8972]: rtt min/avg/max/mdev = 4.369/4.369/4.369/0.000 ms
May 08 06:15:28 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Deactivated successfully.
May 08 06:15:28 ip-10-0-2-7.ec2.internal systemd[1]: Finished ping-test.service - ping test.
May 08 06:15:38 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 06:15:38 ip-10-0-2-7.ec2.internal ping[8974]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.

ポリシー変数を変更して10秒後に一回だけ到達しなかったようです。

たまたまかな? と思い、ポリシー変数を10.0.2.0/24から10.0.1.0/24に変更しましたが、やはり到達できないタイミングがありました。

$ journalctl -u ping-test -n 30 -S "May 08 07:21:22"
May 08 07:21:30 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 07:21:30 ip-10-0-2-7.ec2.internal ping[12853]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 07:21:30 ip-10-0-2-7.ec2.internal ping[12853]: --- 1.1.1.1 ping statistics ---
May 08 07:21:30 ip-10-0-2-7.ec2.internal ping[12853]: 1 packets transmitted, 1 received, 0% packet loss, time 0ms
May 08 07:21:30 ip-10-0-2-7.ec2.internal ping[12853]: rtt min/avg/max/mdev = 4.529/4.529/4.529/0.000 ms
May 08 07:21:30 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Deactivated successfully.
May 08 07:21:30 ip-10-0-2-7.ec2.internal systemd[1]: Finished ping-test.service - ping test.
May 08 07:21:40 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 07:21:50 ip-10-0-2-7.ec2.internal ping[12854]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 07:21:50 ip-10-0-2-7.ec2.internal ping[12854]: --- 1.1.1.1 ping statistics ---
May 08 07:21:50 ip-10-0-2-7.ec2.internal ping[12854]: 1 packets transmitted, 0 received, 100% packet loss, time 0ms
May 08 07:21:50 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Main process exited, code=exited, status=1/FAILURE
May 08 07:21:50 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Failed with result 'exit-code'.
May 08 07:21:50 ip-10-0-2-7.ec2.internal systemd[1]: Failed to start ping-test.service - ping test.
May 08 07:21:50 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 07:21:50 ip-10-0-2-7.ec2.internal ping[12855]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 07:21:50 ip-10-0-2-7.ec2.internal ping[12855]: --- 1.1.1.1 ping statistics ---
May 08 07:21:50 ip-10-0-2-7.ec2.internal ping[12855]: 1 packets transmitted, 1 received, 0% packet loss, time 0ms
May 08 07:21:50 ip-10-0-2-7.ec2.internal ping[12855]: rtt min/avg/max/mdev = 4.472/4.472/4.472/0.000 ms
May 08 07:21:50 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Deactivated successfully.
May 08 07:21:50 ip-10-0-2-7.ec2.internal systemd[1]: Finished ping-test.service - ping test.
May 08 07:22:00 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 07:22:00 ip-10-0-2-7.ec2.internal ping[12856]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
May 08 07:22:00 ip-10-0-2-7.ec2.internal ping[12856]: --- 1.1.1.1 ping statistics ---
May 08 07:22:00 ip-10-0-2-7.ec2.internal ping[12856]: 1 packets transmitted, 1 received, 0% packet loss, time 0ms
May 08 07:22:00 ip-10-0-2-7.ec2.internal ping[12856]: rtt min/avg/max/mdev = 11.568/11.568/11.568/0.000 ms
May 08 07:22:00 ip-10-0-2-7.ec2.internal systemd[1]: ping-test.service: Deactivated successfully.
May 08 07:22:00 ip-10-0-2-7.ec2.internal systemd[1]: Finished ping-test.service - ping test.
May 08 07:22:10 ip-10-0-2-7.ec2.internal systemd[1]: Starting ping-test.service - ping test...
May 08 07:22:10 ip-10-0-2-7.ec2.internal ping[12858]: PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.

ダウンタイムはありそうですね。

ポリシー変数を変更する場合はネットワークトラフィックが控えめなタイミングで行うのが吉ですね。

具体的にはCloudWatchでReceivedPacketsの値が低いタイミングを確認することになります。

マネージドルールが使いやすくなりました

AWS Network Firewall のファイアウォールポリシーで Suricata IPS互換ルールのHOME_NETをオーバーライドできるようになったアップデートを紹介しました。

これでまた一つマネージドルールが使いやすくなりましたね。

また、マネージドルールを使っていない場面でも、複数のSuricata互換のルールグループがある時に各ルールグループでHOME_NETを定義する必要がなくなりそうです。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!