#005: azdのスコープをResource Groupに変更する

※本記事は、個人の意見および個人的活動で得た経験を記したものであり、会社を代表するものではありません

# 1. azdのスコープ

“azd”コマンドのデフォルトスコープは”subscription”、これは”azd up”や”azd down”の対象にリソースグループの作成・削除が含まれる。

個人的には、きちんとリソースグループから再作成できる方が好きなのだが、実際にはサブスクリプションには権限が付与されず、事前に作成されたリソースグループに対してのみ例えば共同所有者のアクセス権限が付与されるといったケースもあるかもしれない。

この場合は、一度作成したリソースグループは削除できないので（削除は可能だが、作成権限がないため、権限のあるユーザーに再度作成してもらう必要がある）、azdコマンドのスコープを”ResourceGroup”に変更する必要がある。

ただし、この機能はこの記事を書いている時点では”alpha version”で、”azd down”（リソース削除処理）が想定と異なる動作になるためお勧めしないが、こんな機能が今後利用できるだろうから、少し寄り道して勉強してみた。

https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/resource-group-scoped-deployments

# 2. azdコマンドのスコープを”ResoruceGroup”に変更

## 2-1. 事前処理

事前処理として、以下のコマンドでスコープをResource Groupにする。

```bash
sato@[16:59:19]:~/proj/RagSystem% azd config set alpha.resourceGroupDeployments on
sato@[16:59:42]:~/proj/RagSystem% 
```

## 2-2. [Step.1] bicepファイルのターゲットスコープを”resourceGroup”に変更する。

“main.bicep”ファイルの”targetscope”を”ResourceGroup”に変更する。

```bicep
// This is the main bicep file for the RagSystem.

// Settings No.1 of the resource group scoped deployment.
// https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/resource-group-scoped-deployments
//
// To enable with resource group deployment, change the targetScope to 'resourceGroup'.
//targetScope = 'subscription'
targetScope = 'resourceGroup'
```

## 2-3. [Step.2] すべてのモジュールからtargetscopeを削除

“main.bicep”からモジュールとして参照されるbicepファイルで定義している”targetScope”はすべて削除する。今回は”rg.bicep”は参照しない（理由は後述）ので対象外とし、”vnet.bicep”の”targetScope”だけ削除。

```bicep
metadata description = 'Create a Azure Virtual Network by bicep template with some tags.'

// Settings No.2 of the resource group scoped deployment.
// https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/resource-group-scoped-deployments
// 
// To enable with resource group deployment, this is needed to be disabled.
//targetScope = 'resourceGroup'
```

## 2-4. [tips] resourceTokensの設定は不要

MSの公式ドキュメントでは、次のステップとして”resourceToken”の設定が記載されているが、azdコマンドでは、azdコマンド内部で処理されるためこの設定および参照は不要。

“resourceToken”というのは、Azureリソースを構築するプログラム（今回でいうとazdコマンド、他にはAzure CLIコマンドなど）がAzureにアクセスする際に取得する認証・認可のためのトークンのこと。

## 2-5. [Step.4] リソースグループのモジュール定義を削除

リソースグループは既存のものを参照するだけで、作成も削除もしないため、main.bicep内でrg.bicepをモジュール参照している箇所をコメントアウト。

```bicep
// Settings No.4-1 of the resource group scoped deployment.
// https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/resource-group-scoped-deployments
// 
// Removed the definition of the resource group in this template. Instead of this, resource group name is defined in environment variables file and specified as a parameter.
//@description('The name of the resource group. This is used for specifying the scope of the module of the resources that is created in the resource group.')
//var rgName = '${systemName}-${environmentName}'

// Settings No.4-2 of the resource group scoped deployment.
// https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/resource-group-scoped-deployments
// 
// Disabled the definition of the resource group in the bicep file.

////////////////////////////////////////////////////////////
// Definitions of the resource group.
/*
@description('Create a Azure Resource Group by bicep template with some tags.')
module ragRg './resource-group/rg.bicep' = {

  scope: subscription()
  name: 'ragRg'

  params: {
    rgName: rgName
    location: location
    tags: tags
  }
}
*/
```

## 2-6. [Step.5] リソースグループ名を定義

リソースグループは既存のものを参照するだけなので、リソースグループ名を環境変数ファイルに定義し、リソース作成時に指定するリソースグループ名として参照できるようにする。

