AWSの新サービス「AWS Network Firewall」を早速使ってみた

# はじめに
2020/11/17のアップデートで**「AWS Network Firewall」**という新しいサービスが登場しました。
本記事ではこのサービスの特徴について調べ、使い所を検討してみました。

# これまでのサービスとは
これまで、AWSで外部からのアクセス制御・保護と言えば以下のサービスがありました。

* Amazon Elastic Compute Cloud （EC2） インスタンスレベルでアクセス制御する**Security Group**
* Amazon Virtual Private Cloud （VPC） のサブネットレベルでアクセス制御する**Network ACL**
* Amazon CloudFront、Application Load Balancer （ALB）、Amazon API Gatewayで実行されているWebアプリケーションを保護する**AWS Web Application Firewall （WAF）**
* 分散サービス拒否（DDoS）攻撃から保護する**AWS Shield**

# AWS Network Firewallとは
新たに登場した「AWS Network Firewall」では、AWS上の仮想ネットワークを保護するために、**ステートフルインスペクション**、**侵入防止・検知**、**Webフィルタリング**を簡単に導入・管理できます。
また「AWS Network Firewall」は、トラフィック量に応じて自動的にスケーリングし、高可用性のあるアクセス制御・保護機能となります。

## 特に、新たにできること
「AWS Network Firewall」では、以下の事が可能となります。

* VPCが不正なドメインにアクセスしないようにカスタマイズしたルールを実装
* 数千もの既知の悪意のあるIPアドレスをブロックしたり、シグネチャベースの検出機能を使って悪意のあるアクティビティを特定
* CloudWatchのメトリクスを介してファイアウォールのアクティビティをリアルタイムで可視化し、ログをS3、CloudWatch、Kinesis Firehoseに送信することでネットワークトラフィックの可視性を向上
* AWS Firewall Managerと統合されているため、AWS Organizationsを利用していれば、すべてのVPCとAWSアカウントのファイアウォールアクティビティを単一の場所で有効化し、監視
* Network Firewallは、CrowdStrike、Palo Alto Networks、Splunkなどの既存のサードパーティ製セキュリティ製品との相互運用が可能
    * コミュニティで管理されているSuricataのルールセットから既存のルールをインポート可能

## 基本的な考え方
VPCで、AZごとにFirewallを使用し、各AZでトラフィックをフィルタリングするための**Firewall Endpoint**を起動するサブネットを選択します。
AZ内のFirewall Endpointは、そのサブネットを除く、AZ内のすべてのサブネットを保護できます。

AWS Network Firewallは以下の3つの要素で成り立っています。

* **Firewall**
    * 保護したいVPCをFirewall Policyで定義された動作にアタッチします。
    * 保護したい各AZに対して、Firewall Endpoint専用の**パブリックサブネット**をNetwork Firewall用に構築します。
    * Firewallを使用するには、Route Tableを更新して、Firewall Endpoint経由でInboundとOutboundトラフィックを送信するようにします。

* **Firewall Policy**
    * **ステートレス**と**ステートフル**のRule Groupやその他の設定の集合体
    * Firewallの動作を定義
    * 各Firewallを1つのFirewall Policyにアタッチしたり、1つのFirewall Policyを複数のFirewallにアタッチすることが可能

* **Rule Group**
    * ネットワークトラフィックの検査と処理方法を定義するステートレスまたはステートフルなルールの集合
    * ルール設定には、5-tuple (送信元IP、送信元ポート番号、宛先IP、宛先ポート番号、プロトコル番号)と**ドメイン名によるフィルタリングを含む**
    * Suricataのオープンソースのルールセットを使用することによるステートフルルールも定義可能

# AWS Network Firewall経由で外部から接続できるように構成変更する
記事執筆(2020/11/18)時点では東京リージョンには登場していません。
バージニア北部リージョンで試していきます。

