【Microsoft Azure】ポータルでの Terraform エクスポート機能がパブリックプレビューになった！

## 1. はじめに

己の心にギャルを飼え。こんにちは、はしもと（仮名）です。

今月はじめ、**Azure ポータルから** リソースの Terraform 定義を直接エクスポートできる機能が、パブリックプレビューとして公開されました！

https://techcommunity.microsoft.com/blog/azuretoolsblog/announcing-public-preview-of-terraform-export-from-the-azure-portal/4409889

Azure リソースのIaCを実現するための手段としては Bicep や ARMテンプレートなども挙げられますが、Terraformには以下のような利点があります。

- 様々なクラウドプロバイダーに対応
- 多くのSaaSサービスとの連携が可能
- 異なるプラットフォーム間でも同じ記法で一貫したインフラ管理が可能

これらの利点から、Terraformを利用している方は多いのではないでしょうか。私です。

早速試してみたいと思いますが、その前に「Azure Export for Terraform」について少し言及します。

## 2. Azure Export for Terraform について

以前より「既存の Azure リソースに対応する Terraform 定義をエクスポートする」ためのツールとして、「**Azure Export for Terraform (aztfexport)**」 が公開、案内されています。

このツールの仕様は以下のとおりです。
- コマンドラインからの実行を前提としている
- 指定したスコープに該当するリソースの設定からterraform 定義を生成
- スコープの指定方法：
  - 任意の1リソース
  - リソースグループ
  - Azure Resource Graphを使用したクエリによるフィルタリング

https://learn.microsoft.com/ja-jp/azure/developer/terraform/azure-export-for-terraform/export-terraform-overview

https://github.com/Azure/aztfexport

今回のアップデートにより、未対応のリソースなどはある（後述）ものの、ほぼ同様の操作をポータルから手軽に行えるようになりました。
新しくツールを導入する必要もなく、普段触っている画面から操作できるのは嬉しいですね。

## 3. Azure Portal からのエクスポート機能

最初のアナウンス記事記載の手順を見ながら、実際に試してみます。

### 3.1 （事前準備）検証用リソースの作成

検証用に、サブスクリプションに以下のリソースを作成しました。

- リソースグループ: `qiita_test`
- ストレージアカウント: `sthaveagalinyourheart`
- キューサービス: `test-qiita-queue`

ストレージアカウントはリソースグループに関連付けられており、キューはストレージアカウント内に作成しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/8e77ad4b-5916-49ef-a9ab-7fd5d7a413ca.png)

### 3.2 必須プロバイダの登録

ポータルから利用する際、サブスクリプションの `設定 > リソースプロバイダー` から、`Microsoft.AzureTerraform` のプロバイダーを登録する必要があります。

https://learn.microsoft.com/en-us/azure/developer/terraform/azure-terraform-resource-provider/resource-provider-overview#registration

上記を参考に、以下のいずれかの方法で登録を行います。
- Terraformの`azurerm_resource_provider_registration`リソース
- azure CLI (`az provider register -n Microsoft.AzureTerraform`)
- ポータルからの操作

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/82f4910d-6fd9-44d3-ba53-b0955ee32468.png)

### 3.3 生成される Terraform テンプレートの確認

これでエクスポートの準備が整いました。
普段から Azure を使って開発をしているなら、プロバイダの登録を行うだけです。

テンプレートは、対象リソースページのメニュー一覧から `オートメーション > テンプレートのエクスポート` を選択することで見ることができます。

出力形式は、AzureRM と AzAPI から選択できます。

- **AzureRM**: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs


- **AzAPI**: https://registry.terraform.io/providers/Azure/azapi/latest/docs

エクスポート対象（範囲）は、「リソースグループ」と「ストレージアカウント」の2パターンです。

:::note warn
前述したプロバイダー登録が完了していない場合、以下のようなエラーが表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/94fd4e54-2844-402a-a3fc-39be9b51379b.png)
:::

#### 3.3.1 リソースグループ

##### AzureRM

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/b3834134-dd25-479a-b0ab-221a185db0ec.png)

画面上に警告が表示されています。詳細を確認します。
> まだエクスポートできないリソースタイプが4個あります。これらはテンプレートに含まれません。エラーの詳細を確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/26ac82cd-e72e-4a56-a9c2-1572b9472ee9.png)

どうやらストレージアカウントの場合、アカウント自体の設定はエクスポートできるものの、**ブロブやキューなどの各サービスの設定のエクスポートには非対応**のようです。