### 2-6-1. 環境変数を追加定義

.env 環境変数ファイルにリソースグループ名を追加定義。

```bicep
AZURE_ENV_NAME="dev"
AZURE_LOCATION="eastus2"
AZURE_RESOURCE_GROUP_NAME="リソースグループ名"
SYSTEM_NAME="RagSystem"
```

### 2-6-2. パラメータ定義を変更

main.bicepparamファイルでリソースグループ名として環境変数を参照するように変更。

```bicep
using './main.bicep'

param systemName = readEnvironmentVariable('SYSTEM_NAME')
param environmentName = readEnvironmentVariable('AZURE_ENV_NAME')
param location = readEnvironmentVariable('AZURE_LOCATION')
//param resourceGroupName = '${systemName}-${environmentName}'
param resourceGroupName = readEnvironmentVariable('AZURE_RESOURCE_GROUP_NAME')
```

## 2-7. リソースのスコープとしてリソースグループを名前で指定するように変更し、依存関係を削除

virtual networkの作成で、どこに作成するかを指定するscope、以前はテンプレート内で作成したオブジェクトを参照していたが、今回はリソースグループ名を指定するように変更。

さらに、”dependsOn”でリソースグループに依存関係を定義していたが、これをコメントアウトしている。

```bicep
module RagVNet './network/vnet.bicep' = {
  // scope: resourceGroup(RagRg)
  scope: resourceGroup(resourceGroupName)
  name: 'RagVNet'

  params: {
    location: location
    tags: tags
    
    // for the RagVNet that is a main virtual networkf for the RagSystem.
    ragVNet_name: ragVNet_name
    ragVNet_addressPrefix: ragVNet_addressPrefix
    ragVNet_encryptionEnabled: ragVNet_encryptionEnabled
    ragVNet_ddosProtectionEnabled: ragVNet_ddosProtectionEnabled

    // for the AdminSubnet
    adminSubnet_name: adminSubnet_name
    adminSubnet_addressPrefix: adminSubnet_addressPrefix
    adminSubnet_privateEnabled: adminSubnet_privateEnabled
    adminSubnet_privateEndpointNetworkPolicies: adminSubnet_privateEndpointNetworkPolicies

    // for the BastionSubnet
    bastionSubnet_name: bastionSubnet_name
    bastionSubnet_addressPrefix: bastionSubnet_addressPrefix
    bastionSubnet_privateEnabled: bastionSubnet_privateEnabled
    bastionSubnet_privateEndpointNetworkPolicies: bastionSubnet_privateEndpointNetworkPolicies
  }
  /*
  dependsOn: [
    ragRg
  ]
  */
}
```

## 2-8. azdコマンド実行

準備万端、早速実行。

WARNINGでリソースグループをターゲットしたデプロイはアルファバージョンだということが表示された。

リソースグループを作成するのか、指定した名前のリソースグループを参照するのかの２択、ここでは指定した名前のリソースグループを参照する。

```bash
sato@[22:10:43]:~/proj/RagSystem% azd up

  WARNING: Feature 'resourceGroupDeployments' is in alpha stage.
  To learn more about alpha features and their support, visit https://aka.ms/azd-feature-stages.

? Pick a resource group to use:  [Use arrows to move, type to filter]
  Create a new resource group
> <選択したリソースグループ名>
```

以上、正常に作成できた。

```bash
sato@[22:10:43]:~/proj/RagSystem% **azd up**

  WARNING: Feature 'resourceGroupDeployments' is in alpha stage.
  To learn more about alpha features and their support, visit https://aka.ms/azd-feature-stages.

? Pick a resource group to use: 1. <選択したリソースグループ名>

Packaging services (azd package)

Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

  WARNING: Feature 'resourceGroupDeployments' is in alpha stage.
  To learn more about alpha features and their support, visit https://aka.ms/azd-feature-stages.

Subscription: <サブスクリプション名> (xxx)
Location: East US 2

  You can view detailed progress in the Azure Portal:
  https://portal.azure.com/#view/HubsExtension/DeploymentDetailsBlade/~/overview/id/%2Fsubscriptions%2Fxxxf%2FresourceGroups%2F<リソースグループ名>%2Fproviders%2FMicrosoft.Resources%2Fdeployments%2Fdev-1722085956

  (✓) Done: Virtual Network: RagSystem-vnet-dev

Deploying services (azd deploy)

SUCCESS: Your up workflow to provision and deploy to Azure completed in 26 seconds.
sato@[22:13:48]:~/proj/RagSystem% 
```