## 前提1: 前提環境の用意
まずはインターネット経由でElastic IPを宛先にして、直接SSHとHTTPで接続できるEC2を用意します。
ここから検証のスタートです。
※記事を公開した時点で、Elastic IPをリリースしております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/33cfdf90-2499-1dd7-ca9e-990266def2e4.png)
クライアントから、Elastic IP宛にHTTPで接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/413e131e-e72c-7a5f-17e3-359e8481955c.png)
この時のVPC Flow Logsは以下の通りで、クライアントのGlobal IPから、EC2のPrivate IPに80番ポートで接続され、戻りの通信が発生しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/c7db1c7f-27e0-5148-dac4-04ea26d5415c.png)
この接続を、AWS Network Firewallを経由してもパスすることを目指してみます。

## 前提2: 目指す構成
目指す構成は、クライアントとWebサーバの間にAWS Network Firewallが挟まったとしても接続を維持できる状態とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/ff1a788f-bdc9-5d05-a666-965d1cb2a61f.png)

## 手順1: Firewall用サブネットの作成
作るだけなので割愛します。

## 手順2: Firewallの作成
手順1で作ったサブネット上に、まずFirewallを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/e340c467-d0d5-1e68-b8d2-6f8dd7c4b652.png)
一緒に空のFirewall Policyを作っておきます。
ここまで入力して「ファイアウォールの作成」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/d51f2a51-8eb2-7f66-4614-4be3d483b271.png)
ここまでで、FirewallとFirewall Policyのプロビジョニングが開始されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/1e1584b9-338b-0091-8e4d-fba6843dc6df.png)
プロビジョニングには少々の時間がかかります。
完了すると以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/0e5cf272-afc6-d5f7-de6f-889c13f7d8f6.png)
Firewallがプロビジョニングされると、Firewallに接続するためのFirewall Endpointが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/514cc268-4c08-a5d4-ae59-a8795755c606.png)

## 手順3: Firewall PolicyのRule Groupを設定
判定順はステートレスルール→ステートフルルールの順番です。
今回はステートレスルールだけを設定します。
まずはInboundのHTTP通信をパスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/9522d412-f306-085d-2d05-8d4239b0d7db.png)
パスさせたいので、アクションには「パス」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/1f1f7c4d-7c0d-ce31-0a23-186806e2cc68.png)
戻りのOutboundも同じようにパスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/6ac3f848-68d4-c02e-aa4d-437e16c50e8d.png)
ルールの登録が以下の状態になったところで「作成と追加」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/0f3623af-ffca-70c7-4bb6-a2fc695ed2ef.png)
また、ステートレスルールに合致しなかったアクションの取り扱いを決めておきます。
今回は「ドロップする」にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/5632b594-bc7b-4009-7214-c2812baee9ae.png)

## 手順4: Firewallのログ記録を有効化する
Firewallで「ログ記録」を有効化しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/4d1ef9ff-5da3-5402-e475-df5ca91b3402.png)

## 手順5: Gateway Route Tableの作成とInternet Gatewayへのアタッチ
トラフィックがInternet Gatewayを通過する時に、Firewall Endpointを経由させるために、Internet GatewayにRoute Tableをアタッチします。
以下の画面の「Edge Associations」を編集します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/61d0cfbb-e58d-ef6c-71ab-07828de47803.png)
既に作られているIGWに、Route Tableを関連付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/f3251f46-5bb8-f414-2e78-b5b03f7c3129.png)
ルートには、今回の例でWebサーバが存在する10.0.0.0/24宛のアクセスがFirewall経由になるように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/483d980c-f8dd-6a89-24b0-f1aff14981f6.png)

## 手順6: Subnet Route Tableの変更
サブネットにアタッチされているRoute Tableの設定を変更し、通信経路を変えます。

Firewallが存在する10.0.1.0/24のサブネットにアタッチされているRoute Tableは以下となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/61731c6d-1329-5565-2d85-7db722467f38.png)

Webサーバが存在する10.0.0.0/24のサブネットにアタッチされているRoute Tableは以下となります。
デフォルトゲートウェイが、IGWからFirewall Endpointに変わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/a2748cd4-8ad2-ab6b-bee8-2783b93dcdf9.png)

ここまでの作業で**「序章2: 目指す構成」**の通りとなりました。

