TerraformでMicrosoft Entra IDのクライアントシークレットを更新する

前回、Terraformを使用してAzureサービスプリンシパルとクライアントシークレットを作成しました。 blog.jbs.co.jp

作成したクライアントシークレットには有効期限があり、期限を過ぎてしまうと使用不可となってしまいます。そうなった場合、Azureポータル上で再作成を実施しなければなりません。

その問題をTerraformを実行することで解決していきます。

time_rotatingリソースの適用

Terraform定義ファイル内でクライアントシークレットの再作成を行う場合、time_rotatingリソース(以下、time_rotating)を使用します。

time_rotatingはAzureリソースではなく、Terraform独自のリソースです。

time_rotatingはタイマーのようなイメージです。terraform applyを実行するだけで、古いクライアントシークレットを削除、再作成できます。

registry.terraform.io

azureadプロバイダー内で、time_rotatingを適用できるリソースは以下の2つです。

定義ファイル記載例

main.tf

プロバイダー情報、作成先サブスクリプション、状態格納用ストレージを記載します。

provider "azuread" {
  tenant_id = var.tenant_id
}

# Azure Provider
terraform {
  required_providers {
    azuread = {
      source  = "hashicorp/azuread"
      version = "2.47.0"
    }
  }

  # Store Terraform state in Azure Storage
  backend "azurerm" {
    resource_group_name  = "状態格納用ストレージアカウントがあるリソースグループ名"
    storage_account_name = "ストレージアカウント名"
    container_name       = "BLOBコンテナー名"
    # Statment File Name
    key = "任意のファイル名"
  }
}

variables.tf

定義ファイル内で使用するリソース名、変数を指定します。

#-------------------------------
# 基本変数定義
#-------------------------------

#テナントID
variable "tenant_id" {}

#---------------------------------
# Service Principal
#---------------------------------
#Entra ID アプリケーションオブジェクト名/サービスプリンシパルオブジェクト名
variable "name_app" {
  default = "test-sp001" #任意の名前
}
#クライアントシークレット有効期限
variable "end_time" {
  default = "17520h" #有効期限2年間
}

sp.tf

Microsoft Entraアプリケーションオブジェクト、サービスプリンシパルオブジェクトを定義します。テストのため、クライアントシークレットを10分でローテーションする設定にします。

#----------------------------------------
# time_rotating
#----------------------------------------
#ローテーション時間を指定(分、時、日、月、年が可能)
resource "time_rotating" "rotation" {
  rotation_minutes = 10 #10分で更新できるようにする
  #rotation_hours = 1 #1時間で更新できるようにする
  #rotation_months = 1 #1か月で更新できるようにする
  #rotation_years = 1 #1年で更新できるようにする
}

#----------------------------------------
#Azure App
#----------------------------------------

#Microsoft EntraIDにアクセス
data "azuread_client_config" "provider" {}

#AzureApp

#Microsoft Entraアプリケーションオブジェクト作成
resource "azuread_application" "azure_app" {
  display_name = var.name_app #Entra ID アプリケーションオブジェクト名を指定
  owners       = [data.azuread_client_config.provider.object_id] #所有者はapply実行者となる
  }

#クライアントシークレット作成
resource "azuread_application_password" "app_password" {
  application_id    = azuread_application.azure_app.id #アプリケーション(クライアント)ID
  end_date_relative = "17520h" #有効期限2年間

  rotate_when_changed = {
    rotation = time_rotating.rotation.id #time_rotatingリソースを適用する
  }

  # 既存の Client Secret を削除する前に新しいものを作成するようにする
  lifecycle {
    create_before_destroy = true
  }
}

#----------------------------------------
#Service Principal
#----------------------------------------

#サービスプリンシパルオブジェクト作成
resource "azuread_service_principal" "service_principal" {
  client_id                    = azuread_application.azure_app.client_id #アプリケーション(クライアント)ID
  app_role_assignment_required = true #ロールの割り当て有効化
  owners                       = [data.azuread_client_config.provider.object_id] #所有者はapply実行者となる
}

