Azure Kubernetes ServiceでApplication GatewayのWAFを利用する

## はじめに

本記事は[エーピーコミュニケーションズ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ap-com)の9日目です。

本日12/9は私の誕生日ですので、( ﾟ∀ﾟ)o彡°わっふる！わっふる！な感じで**WAF**のお話です。端的に言って意味が分かりませんね。

ちなみに、ここでいうWAFとはWeb Application Firewallのことです。

セキュリティを考慮した構成だと多くのケースで利用されるWAFですが、いざ使おうとすると初見ではパッとわからなかったりするのでアドベントカレンダーに乗じて書くことにしました。
とくに、AKSのAGICと組み合わせるともっと複雑になりますので、その部分を中心に。

## AzureでWAFといったらApplication Gateway

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599221/7aabcbf8-6a09-84f8-bad1-0ca2852ec8db.png)


AzureでWAFを使おうとすると選択肢は以下の3種類です。

+ Application Gateway
+ Front Door
+ Content Delivery Network

今回はもっともオーソドックスなApplication Gatewayです。

## Application GatewayでWAFを利用するための条件

Application GatewayにはSKUが複数ありますが、AKSのAGIC(Application Gateway Ingress Controller)と組み合わせる場合は`WAF V2`を使う必要があります。

表にすると以下です。

||V1|V2|
|:-:|:-:|:-:|
|Standard|X|X|
|WAF|X|O|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599221/fd3cabf1-a04c-8fe5-584f-17c9be617c61.png)


単にWAFを使うだけなら`WAF V1`でもよいですが、AGICを使うために`V2`が必須となっています。

ちなみに`WAF V2`がいちばん高いです。これがゆえに個人でいろいろ検証するにはお財布に厳しいリソースかもしれません。

## Application Gatewayで使えるWAFの種類

Application GatewayでWAFを利用する場合、大別して2種類の方法があります。

+ Application Gatewayに**内蔵のWAFルール**を利用する
+ **WAFポリシー**を作成してApplicaiton Gatewayにアタッチする

さらに、WAFポリシーをアタッチする場合、スコープが選択できます。

+ **Application Gateway**
+ **HTTP Listener**
+ **Route Path**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599221/2d33cee9-a1fb-9fc0-9b74-2eafacd98a52.png)


これはどういうことかというと、Application Gatewayで複数のサイトをホストする場合に、サイトごとに異なるWAFポリシーを適用したりするためにある仕組みです。

## AGICでWAFを利用する場合の組み合わせ

これもいくつか選択肢がありますのでフローチャートにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599221/64a2ec57-f876-fc50-ee2b-2b1f81e52fb0.png)

ここまであれば、もうWAF設定で悩まないですね！

ちなみにAGICアノテーションを使わなくても手動でリスナーに対してWAFポリシーをアタッチすることも可能っちゃ可能です。

**ですが**、AGICでIngressのマニフェストが変更されるたびにリスナーのIDが書き換わってしまうため、書き換えのたびにWAFポリシーをアタッチしなおす手間が発生します。アノテーションを使うのが賢明でしょう。

<details><summary>【参考】フローチャートの作成方法</summary><div>