# 3. azdコマンド実行時のいくつかのtips

## [Tips.1 ]スコープが”subscription”の時にリソースグループを作成するために必要な権限

“azd”コマンドのスコープが”subscription”の場合、”azd”コマンドを実行すると、リソースグループの作成・更新・削除が対象に含まれる。

これを実行するためには、認証されたユーザーに対して対象サブスクリプションのIAM（Identity and Access Management）に”contributor”（共同作成者）以上の権限が必要とのこと。

たとえBicepでリソースグループの作成・削除を定義していなくても、スコープが”subscription”の場合は”azd”コマンドを実行した時に以下のような権限エラーが出力され、処理に失敗する。

上記に示した通り、サブスクリプションのIAMに対して”Contributor”（共同作成者）以上の権限を付与すればよい。

```bash
sato@[10:28:56]:~/proj/RagSystem% azd up

Packaging services (azd package)

Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

Subscription: <サブスクリプション名> (xxx)
Location: East US 2

  |      =| Creating/Updating resources
ERROR: error executing step command 'provision': deployment failed: error deploying infrastructure: starting deployment to subscription: PUT https://management.azure.com/subscriptions/xxx/providers/Microsoft.Resources/deployments/dev-1722066356
--------------------------------------------------------------------------------
RESPONSE 403: 403 Forbidden
ERROR CODE: AuthorizationFailed
--------------------------------------------------------------------------------
{
  "error": {
    "code": "AuthorizationFailed",
    "message": "The client '<アカウント名>' with object id 'xxx' does not have authorization to perform action 'Microsoft.Resources/deployments/write' over scope '/subscriptions/xxx/providers/Microsoft.Resources/deployments/dev-1722066356' or the scope is invalid. If access was recently granted, please refresh your credentials."
  }
}
--------------------------------------------------------------------------------

TraceID: 1c8e0f483be4b0d6c414a9453eb37888
sato@[16:45:57]:~/proj/RagSystem% 
```

## [Tips.2] スコープが”Resource Group”の場合でも、”azd down”ではリソースグループまで削除される

これは注意が必要。

スコープを”ResourceGroup”することで、”azd up”コマンドは、既存リソースグループはそのままに、その中にリソースを作成するが、”azd down”コマンドは、既存リソースグループまで丸っと削除されてしまう。

おそらくalpha versionのため既存リソースグループを残すという処理はまだ実装されていないのだと思われる。

リソースの削除は個別に実施する必要があるようだ。

以下は”azd down”を実行した時のコマンド履歴で、スコープが”ResourceGroup”でも、リソースグループを削除することに対する確認メッセージが表示される。

ここで”Y”を選択したら本当にリソースグループまで削除された。。

```bash
sato@[22:13:48]:~/proj/RagSystem% azd down

Deleting all resources and deployed code on Azure (azd down)
Local application code is not deleted when running 'azd down'.

  WARNING: Feature 'resourceGroupDeployments' is in alpha stage.
  To learn more about alpha features and their support, visit https://aka.ms/azd-feature-stages.

  Resource group(s) to be deleted:

    • <リソースグループ名>: https://portal.azure.com/#@/resource/subscriptions/xxx/resourceGroups/<リソースグループ名>/overview
? Total resources to delete: 1, are you sure you want to continue? No

ERROR: deleting infrastructure: error deleting Azure resources: deleting resource groups: user denied delete confirmation
sato@[22:18:44]:~/proj/RagSystem% 
```

一番最初に言及したが、ターゲットスコープを”ResourceGroup”に指定するケースは、例えばサブスクリプションには権限が付与されずにリソースグループにだけ権限があるような場合。

リソースグループにリソースを作成するためには”Contributor”以上の権限が必要だが、これはリソースグループの削除も実行可能。

このため、間違ってリソースグループまで削除すると権限のあるユーザーに再度リソースグループの作成をお願いしないといけないため、怒られる可能性が大きい。。

これは注意が必要。

アルファバージョンということなので、一旦いまはデプロイスコープはデフォルトのサブスクリプションとする。

