最近加入到一個客戶的 Azure 訂用帳戶設定 CI/CD,在做這件事情之前,當然是先建立好 Service Principal (服務主體),然後才進行角色指派,讓該服務主體擁有必要的權限才能進行部署。不過建立完成後才發現,我忘記將 Storage account (儲存體帳號) 的 Storage Blob Data Contributor
角色指派給我建立好的 Service Principal (服務主體),以致於我無法透過 AzCopy 複製檔案進 Blob 容器中。最悲劇的地方,就是我的 Guest 身份竟然無法讀取 Service Principal (服務主體) 的任何資訊,導致我無法順利指派角色,這篇文章我就來說說我的最終解法!
問題描述
以下是角色指派的過程,你會發現你的 Guest 身份完全無法讀取到 Service Principal (服務主體) 的任何資訊,所以你是無法使用 Azure Portal 進行授權的:
關於 Guest 在 Azure AD 中的權限,可以參見 Restrict guest access permissions in Azure Active Directory 說明。
為了這個問題,我有嘗試使用 Azure CLI 來進行授權
-
PowerShell
az role assignment create `
--role "Storage Blob Data Contributor" `
--assignee sp-cicd `
--scope "/subscriptions/$subscriptionId/resourceGroups/em-s/providers/Microsoft.Storage/storageAccounts/$storageAccountName"
-
Bash
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee sp-cicd \
--scope "/subscriptions/$subscriptionId/resourceGroups/em-s/providers/Microsoft.Storage/storageAccounts/$storageAccountName"
結果得到以下結果:
Insufficient privileges to complete the operation.
這下尷尬了,兩個方式都無法進行角色指派,但跟客戶申請「特權帳號」又需要好幾天時間,實在有點頭疼!
解決方案 1
我後來嘗試了很多方法,我透過 az role assignment create -h
找到了另一種指派角色的方法,也就是直接指定 --assignee-principal-type
與 --assignee-object-id
參數,想不到竟然成功了! 😃
-
PowerShell
az role assignment create `
--role "Storage Blob Data Contributor" `
--assignee-principal-type ServicePrincipal `
--assignee-object-id 'f52ee8ae-1a33-4a2c-9f36-cdab66bd2ce8' `
--scope "/subscriptions/$subscriptionId/resourceGroups/em-s/providers/Microsoft.Storage/storageAccounts/$storageAccountName"
-
Bash
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee-principal-type ServicePrincipal \
--assignee-object-id 'f52ee8ae-1a33-4a2c-9f36-cdab66bd2ce8' \
--scope "/subscriptions/$subscriptionId/resourceGroups/em-s/providers/Microsoft.Storage/storageAccounts/$storageAccountName"
當你在使用 Azure CLI 建立 Service Principal (服務主體) 的時候,預設回傳的 JSON 屬性如下:
az ad sp create-for-rbac --name sp-cicd --role Contributor -o json
{
"appId": "46e15d71-3451-0000-aa25-0ce6d2c913eb",
"displayName": "sp-cicd",
"name": "46e15d71-3451-0000-aa25-0ce6d2c913eb",
"password": "9z$bTSfwDkCQtUrz2Gn6X3K4k@MD52ajjm",
"tenant": "00000000-b057-4d4d-b7a8-ec2b4e8b9fd0"
}
而透過 az role assignment create
指派角色時,重點在於 --assignee-object-id
需要傳入 Service Principal (服務主體) 的 Object ID,但這應該如何取得呢?以下有兩種方法:
-
找任何一個 Azure AD 的 Member 幫你進 Azure AD 查詢 Service Principal (服務主體) 的 Object ID (如下圖示)
-
切換到 Subscription (訂用帳戶) 的 Access Control (IAM) 查看 Service Principal (服務主體) 的詳細資料,然後從網址列查到 Object ID (如下圖示)
因為你執行 az ad sp create-for-rbac
的時候,預設就會幫你建立一個 Access Control (IAM) 角色指派到 Subscription (訂用帳戶),因此你可以用這招查到 Service Principal (服務主體) 的 Object ID!
使用 PowerShell 查詢服務主體 Object ID 的方法
還有一種取得 Object ID 的方法是透過 Windows PowerShell 的 AzureAD 模組 下的 Get-AzureADServicePrincipal
Cmdlet,這個 Cmdlet 可以直接透過 Service Principal (服務主體) 的 顯示名稱 (displayName) 來獲取 Azure AD 中的完整資訊,其中當然包含了 Object ID 屬性!
-
請開啟 Windows PowerShell 視窗
-
安裝 AzureAD 模組
Install-Module AzureAD
-
匯入 AzureAD 模組
Import-Module AzureAD
如果你使用 PowerShell Core 的話,請務必改用以下命令匯入,否則你將無法連接 AzureAD:
Import-Module AzureAD -UseWindowsPowershell
-
指定 TenantId 連接 AzureAD 目錄
$tenantId = '00000000-b057-4d4d-b7a8-ec2b4e8b9fd0'
Connect-AzureAD -TenantId $tenantId
-
指定 TenantId 連接 AzureAD 目錄
Get-AzureADServicePrincipal -Filter "DisplayName eq 'sp-cicd'"
Get-AzureADServicePrincipal -Filter "DisplayName eq 'sp-cicd'" | fl
預期結果:
ObjectId AppId DisplayName
-------- ----- -----------
f52ee8ae-1a33-4a2c-9f36-cdab66bd2ce8 cf3ac9e0-16b1-4d4f-8f8a-da393cf84c6d sp-cicd
相關連結