このフローチャートは[mermaid.js](https://mermaid-js.github.io/mermaid/#/)で書いてます。超便利なので超オススメです。

```js:元データ
graph TD
    A{"WAFを利用するか"}
    B["Standard V2"]
    C{"HTTPリスナーごとのWAF切替が必要か"}
    D{"カスタムルールが必要か"}
    E["WAFポリシーをHTTPリスナーに付与<br/>＋<br/>AGICアノテーション"]
    F["WAFポリシーをAppGWに付与<br/>（AGICアノテーションは不要）"]
    G["内蔵のWAF<br/>（WAFポリシーは不要）"]
    A --> |No| B
    A --> |Yes| C
    C --> |Yes| E
    C --> |No| D
    D --> |Yes| F
    D --> |No| G
```

</div></details>

## AGICアノテーションの書き方

基本的には、azure.github.ioのAGICのページに載っています。

https://azure.github.io/application-gateway-kubernetes-ingress/annotations/#azure-waf-policy-for-path

具体的には、`appgw.ingress.kubernetes.io/waf-policy-for-path`アノテーションを付与すればOKです。

### お手軽ハンズオン

まずは軽く事前準備です。

1. ネットワークが（kubenetではなく）**Azure CNI**なAKSクラスターを作成します。
1. Azure Portalで**AGICアドオン**を有効にします（デフォルトではApplication Gatewayが自動で作成されます）。
1. 作成されたApplication GatewayはデフォルトでStandard V2のため**WAF V2**に変更します。
1. Application Gateway用の**WAFポリシー**を作成します。

デプロイが長めなので、スムーズにやってもここまで20分くらいかかります。

では、やっていきます。AKSとApplication Gatewayは同じリソースグループに作ってある想定で書いてます。異なる場合は適宜読み替えてください。

```bash:環境変数の設定
RG_NAME=<your-resource-group-name>
AKS_NAME=<your-cluster-name>
WAF_NAME=<your-waf-policy-name>
WAF_URI=$(az network application-gateway waf-policy show -g $RG_NAME -n $WAF_NAME -o tsv --query id)
```
```bash:AKS認証情報の取得
az aks get-credentials -g $RG_NAME -n $AKS_NAME
```
```bash:nginxのpod作成
kubectl run nginx --image nginx
```
```bash:nginxのservice作成
kubectl expose po nginx --port 80
```
```bash:nginxのIngress作成
cat << EOF | kubectl apply -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress.class: azure/application-gateway
    appgw.ingress.kubernetes.io/waf-policy-for-path: "${WAF_URI}"
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80
EOF
```

なんとこれだけです。

### ハンズオンの結果

###

ここまで実施してAzure PortalでWAFポリシーのページにいくとHTTP Listenerが関連付けられているのが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599221/18ba096d-a3b5-5221-048f-ce644e833ea8.png)

## FAQ

### いちどApplication GatewayのSKUをWAF V2に変更してから再びStandard V2に戻すことはできますか？

内蔵のWAFを使っている場合は可能です。

WAFポリシーを関連付けした場合、現状は関連付けの完全な解除がサポートされていないため不可です。

### Standard V2のApplication Gatewayに対して`waf-policy-for-path`のアノテーションを付けるとどうなりますか？

502 Bad Gatewayになるのでやめておきましょう。

アノテーションを付けたからといって勝手にWAF V2には変更してくれません。

### 内蔵のWAFルールが有効な状態で`waf-policy-for-path`のアノテーションを付けるとどうなりますか？

共存可能です。アノテーションでは対象のHTTPリスナーに対してのみ指定したWAFポリシーが有効になります。

それ以外のリスナーに関しては内蔵のWAFルールが適用されます。

### AGICで関連付けが行われたWAFポリシーをAzure Portalにて手動で削除・上書きできますか？

これがなんと**できてしまいます**。ただ、普通に考えてよろしくない行いです。絶対にやらないほうがよいでしょう。

本番環境でやったら、ぶっとばされても文句は言えないと思います。

### Application Gateway内蔵のWAFが有効な状態で、Application Gateway全体に対してWAFポリシーを適用するとどうなりますか？

ちゃんと確認のダイアログがでます。ただし、この操作を行うと上述の通りStandard V2に戻すことはできなくなるので注意してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599221/73533d82-09da-a4bb-bc25-e11a197c7a4b.png)

## おわりに

これでアナタもWAFマスターですね！

と言いいたいところですが、WAFポリシーの**中身の設定**は今回は割愛していますので、各自で無限の探求心をもとにAzureという深海の探索を進めていただければと思います。

明日は[@taso_int](https://qiita.com/taso_int)さんの「誕生日じゃないけどなんか書きます」の記事です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599221/43db7e4f-cd55-54c1-8b94-ab6d93860269.png)

実は昨日も@taso_intさんでした。2日も書くなんてすごいですね。わたくし挟まれてしまいました。

てな感じでいろんな人が記事を書いてらっしゃいますんで他の方の記事もぜひ読んでみてください。それではみなさん、ごきげんよう。