マルチサイト+SSLオフロードなApplication Gatewayを作成する

# はじめに
タイトルの通りマルチサイト+SSLオフロード構成なApplicationGatewayを作成する必要な場面が出たのでAzureCLIを使ってshellscript化してみました。
Application Gatewayについては[こちら](https://docs.microsoft.com/ja-jp/azure/application-gateway/application-gateway-introduction)

# 前提
* 今回は2サイト想定
* SSL証明書は自己署名証明書
* httpからhttpsへのリダイレクト付き
* バックエンドとなるVM等は今回作成していないので別途作成後バックエンドプールに追加が必要  
将来的には自動化したい

# 手順

* まずはリソースグループ、VNetを作成  
ゲートウェイサブネットも併せて作成します。

```:
az group create --name $RESOURCE_GROUP_NAME --location $LACATION
az network vnet create --resource-group $RESOURCE_GROUP_NAME --name $VNET_NAME --address-prefixes $VNET_ADDRESS
az network vnet subnet create --address-prefix $AG_SUBNET_ADDRESS --name $AG_SUBNET_NAME --resource-group $RESOURCE_GROUP_NAME --vnet-name $VNET_NAME
```
* 次にpfx形式で証明書をエクスポート  
今回は自己証明書型のSSLを作成してます。

```:
openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout ${HOGE_HOST}.key -out ${HOGE_HOST}.crt \
    -subj "/C=JP/ST=${CSR_LOCATION}/L=${CSR_CITY}/O=${CSR_ORG}/OU=${CSR_UNIT}/CN=${HOGE_HOST}"
openssl pkcs12 -export -out ${HOGE_HOST}.pfx -inkey ${HOGE_HOST}.key -in ${HOGE_HOST}.crt -password pass:${AG_HOGE_PFX_PASS}

openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout ${FOO_HOST}.key -out ${FOO_HOST}.crt \
    -subj "/C=JP/ST=${CSR_LOCATION}/L=${CSR_CITY}/O=${CSR_ORG}/OU=${CSR_UNIT}/CN=${FOO_HOST}"
openssl pkcs12 -export -out ${FOO_HOST}.pfx -inkey ${FOO_HOST}.key -in ${FOO_HOST}.crt -password pass:${AG_FOO_PFX_PASS}
```
* ApplicationGatewayインスタンス作成  
パブリックIPも合わせて作成してます。

```
az network public-ip create --resource-group $RESOURCE_GROUP_NAME --name $AG_PUBLICIP_NAME
az network application-gateway create \
    --name $AG_NAME \
    --location $LACATION \
    --resource-group $RESOURCE_GROUP_NAME \
    --vnet-name $VNET_NAME \
    --subnet $AG_SUBNET_NAME \
    --capacity 1 \
    --sku Standard_Small \
    --http-settings-cookie-based-affinity Disabled \
    --frontend-port 443 \
    --http-settings-port 80 \
    --http-settings-protocol Http \
    --public-ip-address $AG_PUBLICIP_NAME \
    --cert-file ${HOGE_HOST}.pfx \
    --cert-password $AG_HOGE_PFX_PASS
```

* アドレスプール作成  
バックエンドサーバの追加に必要となります。  
今回はマルチサイトということで2つ作成しております。

```:
az network application-gateway address-pool create \
  --gateway-name $AG_NAME \
  --resource-group $RESOURCE_GROUP_NAME \
  --name hogePool
az network application-gateway address-pool create \
  --gateway-name $AG_NAME \
  --resource-group $RESOURCE_GROUP_NAME \
  --name fooPool
```

* SSL証明書のアップロード  
先程作成したSSLをアップロードします

```:
az network application-gateway ssl-cert create \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --name hogeSslCert  \
    --cert-file  ${HOGE_HOST}.pfx  \
    --cert-password $AG_HOGE_PFX_PASS
az network application-gateway ssl-cert create \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --name fooSslCert  \
    --cert-file  ${FOO_HOST}.pfx  \
    --cert-password $AG_FOO_PFX_PASS
```

* リスナー作成  
こちらも複数のホストで受け付ける必要があるため、2つ作成します。

```:
az network application-gateway http-listener create \
  --name hogeListener \
  --frontend-ip appGatewayFrontendIP \
  --frontend-port appGatewayFrontendPort \
  --resource-group $RESOURCE_GROUP_NAME \
  --gateway-name $AG_NAME \
  --host-name $HOGE_HOST \
  --ssl-cert hogeSslCert
az network application-gateway http-listener create \
  --name fooListener \
  --frontend-ip appGatewayFrontendIP \
  --frontend-port appGatewayFrontendPort \
  --resource-group $RESOURCE_GROUP_NAME \
  --gateway-name $AG_NAME \
  --host-name $FOO_HOST \
  --ssl-cert fooSslCert
```


* ルール作成
ルーティングルールを作成します。最後にデフォルトのルールは削除します。

```:
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule2 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener hogeListener \
  --rule-type Basic \
  --address-pool hogePool
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule3 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener fooListener \
  --rule-type Basic \
  --address-pool fooPool
az network application-gateway rule delete \
  --gateway-name $AG_NAME \
  --name rule1 \
  --resource-group $RESOURCE_GROUP_NAME
```

* HTTP受信用のHTTP設定とリスナーを作成

```:
az network application-gateway frontend-port create --port 80 --gateway-name $AG_NAME --resource-group $RESOURCE_GROUP_NAME --name httpPort

az network application-gateway http-listener create \
    --name hogeHttpListener \
    --frontend-ip appGatewayFrontendIP \
    --frontend-port httpPort \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --host-name $HOGE_HOST
az network application-gateway http-listener create \
    --name fooHttpListener \
    --frontend-ip appGatewayFrontendIP \
    --frontend-port httpPort \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --host-name $FOO_HOST

az network application-gateway redirect-config create \
    --name hogeHttpToHttps \
    --gateway-name $AG_NAME \
    --resource-group $RESOURCE_GROUP_NAME \
    --type Permanent \
    --target-listener hogeListener \
    --include-path true \
    --include-query-string true
az network application-gateway redirect-config create \
    --name fooHttpToHttps \
    --gateway-name $AG_NAME \
    --resource-group $RESOURCE_GROUP_NAME \
    --type Permanent \
    --target-listener fooListener \
    --include-path true \
    --include-query-string true
```

* https用リダイレクト用ルールの作成

```:
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule4 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener hogeHttpListener \
  --rule-type Basic \
  --redirect-config hogeHttpToHttps
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule5 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener fooHttpListener \
  --rule-type Basic \
  --redirect-config fooHttpToHttps
```

以下shellscriptです。

```:sample.sh
#!/bin/bash

#変数はお好みで。

PJ_NAME="example"
LACATION="southeastasia"
RESOURCE_GROUP_NAME="${PJ_NAME}rg"
VNET_NAME="${PJ_NAME}vnet"
VNET_ADDRESS="10.0.0.0/16"

AG_NAME="${PJ_NAME}appgw"
AG_SUBNET_NAME="${AG_NAME}net"
AG_SUBNET_ADDRESS="10.0.0.0/24"
AG_PUBLICIP_NAME="${AG_NAME}publiciP"
AG_HOGE_PFX_PASS="Your Password"
AG_FOO_PFX_PASS="Your Password"

HOGE_HOST="hoge.com"
FOO_HOST="foo.com"

CSR_LOCATION="Tokyo"
CSR_CITY="Your City"
CSR_ORG="Your Organization"
CSR_UNIT="Your Unit"

# --------------------------------------------------------------
# --------------------------------------------------------------
# *** Set Global Config ***
az configure --defaults location=$LACATION group=$RESOURCE_GROUP_NAME

# *** Create Resource Group ***
az group create --name $RESOURCE_GROUP_NAME --location $LACATION

# *** Create VNet ***
az network vnet create --resource-group $RESOURCE_GROUP_NAME --name $VNET_NAME --address-prefixes $VNET_ADDRESS

# *** Create Subnet ***
az network vnet subnet create --address-prefix $AG_SUBNET_ADDRESS --name $AG_SUBNET_NAME --resource-group $RESOURCE_GROUP_NAME --vnet-name $VNET_NAME

# *** Create SSL Certificate and Export Pfx file  ***
openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout ${HOGE_HOST}.key -out ${HOGE_HOST}.crt \
    -subj "/C=JP/ST=${CSR_LOCATION}/L=${CSR_CITY}/O=${CSR_ORG}/OU=${CSR_UNIT}/CN=${HOGE_HOST}"
openssl pkcs12 -export -out ${HOGE_HOST}.pfx -inkey ${HOGE_HOST}.key -in ${HOGE_HOST}.crt -password pass:${AG_HOGE_PFX_PASS}

openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout ${FOO_HOST}.key -out ${FOO_HOST}.crt \
    -subj "/C=JP/ST=${CSR_LOCATION}/L=${CSR_CITY}/O=${CSR_ORG}/OU=${CSR_UNIT}/CN=${FOO_HOST}"
openssl pkcs12 -export -out ${FOO_HOST}.pfx -inkey ${FOO_HOST}.key -in ${FOO_HOST}.crt -password pass:${AG_FOO_PFX_PASS}

# *** Create Application Gateway ***
# **** Create Application Gateway IP Address ****
az network public-ip create --resource-group $RESOURCE_GROUP_NAME --name $AG_PUBLICIP_NAME
# **** Create Application Gateway ****
az network application-gateway create \
    --name $AG_NAME \
    --location $LACATION \
    --resource-group $RESOURCE_GROUP_NAME \
    --vnet-name $VNET_NAME \
    --subnet $AG_SUBNET_NAME \
    --capacity 1 \
    --sku Standard_Small \
    --http-settings-cookie-based-affinity Disabled \
    --frontend-port 443 \
    --http-settings-port 80 \
    --http-settings-protocol Http \
    --public-ip-address $AG_PUBLICIP_NAME \
    --cert-file ${HOGE_HOST}.pfx \
    --cert-password $AG_HOGE_PFX_PASS

# **** Create Address Pool ***
az network application-gateway address-pool create \
  --gateway-name $AG_NAME \
  --resource-group $RESOURCE_GROUP_NAME \
  --name hogePool
  az network application-gateway address-pool create \
  --gateway-name $AG_NAME \
  --resource-group $RESOURCE_GROUP_NAME \
  --name fooPool
# **** Upload SSL Certificate ***
az network application-gateway ssl-cert create \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --name hogeSslCert  \
    --cert-file  ${HOGE_HOST}.pfx  \
    --cert-password $AG_HOGE_PFX_PASS
az network application-gateway ssl-cert create \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --name fooSslCert  \
    --cert-file  ${FOO_HOST}.pfx  \
    --cert-password $AG_FOO_PFX_PASS
# **** Create Http Listener ****
az network application-gateway http-listener create \
  --name hogeListener \
  --frontend-ip appGatewayFrontendIP \
  --frontend-port appGatewayFrontendPort \
  --resource-group $RESOURCE_GROUP_NAME \
  --gateway-name $AG_NAME \
  --host-name $HOGE_HOST \
  --ssl-cert hogeSslCert
az network application-gateway http-listener create \
  --name fooListener \
  --frontend-ip appGatewayFrontendIP \
  --frontend-port appGatewayFrontendPort \
  --resource-group $RESOURCE_GROUP_NAME \
  --gateway-name $AG_NAME \
  --host-name $FOO_HOST \
  --ssl-cert fooSslCert
# **** Create Routing Rule ****
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule2 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener hogeListener \
  --rule-type Basic \
  --address-pool hogePool
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule3 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener fooListener \
  --rule-type Basic \
  --address-pool fooPool
az network application-gateway rule delete \
  --gateway-name $AG_NAME \
  --name rule1 \
  --resource-group $RESOURCE_GROUP_NAME

# **** Set Http to Https Redirect ****
# **** Create Frontend Http Port ****
az network application-gateway frontend-port create --port 80 --gateway-name $AG_NAME --resource-group $RESOURCE_GROUP_NAME --name httpPort
# **** Create Http Listener ****
az network application-gateway http-listener create \
    --name hogeHttpListener \
    --frontend-ip appGatewayFrontendIP \
    --frontend-port httpPort \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --host-name $HOGE_HOST
az network application-gateway http-listener create \
    --name fooHttpListener \
    --frontend-ip appGatewayFrontendIP \
    --frontend-port httpPort \
    --resource-group $RESOURCE_GROUP_NAME \
    --gateway-name $AG_NAME \
    --host-name $FOO_HOST
# **** Create Http to Https Redirect Config ****
az network application-gateway redirect-config create \
    --name hogeHttpToHttps \
    --gateway-name $AG_NAME \
    --resource-group $RESOURCE_GROUP_NAME \
    --type Permanent \
    --target-listener hogeListener \
    --include-path true \
    --include-query-string true
az network application-gateway redirect-config create \
    --name fooHttpToHttps \
    --gateway-name $AG_NAME \
    --resource-group $RESOURCE_GROUP_NAME \
    --type Permanent \
    --target-listener fooListener \
    --include-path true \
    --include-query-string true
# **** Create Http to Https Redirect Routeing Rule ****
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule4 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener hogeHttpListener \
  --rule-type Basic \
  --redirect-config hogeHttpToHttps
az network application-gateway rule create \
  --gateway-name $AG_NAME \
  --name rule5 \
  --resource-group $RESOURCE_GROUP_NAME \
  --http-listener fooHttpListener \
  --rule-type Basic \
  --redirect-config fooHttpToHttps
# --------------------------------------------------------------
```

# 最後に
上記がベストなのかわかりませんが、改善の余地がありそうでしたらコメント頂けると助かります。

# 参考
[Azure CLI を使用して複数のサイトをホストするアプリケーション ゲートウェイを作成する](https://docs.microsoft.com/ja-jp/azure/application-gateway/tutorial-multisite-cli)
[Azure CLI を使用して HTTP から HTTPS へのリダイレクトと共にアプリケーション ゲートウェイを作成する](https://docs.microsoft.com/ja-jp/azure/application-gateway/tutorial-http-redirect-cli)