:::note info
各サービス内の Terraform リソースは AzureRM プロバイダーに既に実装されていますが、サービスそのもの(`storageAccounts/xxxServices`)に対応するリソースは見つけることができず、これが現状エクスポートできない要因のひとつと思われます。

後述する AzAPI プロバイダーを使った出力では問題なく出力できているため、AzureRM プロバイダーでもうまく出力できるようになると嬉しいです。
:::

<details><summary>結果抜粋（実際はリソースごとに詳細な設定内容が記載）</summary>

```hcl
terraform {
  required_providers {
    azurerm = {
      source  = "azurerm"
      version = "4.5.0"
    }
  }
}
provider "azurerm" {
  features {}
}

# リソースグループ
resource "azurerm_resource_group" "res-0" {
  location   = "japaneast"
  name       = "qiita_test"
}

# ストレージアカウント
resource "azurerm_storage_account" "res-1" {
  location                          = "japaneast"
  name                              = "sthaveagalinyourheart"
  depends_on = [
    azurerm_resource_group.res-0,
  ]
}
```

</details>

##### AzAPI

次に AzAPI リソースを使用する場合の生成結果です。
さきほどの警告は表示されず、AzureRM リソースではエクスポートできなかった各サービス (`storageAccounts/xxxServices`) やキューの定義も出力に含まれていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/78ba9e9a-1f7c-4a66-b5e4-4393fd17642c.png)

<details><summary>結果抜粋（実際はリソースごとに詳細な設定内容が記載）</summary>

```hcl
terraform {
  required_providers {
    azapi = {
      source  = "Azure/azapi"
      version = "2.0.1"
    }
  }
}
provider "azapi" {}

# ストレージアカウント
resource "azapi_resource" "res-0" {
  location                  = "japaneast"
  name                      = "sthaveagalinyourheart"
  type = "Microsoft.Storage/storageAccounts@2023-05-01"
  depends_on = [
    azapi_resource.res-6,
  ]
}

# ブロブサービス
resource "azapi_resource" "res-1" {
  name                      = "default"
  type                      = "Microsoft.Storage/storageAccounts/blobServices@2023-05-01"
  depends_on = [
    azapi_resource.res-0,
  ]
}

# ファイルサービス
resource "azapi_resource" "res-2" {
  name                      = "default"
  type                      = "Microsoft.Storage/storageAccounts/fileServices@2023-05-01"
  depends_on = [
    azapi_resource.res-0,
  ]
}

# キューサービス
resource "azapi_resource" "res-3" {
  name                      = "default"
  type                      = "Microsoft.Storage/storageAccounts/queueServices@2023-05-01"
  depends_on = [
    azapi_resource.res-0,
  ]
}

# キューリソース
resource "azapi_resource" "res-4" {
  name                      = "test-qiita-queue"
  type                      = "Microsoft.Storage/storageAccounts/queueServices/queues@2023-05-01"
  depends_on = [
    azapi_resource.res-3,
  ]
}

# テーブルサービス
resource "azapi_resource" "res-5" {
  name                      = "default"
  type                      = "Microsoft.Storage/storageAccounts/tableServices@2023-05-01"
  depends_on = [
    azapi_resource.res-0,
  ]
}

# リソースグループ
resource "azapi_resource" "res-6" {
  location                  = "japaneast"
  name                      = "qiita_test"
  type                      = "Microsoft.Resources/resourceGroups@2024-03-01"
}
```

</details>

#### 3.3.2 ストレージアカウント

続いて、リソース単位でのエクスポートも試します。

##### AzureRM

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/85abc48c-990c-4e51-8f0e-5972d41d3c1b.png)

「あれ、警告出ない？」と思ったのもつかの間、やっぱりストレージアカウントのリソース定義しか含まれていませんでした。惜しい。

リソースグループに対する処理結果と比較すると、リソースグループの定義がなくなり、ストレージアカウントの定義のみが含まれていることが分かります。

<details><summary>結果抜粋（実際はリソースごとに詳細な設定内容が記載）</summary>

```hcl
terraform {
  required_providers {
    azurerm = {
      source  = "azurerm"
      version = "4.5.0"
    }
  }
}
provider "azurerm" {
  features {}
}

# ストレージアカウント
resource "azurerm_storage_account" "res-0" {
  location            = "japaneast"
  name                = "sthaveagalinyourheart"
  resource_group_name = "qiita_test"
}
```

</details>


##### AzAPI

期待する結果としては、リソースグループに対するエクスポート結果から、リソースグループの定義がなくなっていることです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/4fcf47c9-ed9a-4786-8075-7f2321832ae7.png)

