しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure App Service に追加された Unique Default Hostname (Preview) を Bicep / Terraform でも試した

ほぼ Build 2024 直後に公開された機能で、割と今更という感じはあるのですが App Service の Unique Default Hostname がプレビューとなったので試しました。挙動としては Container Apps や Front Door のホスト名に近く、ランダムな文字列 + リージョンが含まれるようになるというものです。

何故ランダムな文字列が付くようになるかというと、数年前に騒ぎになった Subdomain Takeover への対応がメインです。App Service は削除された名前と同じ名前を誰でも再利用可能なので、DNS に CNAME レコードが残っていれば誰でも乗っ取ることが可能でした。

現在は CNAME 向けにもドメイン検証用のレコードが追加されたため改善されていますが、今回の Unique Default Hostname によってホスト名にランダムな文字列が付くため、第三者が同じホスト名を取ることが出来なくなります。これで Subdomain Takeover への対策としては完了という形です。

既に Web App 向けには Azure Portal から有効化出来るようになっているので、作成時に Unique Default Hostname のチェックを入れるとセキュアなホスト名が使われます。

ランダムな文字列以外にもリージョン名がホスト名に付くようになっているので、App Service の命名に関して制約が緩和されていると思って確認すると、以下のように記載されていました。要するに Unique Default Hostname が有効になっている場合は、同名の App Service を別リージョンに作成できるということです。

パターンを確認してみると素直に Unique Default Hostname のオンオフで Region スコープと Global スコープが切り替わるようになっていました。

The region in the unique default hostname would be based on the region where the site is located. Since the unique default hostname is now regionalized, you will be able to create a site called “test” in different regions. The site name however still must be regionally unique, which means that there can only be one site called “test” in East US regardless if they have different hash values.

Public Preview: Creating Web App with a Unique Default Hostname - Microsoft Community Hub

既に作成済みの App Service と同名の App Service を別リージョンであれば作成できるので、その点だけは注意が必要かもしれません。そして新しいリソースでは一般的な Resource Group スコープではなく珍しい Region スコープというのも盲点になりそうです。

Azure Portal ではチェックを入れるだけで有効化出来ましたが、ARM Template / Bicep / Terraform では AutoGeneratedDomainNameLabelScope という新しいプロパティを指定する必要があります。既に Container Instances では同名のプロパティが導入されているため、挙動としては似ているはずです。参考までドキュメントを紹介しておきます。

実際に Bicep を使って Unique Default Hostname が有効な Web App をデプロイしてみます。残念ながら該当のプロパティは Azure REST API Spec に追加されていないため、入力補完は聞かずビルド時には警告が出ますが、デプロイは成功するという代物です。

既存の App Service Plan の上にデプロイする定義は以下のようにシンプルに書けます。

resource appServicePlan 'Microsoft.Web/serverfarms@2023-12-01' existing = {
  name: 'plan-webapp-test'
}

resource webApp 'Microsoft.Web/sites@2023-12-01' = {
  name: 'app-webapp-bicep'
  location: 'japaneast'
  kind: 'app'
  properties: {
    serverFarmId: appServicePlan.id
    AutoGeneratedDomainNameLabelScope: 'TenantReuse'
  }
}

この Bicep 定義をデプロイすると以下のように Unique Default Hostname が有効になっていることが確認出来ます。今回は TenantReuse を指定していますが、正直デフォルトが NoReuse でも問題ないと思います。

Bicep は ARM Template にコンパイルされるので、API 定義に存在していなくても問題なくデプロイ出来ますが、Terraform ではそうはいきません。特に AzureRM Provider の場合は REST API 定義から SDK を自動生成しているので、定義が更新されない限りサポートはされません。

従ってこのようなケースでは必然的に AzAPI Provider を使うことになります。ほぼ ARM Template と同じ書き方になるので Terraform を使うメリットが減ってしまうのですが、今回のように対応していないプロパティも指定することが出来ます。

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">= 3.0"
    }
    azapi = {
      source  = "Azure/azapi"
      version = ">= 1.0"
    }
  }
}

provider "azurerm" {
  features {}
}

provider "azapi" {
}

data "azurerm_resource_group" "group" {
  name = "rg-webapp-test"
}

data "azurerm_service_plan" "plan" {
  name                = "plan-webapp-test"
  resource_group_name = data.azurerm_resource_group.group.name
}

resource "azapi_resource" "webapp" {
  type                      = "Microsoft.Web/sites@2023-12-01"
  name                      = "app-webapp-terraform"
  location                  = "japaneast"
  parent_id                 = data.azurerm_resource_group.group.id
  schema_validation_enabled = false
  body = jsonencode({
    properties = {
      serverFarmId                      = data.azurerm_service_plan.plan.id
      AutoGeneratedDomainNameLabelScope = "TenantReuse"
    }
  })
}

AzAPI Provider ではデフォルトでスキーマベースのバリデーションが行われる関係で、現時点でスキーマに追加されていない AutoGeneratedDomainNameLabelScope を指定するとエラーになってしまったので、リソースに対して schema_validation_enabled を追加してバリデーションをオフにしました。

こちらもデプロイしてみると、Unique Default Hostname が有効になっていることが確認出来ます。

おまけ情報として Azure Functions 向けには Azure Portal で Unique Default Hostname のオプションが表示されていませんが、例によって内部的には Web App と同一リソースなので、Bicep / Terraform を使ってデプロイすると以下のように Unique Default Hostname を持つ Azure Functions が作成できます。

Azure Functions に対して直接カスタムドメインを割り当てることは少ないと思いますが、将来的には Unique Default Hostname がデフォルトで有効化されると思うので、頭に入れておいて損は無さそうです。