## 検証1: HTTP接続前のモニタリング
既にFirewall経由の通信が通る状況となっているため、このタイミングでモニタリングしてみると、許可されているHTTP以外の通信は軒並みドロップされていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/7f36b99d-7824-1e6e-cc23-28866a75618c.png)

## 検証2: クライアントからの接続確認
この状態で、Firewall Policyで許可したHTTP接続が通ることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/a94f2ce7-15f7-31de-1196-517dcd729414.png)
次に、許可していないSSH接続を試みると、接続できません。

```bash
$ ssh -i web.pem ec2-user@18.211.147.155
ssh: connect to host 18.211.147.155 port 22: Operation timed out
```

以上の検証により、AWS Network Firewallを挟んでWebサーバ用EC2にHTTP接続でき、許可していない通信が期待通りドロップされていることが分かりました。

# ルール評価の検証
検証2の状態から設定を変更して、ルール評価について検証してみました。

## 検証3: 検証2の状態でステートレスルールを片方向だけ消すとどうなるか
ステートレスルールからInboundまたはOutboundのいずれか片方向のルールを消したところ、接続できなくなりました。
ステートレスだけに、**Network ACLと同じく戻りの通信を許可する必要があると言えます。**

## 検証4: 検証2の状態でステートレスデフォルトアクションを「ステートフルルールグループに転送」と変更するとどうなるか
検証2の状態では、許可されている通信はHTTPのみであり、その他の通信、例えばSSHは許可されていません。
この状態で、手順3で「ドロップ」としていたステートレスデフォルトアクションを「ステートフルルールグループに転送」と変更するとどうなるのか試してみました。

以下のように変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/73d15762-0f68-b4a5-4e38-91764f800e0d.png)
転送先のステートフルルールグループはまだ設定されていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/116cd318-2824-0cba-9d1c-6b3215e05fe7.png)
変更後、SSHで接続してみると、**接続できてしまいました。**

## ルール評価の検証まとめ
これまでの検証から分かることとしては、以下となります。

* ステートレスルールに合致するかどうかが、まず優先度順で評価される
    * ステートレスルールは戻りの通信の許可も必要
    * 行きの通信と戻りの通信それぞれの評価時点で、条件に一致した場合の「ステートフルルールグループに転送」ができ、複合的に評価可能
* いずれのステートレスルールにも合致しない場合 (1つもルールが設定されていない場合を含む) のアクションが3種類設定可能
    * 「パス」とした場合、アクセス許可して終了
    * 「ドロップ」とした場合、アクセス拒否して終了 ※検証2のSSH
    * 「ステートフルルールグループに転送」とした場合、ステートフルルールグループの評価に移る
* ステートフルルールグループは、**デフォルトが許可**となっている
    * ステートフルルールグループが空の状態では、転送されてきた場合に「パス」と同じ動きとなる ※検証4
    * ステートフルルールグループにDenyルールを追加することで、不要なアクセスを拒否することが可能
        * ただし、いずれのステートフルルールにも合致しない場合は「パス」される

![rule](https://docs.aws.amazon.com/network-firewall/latest/developerguide/images/firewall-stateless-stateful.png)
引用: https://docs.aws.amazon.com/network-firewall/latest/developerguide/firewall-rules-engines.html

# まとめ
「AWS Network Firewall」では、これまでのNetwork ACLやSecurity Groupに比べ、さらに細かい制御が可能となっています。
また、ステートフルルールで**ドメイン名でのアクセス拒否**が可能となるため、ブラックリスト型のプロキシとしての用途も考えられます。
マネージド型プロキシと考えれば、ありがたい存在となりそうです。
ただし、ステートレスルールとステートフルルールを併用して使う際は、前述の通りルール評価には注意が必要となります。
片方だけ使うという手もあるでしょうから、まずは少しずつ検証してみるのが良さそうです。

# 参考文献
* [AWS Network Firewall](https://docs.aws.amazon.com/network-firewall/latest/developerguide/what-is-aws-network-firewall.html) 
* [AWS Network Firewall – New Managed Firewall Service in VPC](https://aws.amazon.com/jp/blogs/aws/aws-network-firewall-new-managed-firewall-service-in-vpc/)