警告もなく想定どおりになったかと思いきや、今度は AzAPI の結果でも ストレージアカウントのリソース定義 (`Microsoft.Storage/storageAccounts`) だけになってしまいました。悔しい。

<details><summary>結果抜粋（実際はリソースごとに詳細な設定内容が記載）</summary>

```hcl
terraform {
  required_providers {
    azapi = {
      source  = "Azure/azapi"
      version = "2.0.1"
    }
  }
}
provider "azapi" {}

# ストレージアカウント
resource "azapi_resource" "res-0" {
  location                  = "japaneast"
  name                      = "sthaveagalinyourheart"
  type = "Microsoft.Storage/storageAccounts@2023-05-01"
}
```

</details>


##### Bicep（参考）

参考までに、Bicep での出力結果も記載します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/a6f9c85e-cdc6-44b7-a041-8d7d2c72b679.png)

Bicep だと、`Microsoft.Storage/storageAccounts/xxxServices`やキューのリソースも正しく含まれていることが分かります。

<details><summary>結果抜粋（実際はリソースごとに詳細な設定内容が記載）</summary>

```
param storageAccounts_sthaveagalinyourheart_name string = 'sthaveagalinyourheart'

# ストレージアカウント
resource storageAccounts_sthaveagalinyourheart_name_resource 'Microsoft.Storage/storageAccounts@2024-01-01' = {
  name: storageAccounts_sthaveagalinyourheart_name
  location: 'japaneast'
}

# ブロブサービス
resource storageAccounts_sthaveagalinyourheart_name_default 'Microsoft.Storage/storageAccounts/blobServices@2024-01-01' = {
  name: 'default'
}

# ファイルサービス
resource Microsoft_Storage_storageAccounts_fileServices_storageAccounts_sthaveagalinyourheart_name_default 'Microsoft.Storage/storageAccounts/fileServices@2024-01-01' = {
  name: 'default'
}

# キューサービス
resource Microsoft_Storage_storageAccounts_queueServices_storageAccounts_sthaveagalinyourheart_name_default 'Microsoft.Storage/storageAccounts/queueServices@2024-01-01' = {
  name: 'default'
}

# テーブルサービス
resource Microsoft_Storage_storageAccounts_tableServices_storageAccounts_sthaveagalinyourheart_name_default 'Microsoft.Storage/storageAccounts/tableServices@2024-01-01' = {
  name: 'default'
}

# キューリソース
resource storageAccounts_sthaveagalinyourheart_name_default_test_qiita_queue 'Microsoft.Storage/storageAccounts/queueServices/queues@2024-01-01' = {
  name: 'test-qiita-queue'
}
```

</details>

#### 3.3.3 【取得不可】Resource Graph のクエリ

Resource Graph クエリを使用したフィルタリング結果からのエクスポートが可能か確認しましたが、クエリ後に Terraform テンプレートを出力するための導線は見つけられませんでした。
見ている画面が間違っているだけかもしれませんが、現状この方法でのエクスポートは `aztfexport` を使用するしかないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463957/d223c7fe-c2bd-4ac6-9f7f-a2657559725d.png)

## 4. まとめ

パブリックプレビューとなった、Azure Portal からの Terraform エクスポート機能の検証を行いました。

### できるようになったこと

- **Azure ポータルから直接** Terraform 定義をエクスポートできるようになった
- **AzureRM** と **AzAPI** の2種類のプロバイダー形式で出力が選択可能
- 追加ツールなしで既存リソースの **IaC 化が容易**になった

### 現状の制限事項

- **AzureRM プロバイダー**では、ストレージアカウント内の各サービス（ブロブ、キューなど）の定義が**エクスポートできない**
- **個別リソース**でのエクスポート時には**子リソースが含まれない**（AzAPI でも同様）
- **Resource Graph クエリ**からのフィルタリングができない
- **複数リソースグループの一括エクスポート**ができない

これらの機能が必要な場合は、アナウンス内にもあるとおり、従来の **aztfexport ツール**の使用が推奨されます：

> For scripting or exporting many resource groups or resource types, we encourage you to check out the Azure Export for Terraform tool, which comes with customization features.
（訳）スクリプトを作成したり、多数のリソースグループやリソースタイプをエクスポートするには、カスタマイズ機能を備えた Azure Export for Terraform ツールをチェックすることをお勧めします。

プレビュー版としてまだ機能は限定的ですが、日常的に Azure ポータルを使う開発者にとっては便利な機能として、今後の改善に期待したいと思います。

## 参考

https://zenn.dev/yuta28/articles/azure-export-terraform

https://www.michikusayan.com/entry/20230524/1684932878