Azure Application Gateway のレート制限

Application Gateway のレート制限が GA (2023/11/09) ~~パブリックプレビュー (2023/08/22)~~ となりました。Azure Front Door の WAF では以前からサポートされてましたが、Application Gateway でも利用可能になったことで、オンプレからプライベート IP アドレスで Azure にアクセスするようなシナリオにおいても、特定の IP アドレスやヘッダー単位でリクエスト数の上限を設けられるようになります。
実際に試して設定方法や留意点等をまとめておりますので、ご利用の際はご一読いただけたら幸いです。

https://azure.microsoft.com/ja-jp/updates/public-preview-ratelimit-rules-for-application-gateway-web-application-firewall/

## 構成

同じ VNet 内のクライアントから Application Gateway V2 (WAF ポリシーあり) 経由で Web サーバーへアクセスし、レート制限の検証を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/0ecc4a65-b360-3a6f-062f-4b05190cea02.png)

## 前提

- Application Gateway v2 がデプロイ済みであること
- リスナーがプライベート IP アドレスで構成されていること
- バックエンドの VM の Web サーバーに Application Gateway の経由でアクセス可能であること

## レート制限の有効化
Application Gateway のレート制限は Web Application Firewall (WAF) ポリシーの機能を使って実現しております。 WAF ポリシーはリソースを新規作成してから、Application Gateway に関連付けすることもできますが、
Application Gateway の画面からレベル (SKU) を WAF V2 に変更し、WAF ポリシーの作成・関連付けを行うこともできるようになっております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/7e8a30e7-78e9-6d46-909e-f4096c263c7d.png)

WAF ポリシーの作成・関連付けを行ったら、WAF ポリシーのリソースをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/787e852a-a009-fd40-5557-61c2b97034d8.png)

レート制限は最新の WAF エンジン (CRS 3.2) のみでサポートされているため、CRS のバージョンを 3.2 に変更します。(**※現状、CRS 3.2 から他のバージョンへのダウングレードはサポートリクエストでの対応が必要です**)
WAF ポリシーの "管理されているルール" > "割り当てる" > "既定のルールセット" から OWASP_3.2 を選択し、保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/a0cb826c-06dc-7d62-2796-8f0239817750.png)

https://learn.microsoft.com/ja-jp/azure/web-application-firewall/ag/rate-limiting-overview#rate-limiting-policies

:::note warn
レート制限規則は、最新の WAF エンジンを実行している Web アプリケーション ファイアウォールでのみサポートされます。 最新のエンジンを使用するには、既定の規則セットに CRS 3.2 を選択します。
:::

カスタムルールにてレート制限のルールを以下のようなパラメーターで作成します。

| 項目 | 設定値 | 備考 |
|-|-|-|
| カスタムルール名  | ratelimit1 |
| ルールを有効にする  | 有効 |
| ルールの種類  | レート制限 |
| 優先度  | 3 | 1-100 で指定。数字が小さいほど優先される。|
| レート制限の期間  | 1 分 | レート制限を評価する時間。1 分または 5 分を指定可能 |
| レート制限のしきい値 (要求数) | 5 | 期間内のリクエスト数の閾値 |
| トラフィックのレート制限の基準となるグループ  | クライアントアドレス | クライアントアドレス/Geo/なし から選択可能　※詳細は後述|
| 一致の種類  | IP アドレス |
| IP アドレスまたは範囲  | 10.20.1.4 |
| 結果 | トラフィックを拒否する |


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/8438a640-df3f-1d28-23c1-eec2a42efb2b.png)

WAF を防止モードに変更しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/ac6e8d62-d8aa-864d-2a3b-dfb5d2b33f01.png)

この構成で ClientVM1 から 1 分間に 6 回以上リクエストを投げて、Status 403 となるかを確認します。
6 回目以降は Status 403 となりました。
また、レート制限をかけていない VM からは問題なくリクエストを投げられました。

```
$ curl -v  http://10.20.0.254
* Rebuilt URL to: http://10.20.0.254/
*   Trying 10.20.0.254...
* TCP_NODELAY set
* Connected to 10.20.0.254 (10.20.0.254) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.20.0.254
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Server: Microsoft-Azure-Application-Gateway/v2
< Date: Tue, 29 Aug 2023 06:55:41 GMT
< Content-Type: text/html
< Content-Length: 179
< Connection: keep-alive
<
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>Microsoft-Azure-Application-Gateway/v2</center>
</body>
</html>
* Connection #0 to host 10.20.0.254 left intact
```

以下の様に for 文にて 10 秒間隔でリクエストを投げ続け、どのタイミングでレート制限の閾値が緩和されるのかを確認してみました。
PHP にてレスポンスが返った時間を表示しながら、Status 403 となるタイミング、制限が緩和されるタイミングを見てみます。

