Azure Front Door Premium と Azure Storage の Private Link 接続構成を Azure CLI で構築してみた

## 背景と目的

よくあるウェブサービスのインフラ構成として、コンテンツキャッシュ＋動的サイト（データベース含む）＋静的コンテンツを組み合わせるパターンが多いと思います。Azure でリージョンを跨るこれらのインフラを構成するとしたら、例えばコンテンツキャッシュは Front Door、動的サイトは App Service、静的コンテンツは Storage アカウントを選択したくなったりします。しかし、Front Door と App Service はサービスタグを使ってセキュアに接続出来るのですが、Front Door と Storage アカウントは簡単にセキュアな接続をすることが出来ません。以前書いた「[App Service Linux で HTTPS リバースプロキシーを試してみた](https://qiita.com/mnrst/items/353e5ff96d581f6c8645)」のように App Service にリバプロ機能を持たせて Storage アカウントに接続するとか、Application Gateway を間に挟んで Front Door と Storage アカウントを構成するとか、少々複雑な構成になってしまいます。

今回は、Azure Front Door Premium の Private Link 接続を使ってセキュアに Storage アカウントに接続する構成を Azure CLI を使って構築してみました。なお、Storage アカウントは「静的な Web サイト」を有効にするのではなく、 Azure Front Door Premium の Private Link が対応している BLOB アクセスを有効にします。

余談ですが今回試した構成は、Front Door と App Service のセキュアな接続や、App Service のリージョン冗長構成、Storage アカウントのリージョンレプリケーションなどのインフラ構成の一部になる想定です。

## 前提条件

コマンドの実施環境は、Mac + Azure CLI です。

```bash:bash
$ sw_vers
ProductName:    macOS
ProductVersion: 12.3.1
BuildVersion:   21E258

$ az version
{
  "azure-cli": "2.35.0",
  "azure-cli-core": "2.35.0",
  "azure-cli-telemetry": "1.0.6",
  "extensions": {}
}
```

## Storage アカウントを準備

```bash:bash
# 環境変数をセットします
region=japaneast
prefix=mnrfdtest

# リソースグループを作成します
az group create \
  --name ${prefix}-rg \
  --location $region

# Storage アカウントを作成します
az storage account create \
  --name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --sku Standard_LRS

# ストレージキーを取得します
storagekey=$(az storage account keys list \
  --account-name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --query "[0].value" \
  --output tsv)

# ストレージコンテナを作成します
az storage container create \
  --account-name ${prefix}stor \
  --account-key $storagekey \
  --name static \
  --public-access blob

# コンテンツを作成します
echo "<h1>${prefix}</h1>" > index.html

# コンテンツをアップロードします
az storage blob upload \
  --account-name ${prefix}stor \
  --account-key $storagekey \
  --container-name static \
  --file index.html \
  --name index.html

# コンテンツにアクセス出来るか確認します
curl https://${prefix}stor.blob.core.windows.net/static/index.html

# Storage アカウントの外部接続を遮断します
az storage account update \
  --name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --default-action Deny

# コンテンツにアクセス出来なくなった事を確認します
curl https://${prefix}stor.blob.core.windows.net/static/index.html
```

## Front Door を構成

```bash
# Premium プロファイルを作成します
az afd profile create \
  --resource-group ${prefix}-rg \
  --profile-name ${prefix}fd \
  --sku Premium_AzureFrontDoor

# エンドポイントを作成します
az afd endpoint create \
  --resource-group ${prefix}-rg \
  --endpoint-name ${prefix} \
  --profile-name ${prefix}fd \
  --enabled-state Enabled

# 配信元グループを作成します
az afd origin-group create \
  --resource-group ${prefix}-rg \
  --origin-group-name ${prefix}og \
  --profile-name ${prefix}fd \
  --probe-request-type HEAD \
  --probe-protocol Http \
  --probe-interval-in-seconds 120 \
  --probe-path / \
  --sample-size 4 \
  --successful-samples-required 3 \
  --additional-latency-in-milliseconds 50

# 配信元を作成します
az afd origin create \
  --resource-group ${prefix}-rg \
  --host-name ${prefix}stor.blob.core.windows.net \
  --profile-name  ${prefix}fd \
  --origin-group-name ${prefix}og \
  --origin-name ${prefix}og1 \
  --origin-host-header ${prefix}stor.blob.core.windows.net \
  --priority 1 \
  --weight 1000 \
  --enabled-state Enabled \
  --http-port 80 \
  --https-port 443 \
  --enable-private-link true \
  --private-link-resource $(az storage account show \
  --name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --query id \
  --output tsv) \
  --private-link-location $region \
  --private-link-request-message 'Please approve this request' \
  --private-link-sub-resource blob

# Storage アカウントのプライベートエンドポイント接続を承認します
az storage account private-endpoint-connection approve \
  --id $(az storage account show \
  --name ${prefix}stor \
  --resource-group ${prefix}-rg \
  --query "privateEndpointConnections[0].id" \
  --output tsv)

# ルートを作成します
az afd route create \
  --resource-group ${prefix}-rg \
  --endpoint-name ${prefix} \
  --profile-name ${prefix}fd \
  --route-name ${prefix}route \
  --https-redirect Enabled \
  --origin-group ${prefix}og \
  --supported-protocols Https \
  --link-to-default-domain Enabled \
  --forwarding-protocol MatchRequest

# Front Door の URL を取得します
weburl=$(az afd endpoint show \
  --resource-group ${prefix}-rg \
  --endpoint-name ${prefix} \
  --profile-name ${prefix}fd \
  --query hostName \
  --output tsv)

# Front Door 経由で Storage アカウントのコンテンツが表示される事を確認します
curl https://$weburl/static/index.html
```

## 参考

```bash
# リソースグループを削除します
az group delete \
  --name ${prefix}-rg \
  --yes
```

https://docs.microsoft.com/ja-jp/azure/frontdoor/private-link

https://docs.microsoft.com/ja-jp/azure/frontdoor/standard-premium/how-to-enable-private-link-storage-account

https://docs.microsoft.com/ja-jp/azure/frontdoor/standard-premium/create-front-door-cli