しばやん雑記

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

Terraform Azure AD Provider を使って App Service の作成と同時に Azure AD 認証を有効化する

個人的に App Service / Azure Functions で頻繁に使う機能 1,2 位を争うのが App Service Authentication で、Azure サブスクリプションが紐づいている Azure AD テナントのユーザーのみアクセス許可したい場合には、コードの修正なしで Azure Portal から有効化出来てとても便利です。

Azure Portal から設定する場合は自動的に Azure AD にアプリケーションを作成してくれるので手間がかかりませんが、Terraform や ARM Template を使う場合には別途作成が必要になるので結構面倒です。

やはり手作業は行いたくないので、今回は Terraform Provider for Azure AD を組み合わせて、App Service と同時に Azure AD アプリケーションを作成することで、手作業を完全に無くしてみます。去年リリースされたバージョン 2.0 から Microsoft Graph にも対応しているので安心です。

基本的な書き方は Terraform Provider for Azure と変わらないので、今回のケースのように複数 Provider を利用する場合には Terraform の良さが出ますね。

以前は廃止扱いになっていた気がしたのですが、今はアクティブに開発されているので、そういった意味でも安心して使えそうです。秩序ある Azure AD の管理には必須だと思います。

今回作成する Azure AD のアプリケーションは設定項目が多く、識別子も GUID で Object ID や Application ID さらには Tenant ID と複数出てくるので、出来れば依存関係はコードで表現したい部分です。

一応公式ドキュメントに App Service Authentication での利用向け Azure AD アプリケーション作成方法が紹介されているので、これをベースに Terraform で定義していきます。ただし不要そうな部分は削っています。

Expose API 周りは単なる OpenID Connect としての利用なら不要だと思っているので削りました。API として公開している場合のみ設定すればよいという認識です。

以下が実際に作成した Azure AD アプリケーションの Terraform 定義です。App Service Authentication では Client Secret が必要なので azuread_application_password を使って作成しています。

terraform {
  required_providers {
    azuread = {
      version = "> 2.0"
    }
  }
}

resource "azuread_application" "test" {
  display_name = "Terraform example"

  web {
    redirect_uris = ["https://***.azurewebsites.net/.auth/login/aad/callback"]

    implicit_grant {
      access_token_issuance_enabled = false
      id_token_issuance_enabled     = true
    }
  }
}

resource "time_rotating" "test" {
  rotation_days = 180
}

resource "azuread_application_password" "test" {
  application_object_id = azuread_application.test.object_id

  rotate_when_changed = {
    rotation = time_rotating.test.id
  }
}

正直 redirect_uris に決め打ちでホスト名を指定しないといけないのがイケてないのですが、認証周りの設定が App Service から分離されたリソースになっていないため、循環参照になってしまうので仕方ないです。

Azure AD で各 Secret を作成する場合には有効期限が悩みどころですが、Terraform を使うと time_rotating リソースと rotate_when_changed の組み合わせで、指定した期間でローテート可能なので便利そうです。

この定義に対して terraform apply を実行すると数秒で Azure AD アプリケーションが作成されます。

f:id:shiba-yan:20220221210239p:plain

今回利用した azuread_application には多くのプロパティが用意されていて、機能的にはほぼ網羅されているようなので詳しくはドキュメントを参照してください。

azuread_application | Resources | hashicorp/azuread | Terraform Registry

Azure AD アプリケーションを作成して Client ID と Client Secret が用意出来れば、後は App Service を作成して auth_settings に設定してあげるだけで完了です。Terraform は Auth Settings V2 に対応していないので、Azure Portal からは確認できないのが割と不便ですが、問題なく動作はします。

data "azuread_client_config" "current" {}

resource "azurerm_resource_group" "test" {
  name     = "rg-terraform-test"
  location = "westus2"
}

resource "azurerm_app_service_plan" "test" {
  name                = "plan-terraform-test"
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location

  sku {
    tier = "Standard"
    size = "S1"
  }
}

resource "azurerm_app_service" "test" {
  name                = "app-terraform-test"
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location
  app_service_plan_id = azurerm_app_service_plan.test.id

  client_affinity_enabled = false
  https_only              = true

  site_config {
    default_documents = ["hostingstart.html"]
  }

  auth_settings {
    enabled                       = true
    token_store_enabled           = true
    default_provider              = "AzureActiveDirectory"
    unauthenticated_client_action = "RedirectToLoginPage"
    issuer                        = "https://login.microsoftonline.com/${data.azuread_client_config.current.tenant_id}/v2.0"

    active_directory {
      client_id     = azuread_application.test.application_id
      client_secret = azuread_application_password.test.value
    }
  }
}

現在の Azure AD で利用されている issuer についてはプロパティなどで取得できなかったので、ここに関しては Tenant ID から適当に URL を組み立てることで対応します。

追加した Terraform 定義に対して更に terraform apply を実行すると App Service が作成されます。ブラウザからアクセスしてみると、以下のような見慣れた Azure AD の確認画面が表示されるはずです。

f:id:shiba-yan:20220221205905p:plain

更に承諾ボタンをクリックすると、ログイン処理が継続して App Service のデフォルトページが表示されます。Terraform Provider for Azure AD を組み合わせることで Azure Portal や Azure CLI を使わずに、Terraform のみで Azure AD 認証付きの App Service が作成できました。

f:id:shiba-yan:20220221205913p:plain

必要なリソースは全て Terraform で管理されているので、削除する場合も terraform destroy を実行すれば Azure AD アプリケーションを含め全てが削除されるので、ゴミが残ることなく安心です。

個人的には Client Secret のローテートをスマートに解決できそうなので気に入りました。今回は利用していませんがセキュリティグループの管理と割り当てはコード化とレビュー付きで行いたいので、どこかのタイミングで本番運用に持っていきたいと思っています。