🔥

AWS Network Firewall でステートフルデフォルトアクションを活用して暗黙の Deny を実現する

2021/10/20に公開

https://aws.amazon.com/jp/about-aws/whats-new/2021/10/aws-firewall-configuration-rule-ordering-drop/

いつの間にかリリースされていたようで、Suricata 互換 IPS ルールを用いる事で簡単に実現できるようになってました。ようやくか~、と思ったりしますがとりあえず嬉しいアップデートです。

様子を見てみる

マネジメントコンソールから AWS Network Firewall を選び、既存のファイアウォールリソースを開いてみると……

ありました! では編集を……と思ったら編集ボタンがグレーアウトしてますね。

まだ東京リージョンでは使えない?
いえ、そんな事ありません。

どうやら、当該項目を利用するためには新規でファイアウォールポリシーを作成する必要があるようです。新規でファイアウォールポリシーを作って、ファイアウォールにアタッチしてみましょう。

編集できるようになりました。一安心。

https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-rule-evaluation-order.html#suricata-default-rule-evaluation-order

の資料の通り、Strict evaluation order として 4 つのアクションをデフォルトアクションとして選べるようです。

今回の目的は暗黙の Deny を実現する事なので、とりあえず すべてをドロップ(Drop all) を選択しました。

暗黙の Deny を実現できるかな

https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-examples.html

ドキュメントの通り、Managing rule evaluation order を参考にして Suricata 互換 IPS ルールグループを作成していきます。

今回は特定の Web サイトにアクセスできるようにドメインを見て通信を許可するようにルールを作成しました。

pass http $HOME_NET any -> $EXTERNAL_NET 80 (http.host; dotprefix; content:".hinatazaka46.com"; endswith; msg:"Allowed HTTP domain"; sid:1; rev:1;)
pass tls $HOME_NET any -> $EXTERNAL_NET 443 (tls.sni; dotprefix; content:".hinatazaka46.com"; endswith; msg:"Allowed HTTP domain"; sid:2; rev:1;)
pass tcp 自宅環境 IP アドレス any -> $HOME_NET 22 (msg:"Allow TCP 22 to Private Subnet from specified IP addr"; sid:3; rev:1;)
pass tcp $HOME_NET any <> $EXTERNAL_NET 80 (flow:not_established; sid:4; rev:1;)
pass tcp $HOME_NET any <> $EXTERNAL_NET 443 (flow:not_established; sid:5; rev:1;)

1 行目、2 行目共に同様のドメインに対する制御ではありますが、プロトコル別にルールを記載しています。
1 行目の HTTP では HTTP の Host ヘッダを見て、content 内のドメインかどうか検査します。
2 行目の HTTPS では TLS の SNI フィールドを見て content 内のドメインかどうか検査します。
3 行目は動作確認用に Private Subnet に用意した EC2 インスタンスへ SSH するためのルールを書いてあります。通信方向は記載の通り、自宅 -> $HOME_NET(つまり VPC CIDR) の流れです。

4 行目と 5 行目が肝で、超重要です。
今回ステートフルのデフォルトアクションで すべてをドロップ(Drop all) を選択しています。
HTTP や HTTPS の通信であるのかは TCP 接続確立後に判明しますので、つまり TCP ハンドシェイク前には判断できません。
https://suricata.readthedocs.io/en/suricata-5.0.2/rules/flow-keywords.html#flow

つまり、pass http 及び pass tls をしていても、デフォルトアクションで先に TCP Handshake のパケットが落とされてしまう事で、意図した動作になりません。
https://docs.aws.amazon.com/ja_jp/network-firewall/latest/developerguide/suricata-rule-evaluation-order.html

The protocol layer does not impact the rule evaluation order by default. If you want to avoid matching against lower-level protocol packets before higher-level application protocols can be identified, consider using the flow keyword in your rules. This is needed because, for example, a TCP rule might match on the first packet of a TCP handshake before the stateful engine can identify the application protocol.

それを補うのが 4 行目と 5 行目です。TCP プロトコルかつ 80・443 ポートの通信で、接続確立されていないものを許可しています。
4 行目、5 行目のルールのおかげで TCP Handshake までは通りますが、TCP Handshake 完了後、つまり TCP 接続確立後の通信はこのルールの対象外です。そのため、TCP 接続確立後、HTTP 及び HTTPS の通信であれば 1 行目、2 行目が検査を行い、それ以外の TCP の通信であればデフォルトアクションに沿って全てドロップされる、という事です。

従って、上記ルール群のいずれにもマッチしなければデフォルトアクションが実施されるということで、簡単に暗黙の Deny を実現する事ができました。

なお、ドメインリストルールグループ単体で上記はできないの? と思う方もいると思いますが、2021年10月20日現在で、Strict evaluation order を変更したファイアウォールポリシーではドメインリストルールグループを適用できないようでしたので、まだ実現できなさそうです。

Discussion