実際のプロジェクトではリソースグループが払い出されて、リソースグループ配下のリソース構築から実施するという事も想定されるので、今後azdコマンドが改善されることを期待したい。

## [Tips.3] 再デプロイ方法

なぜこのTipsを書いたかというと、以下の場合、azdコマンドはbicepテンプレートに変更がないと判断し、再デプロイを実行してくれないため。

- スコープを”ResourceGroup”にして”azd up”コマンドでデプロイ
- 手動でリソースを削除
- bicepテンプレート、パラメータファイルを変更せずに”azd up”コマンドで再デプロイ

この動作から察するに、“azd”コマンドはリソースの存在有無は確認しないようで、前回の”azd up”コマンド実行時からのbicepテンプレート変更有無を確認し、変更がない場合、”  (-) Skipped: Didn't find new changes.” というメッセージを出力して何もせずに終了する。

bicepテンプレートファイルが更新されたかどうかは以下の２つでチェックしていると思われる。なぜなら、単純にファイルを上書きしてファイルの更新日時だけ更新しても、再デプロイが実行されなかったが、ファイル内で１つ改行を入れただけで再デプロイされた。

- ファイルの更新日時
- ファイルサイズ

```bash
sato@[10:10:13]:~/proj/RagSystem% azd up

  WARNING: Feature 'resourceGroupDeployments' is in alpha stage.
  To learn more about alpha features and their support, visit https://aka.ms/azd-feature-stages.

Packaging services (azd package)

Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

  WARNING: Feature 'resourceGroupDeployments' is in alpha stage.
  To learn more about alpha features and their support, visit https://aka.ms/azd-feature-stages.

Subscription: <サブスクリプション名> (xxx)
Location: East US 2

  (-) Skipped: Didn't find new changes.

Deploying services (azd deploy)

SUCCESS: Your up workflow to provision and deploy to Azure completed in 5 seconds.
sato@[10:10:44]:~/proj/RagSystem%
```

## [Tips.4] resourceGroupDeploymentsモードを解除する方法

最後にalphaバージョンのresourceGroupDeploymentモードを解除する方法。

### 現在のazdコマンドの設定情報の確認

azdコマンドの設定情報は”azd config show”で見ることができる。この中で”alpha”というオブジェクトに記載されている項目が、現在有効になっているalphaバージョンの機能。

以下は、resourceGroupDeploymentが”on”になっている。

```bash
sato@[11:13:08]:~/proj/RagSystem% azd config show
{
  "alpha": {
    "resourceGroupDeployments": "on"
  },
  "defaults": {
    "location": "japaneast",
    "subscription": "xxx"
  },
  "template": {
    "sources": {
      "awesome-azd": {
        "key": "awesome-azd",
        "location": "https://aka.ms/awesome-azd/templates.json",
        "name": "Awesome AZD",
        "type": "awesome-azd"
      }
    }
  }
}
sato@[11:13:12]:~/proj/RagSystem%
```

### alphaバージョンの機能を解除

これを解除するには、”azd config unset”コマンドを使ってresourceGroupDeploymentを削除すれば良い。

```bash
sato@[11:13:12]:~/proj/RagSystem% azd config unset alpha.resourceGroupDeployments
sato@[11:13:17]:~/proj/RagSystem% azd config show
{
  "alpha": {},
  "defaults": {
    "location": "japaneast",
    "subscription": "xxx"
  },
  "template": {
    "sources": {
      "awesome-azd": {
        "key": "awesome-azd",
        "location": "https://aka.ms/awesome-azd/templates.json",
        "name": "Awesome AZD",
        "type": "awesome-azd"
      }
    }
  }
}
sato@[11:13:19]:~/proj/RagSystem% 
```

### Subscriptionへの権限復活

これ、忘れないように。

スコープを”Subscription”に戻した場合、リソースグループの作成削除も必要になるため、親オブジェクトであるデプロイ先のサブスクリプションに対する”Contributor”（共同作成者）以上の権限が必要になるのでこれを付与する。

### azdの認証情報の更新

最後に、”azd auth logout”してから”azd auth login”して認証情報をアップデートすると、Subscriptionスコープで”azd up”や”azd down”が実行できるようになる。

# 4. 作業結果のソースコード

ここまでの全容は以下を参照されたし。

https://github.com/masatoshisato/RagSystem/tree/v1.0.3-rg-scope