Terraform実行

定義が完了したので、Terrformを実行していきます。 terraform initを実行し、初期化していきます。

terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/azuread from the dependency lock file
- Reusing previous version of hashicorp/time from the dependency lock file
- Using previously-installed hashicorp/azuread v2.47.0
- Using previously-installed hashicorp/time v0.10.0

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

terraform planを実行し、エラーがないことを確認します。

terraform plan
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Plan: 4 to add, 0 to change, 0 to destroy.

terraform applyを実行し、リソースを作成します。

terraform apply
data.azuread_client_config.provider: Reading...
data.azuread_client_config.provider: Read complete after 0s [id=*****-*****-*****]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Plan: 4 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

リソースの確認

Microsoft Entra ID>アプリの登録><作成したアプリの登録名>>証明書とシークレットをクリックし、クライアントシークレットが存在するか確認します。

クライアントシークレット実行結果(作成)

Terraform再実行

10分後、再度terraform planを実行し、クライアントシークレットに変更がかかるか確認します。

terraform plan
  # azuread_application_password.app_password must be replaced
+/- resource "azuread_application_password" "app_password" {
      ~ application_object_id = "*****" -> (known after apply)
      + display_name          = (known after apply)
      ~ end_date              = "*****" -> (known after apply)
      ~ id                    = "*****/password/*****" -> (known after apply)
      ~ key_id                = "*****" -> (known after apply)
      ~ rotate_when_changed   = { # forces replacement
          - "rotation" = "*****"
        } -> (known after apply)
      ~ start_date            = "*****" -> (known after apply)
      ~ value                 = (sensitive value)
        # (2 unchanged attributes hidden)
    }

  # time_rotating.rotation will be created
  + resource "time_rotating" "rotation" {
      + day              = (known after apply)
      + hour             = (known after apply)
      + id               = (known after apply)
      + minute           = (known after apply)
      + month            = (known after apply)
      + rfc3339          = (known after apply)
      + rotation_minutes = 10
      + rotation_rfc3339 = (known after apply)
      + second           = (known after apply)
      + unix             = (known after apply)
      + year             = (known after apply)
    }

Plan: 2 to add, 0 to change, 1 to destroy.

古いクライアントシークレットが削除され、新しいクライアントシークレットとtime_rotatingが作成されることが確認できます。 続けてterraform applyを実行し、確認したリソースを再作成します。

terraform apply
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Plan: 2 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

time_rotating.rotation: Creating...
time_rotating.rotation: Creation complete after 0s [id=*****]
azuread_application_password.app_password: Creating...
azuread_application_password.app_password: Creation complete after 6s [id=*****-*****-*****]
azuread_application_password.app_password (deposed object *****): Destroying... [id=*****-*****-*****]
azuread_application_password.app_password: Still destroying... [id=*****-*****-*****, 10s elapsed]
azuread_application_password.app_password: Still destroying... [id=*****-*****-*****, 20s elapsed]
azuread_application_password.app_password: Destruction complete after 20s

Apply complete! Resources: 2 added, 0 changed, 1 destroyed.

リソースの再作成確認

Azureポータルでクライアントシークレットが再作成されていることを確認します。

クライアントシークレット実行結果(再作成)
作成されたクライアントシークレットの値は、状態格納ファイルから確認できます。

最後に

最後まで閲覧ありがとうございます。

この記事を見て、TerraformでMicrosoft Entra IDを操作することに興味を持っていただけたり、クライアントシークレット更新の解決策の1つとなっていただけたりすれば幸いです。

執筆担当者プロフィール
佐藤 宏樹

佐藤 宏樹(日本ビジネスシステムズ株式会社)

クラウドソリューション事業本部に所属しています。主にMicrosoft Azureに携わっています。バイク乗りです。

担当記事一覧