```
for ((i=0;i<1000;i++)); do curl -s http://10.20.0.254/test.php|grep -e Serv
erVM -e 403 ;sleep 10; done
    ServerVM_2023/08/29 (Tue) 08:38:08  </body>
    ServerVM_2023/08/29 (Tue) 08:38:18  </body>
    ServerVM_2023/08/29 (Tue) 08:38:28  </body>
    ServerVM_2023/08/29 (Tue) 08:38:38  </body>
    ServerVM_2023/08/29 (Tue) 08:38:48  </body>
<head><title>403 Forbidden</title></head>
<center><h1>403 Forbidden</h1></center>
    ServerVM_2023/08/29 (Tue) 08:39:08  </body>
    ServerVM_2023/08/29 (Tue) 08:39:18  </body>
```
上記のように 1 分以内に 6 回以上のリクエストが来たタイミングで、Status 403 が返り、その 10 秒後からまたレスポンスが返っています。
このことからリクエストを受け付けたタイミングで直近 1 分以内に閾値以上のリクエストが来ているかどうかを判定して、レート制限を行う動作であるということがわかります。
タイミングにより多少のムラはあり、必ずしもこの動作になるわけではないのでご留意ください。

## マネージドルールの無効化

WAF のレート制限のみの利用目的で、マネージドルールを利用したくない場合、マネージドルールの無効化やリクエストボディの検査を無効化してしまう方法が有効であると考えられます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/5d83dc8e-b5b0-3acc-0e7a-99216a2c3f1b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/88cd167b-5a0c-9009-684c-7352a1d4a4b8.png)

## レート制限の基準となるグループ
レート制限の基準となるグループとして以下の 3 つが選択可能です。
それぞれどのような動作となるかを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/d5153eae-2502-3698-4325-1aef88f76b7e.png)

https://learn.microsoft.com/ja-jp/azure/web-application-firewall/ag/rate-limiting-overview#rate-limiting-policies

### クライアント アドレス
レート制限を IP アドレス単位で実施します。
例えば条件として 10.20.1.0/24 が指定されていた場合、範囲内の IP アドレス単位でレート制限が適用されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/49746222-ea00-b625-88e6-1d278ddc6c56.png)

条件については Geo ロケーションと併用することもできます。
以下の様にレート制限のグループはクライアント アドレスとして、条件を Geo ロケーションにした場合、Geo ロケーションに合致したパブリック IP アドレス単位でレート制限を適用することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/1e89c449-597c-7be4-754e-b8bf81e4e153.png)

動作イメージとしては以下です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/5c756c60-4aa8-511f-9f8e-7bef47d6ae33.png)


### Geo ロケーション
レート制限を Geo 単位で実施します。
以下のような設定で Geo ロケーションとして日本が指定されていた場合、日本と判定される Public IP に対してまとめてレート制限が適用されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/72403d6a-05f0-cba1-7df8-1c0e6eb527da.png)

イメージとしては以下のような動作で、異なる IP アドレスからの通信においても Geo 単位でレート制限が適用されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/ebde495a-9051-a5dc-1e6c-7a34b403cc57.png)

Geomatch を利用する際は "ZZ:不明" も対象に含めることが推奨されております。利用の際は[こちら](https://learn.microsoft.com/ja-jp/azure/web-application-firewall/ag/geomatch-custom-rules)もご確認ください。

:::note warn
ジオフィルタリングを使用するときは、常に国番号 ZZ を含めてください。 国番号 ZZ (または "不明" 国) では、データセット内の国にまだマップされていない IP アドレスが取り込まれます。 これにより、誤検知を回避できます。
:::


### なし
ルールで指定した条件に合致するリクエストに対してレート制限が適用されます。例えば特定の User-Agent に対してレート制限を適用している場合、異なる IP アドレスからのアクセスにおいても同じ User-Agent を使ったアクセスのリクエスト数が閾値をこえると Status 403 となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266293/6e3c82b4-6b25-6698-258c-e9bfc4b28ef9.png)


## 金額のめやす

Application Gateway WAF v2 の場合、1 か月あたりですと、"$381 の固定料金 + 利用量による課金 (容量ユニット、送信データ)" となります。(202308 時点)

以下の公開情報にあるシナリオ (毎秒 25 個の新規 TLS 接続と平均 8.88 Mbps のデータ転送を受信) ですと、容量ユニットは 4 となりますので、381 + 42 = $423 がおおよその目安となります。
なお、Application Gateway v2 の WAF は SKU (WAF) として課金されるため、WAF ポリシー自体に料金はかかりません。

https://learn.microsoft.com/ja-jp/azure/application-gateway/understanding-pricing#example-4--waf_v2-with-autoscaling-capacity-unit-calculations

https://azure.microsoft.com/ja-jp/pricing/details/web-application-firewall/

https://azure.microsoft.com/ja-jp/pricing/calculator/