Template Deployment を使って Azure リソースをデプロイする際に、同時に RBAC 周りの設定を行いたいケースがあったので、世界のぶちぞう RD に聞いたら教えてくれました。
結局は後述する制約によって上手くいかなかったのですが、折角なのでメモとして残します。
ドキュメントはイマイチな感じですが、RBAC は Microsoft.Authorization
Provider で管理されているので、そこに対してロール割り当てのリソースを新しく作る形になります。
Azure Portal からはデプロイ先のリソースグループと含まれるリソースに対してのみ操作が行えます。サブスクリプションスコープで RBAC を弄る必要がある場合は Azure CLI を使ってデプロイする必要があります。
あまり意識してなかったですが、コマンドは明確に分離されています。
az deployment
- サブスクリプションスコープに対してデプロイ
az group deployment
- リソースグループに対してデプロイ
お分かりの通り Azure Portal の Template Deployment はリソースグループに対してのデプロイなので、リソースグループとその中のリソース以外を対象に出来ません。これが非常に都合が悪かったです。
従って ARM Template で同時にデプロイするリソースに対して割り当てる場合は上手くいきます。
ロール定義の GUID を探す
リソースを作成するためには定義ロールの GUID が必要です。ロール定義もリソースとして ARM 上に用意されているので、Azure CLI を使えば簡単に引っ張ってこれます。
必要なのは GUID と名前ぐらいなので、項目を絞り込むようにすると見やすいです。
az role definition list --query "[].[roleName,name]" --output table
実行すると定義済みのロールが全て表示されます。組み込みのロールが持つ GUID はサブスクリプションなど関係なくグローバルで共通の値です。
ドキュメントにもありましたが、よく使うロールの GUID は以下のような感じです。
- Owner =
8e3af657-a8ff-443c-a75c-2fe8c4bcb635
- Contributor =
b24988ac-6180-42a0-ab88-20f7382dd24c
- Reader =
acdd72a7-3385-48ef-bd42-f606fba81ae7
ロールの GUID が分かれば、後はロール割り当てのリソースを作成するだけですが、地味に癖があります。とりあえずリソースグループと各リソースで書き方が違うので、それぞれ分けて紹介します。
リソースグループにロール割り当てを追加
サブスクリプションとリソースグループに対してロール割り当てを追加する場合は、シンプルに type
に Microsoft.Authorization/roleAssignments
を指定すれば良いです。
割り当てを追加する最小限の ARM Template は以下のようになります。
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "principalId": { "type": "string" }, "roleNameGuid": { "type": "string", "defaultValue": "[newGuid()]" } }, "resources": [ { "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2018-09-01-preview", "name": "[parameters('roleNameGuid')]", "properties": { "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "principalId": "[parameters('principalId')]" } } ] }
この例では入力された PrincipalId
に対して Reader
ロールを割り当てています。実際にテンプレートでは PrincipalId
は Managed Identity の System Assigned で作成したものを使うことが多いはずです。
今回は既に作成済みの PrincipalId
を使ってデプロイします。謎の roleNameGuid
ですが、ロール割り当てのリソース作成時に絶対必要なものです。
ARM Template の仕様で newGuid
関数はパラメータの defaultValue
でしか使えないので、こういう不格好な形になっています。冪等性のためには仕方ない部分ですが、不格好です。
デプロイが完了するとリソースグループに対して、ロール割り当てが追加されたのが確認できます。
App Service の Managed Identity で作成された PrincipalId
を使ったので、このような表示となります。
各リソースにロール割り当てを追加
リソースグループ内の各リソースに割り当てる場合もほぼ同じですが、type
と name
の値が割り当てたいリソース毎に異なってくるので複雑です。
以下の例のように type
にはリソースプロバイダを指定しつつ、name
には対象となるリソース名を含める形する必要があります。
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "principalId": { "type": "string" }, "webAppName": { "type": "string" }, "roleNameGuid": { "type": "string", "defaultValue": "[newGuid()]" } }, "resources": [ { "type": "Microsoft.Web/sites/providers/roleAssignments", "apiVersion": "2018-09-01-preview", "name": "[concat(parameters('webAppName'), '/Microsoft.Authorization/', parameters('roleNameGuid'))]", "properties": { "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "principalId": "[parameters('principalId')]" } } ] }
微妙に手間な書き方ですが、このテンプレートをデプロイすると App Service に対してロール割り当てを追加できます。実行結果はリソースグループの時と同じなので省略します。
Managed Identity (System Assigned) にアクセス権限を付ける
もはやアプリ向けに手動で Service Principal を作る時代は終わっているので、Managed Identity を空気のように利用していきます。
今回は App Service に対するテンプレートを書きます。Managed Identity を自動生成する場合は identity
プロパティを追加するだけなので簡単です。
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "functionAppName": { "type": "string" }, "roleNameGuid": { "type": "string", "defaultValue": "[newGuid()]" } }, "resources": [ { "type": "Microsoft.Web/sites", "name": "[parameters('functionAppName')]", "apiVersion": "2018-11-01", "location": "[resourceGroup().location]", "kind": "functionapp", "identity": { "type": "SystemAssigned" }, "properties": { /* 省略 */ } }, { "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2018-09-01-preview", "name": "[parameters('roleNameGuid')]", "dependsOn": [ "[resourceId('Microsoft.Web/sites', parameters('functionAppName'))]" ], "properties": { "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions','acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "principalId": "[reference(resourceId('Microsoft.Web/sites', parameters('functionAppName')), '2018-11-01', 'Full').identity.principalId]" } } ] }
作成した App Service に紐づいた PrincipalId
は reference
関数を使えば参照出来るので、後はその値を使ってロール割り当てを追加するだけです。
reference
関数では Full
を指定しないと値が取れなかった気がします。とても簡単でした。
User Assigned Managed Identity にアクセス権限を付ける(問題あり)
つい先日 App Service 向けの User Assigned Managed Identity が GA したので、今後は利用することが増えていく気がしています。
System Assigned は 1 つの App Service に必ず 1 つ生成されますが、User Assigned Managed Identity は個別に作成して、自由に App Service へ割り当て出来るので管理しやすいです。
User Assigned Managed Identity も単なるリソースの一つなので、ARM Template を使って生成できます。
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "identityName": { "type": "string" }, "roleNameGuid": { "type": "string", "defaultValue": "[newGuid()]" } }, "resources": [ { "type": "Microsoft.ManagedIdentity/userAssignedIdentities", "apiVersion": "2018-11-30", "name": "[parameters('identityName')]", "location": "[resourceGroup().location]" }, { "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2018-09-01-preview", "name": "[parameters('roleNameGuid')]", "dependsOn": [ "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]" ], "properties": { "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", "principalId": "[reference(parameters('identityName')).principalId]" } } ] }
なので組み合わせると、ロール周りの設定も同時に出来て非常に便利!と思っていたのですが、どうも Managed Identity の作成完了が AAD への反映より早いらしくロール割り当てを追加時にエラーとなります。
数秒遅延させると上手くいくという残念な状態なので、App Service を作る前に User Assigned Managed Identity を作成しておいて、最後にロール割り当てを追加すると上手くいきます。*1
*1:直してほしいのでフィードバックする予定