﻿# 如何以 Guest 身份將 Azure 的 Service Principal (服務主體) 加入角色指派

最近加入到一個客戶的 Azure 訂用帳戶設定 CI/CD，在做這件事情之前，當然是先建立好 Service Principal (服務主體)，然後才進行角色指派，讓該服務主體擁有必要的權限才能進行部署。不過建立完成後才發現，我忘記將 Storage account (儲存體帳號) 的 `Storage Blob Data Contributor` 角色指派給我建立好的 Service Principal (服務主體)，以致於我無法透過 [AzCopy](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10?WT.mc_id=DT-MVP-4015686) 複製檔案進 Blob 容器中。最悲劇的地方，就是我的 Guest 身份竟然無法讀取 Service Principal (服務主體) 的任何資訊，導致我無法順利指派角色，這篇文章我就來說說我的最終解法！

### 問題描述

以下是角色指派的過程，你會發現你的 Guest 身份完全無法讀取到 Service Principal (服務主體) 的任何資訊，所以你是無法使用 Azure Portal 進行授權的：

![Add role assignment](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/4ac205b8be9045ce6130-148774838-4f2867b9-2c65-4b62-b466-dc680a5e8c44.png)

> 關於 Guest 在 Azure AD 中的權限，可以參見 [Restrict guest access permissions in Azure Active Directory](https://learn.microsoft.com/en-us/azure/active-directory/enterprise-users/users-restrict-guest-permissions?WT.mc_id=DT-MVP-4015686) 說明。

為了這個問題，我有嘗試使用 Azure CLI 來進行授權

-   PowerShell
    
    ```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
    
    ```powershell
    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
    
    ```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
    
    ```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"
    ```
    

當你在使用 Azure CLI 建立 Service Principal (服務主體) 的時候，預設回傳的 JSON 屬性如下：

```bash
az ad sp create-for-rbac --name sp-cicd --role Contributor -o json
```

```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**，但這應該如何取得呢？以下有兩種方法：

1.  找任何一個 Azure AD 的 Member 幫你進 Azure AD 查詢 Service Principal (服務主體) 的 **Object ID** (如下圖示)
    
    ![App registrations > Object ID](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/f907d9b5b2cde222805f-148781626-0f9c7a67-ea4b-4218-96a6-a24f9781f636.png)
    
2.  切換到 Subscription (訂用帳戶) 的 **Access Control (IAM)** 查看 Service Principal (服務主體) 的詳細資料，然後從**網址列**查到 **Object ID** (如下圖示)
    
    ![Access Control (IAM)](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/52d16eda554ee353e9c4-148782626-4e72d52b-e3b2-4396-b34b-0fc5754d5ad6.png)
    
    ![從網址列查到 Object ID](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/27983e18b83affdd2998-148783034-c4bbb608-8f56-4b2c-8ba2-933ad92a1834.png)
    
    > 因為你執行 `az ad sp create-for-rbac` 的時候，預設就會幫你建立一個 **Access Control (IAM)** 角色指派到 **Subscription** (訂用帳戶)，因此你可以用這招查到 Service Principal (服務主體) 的 **Object ID**！
    

### 使用 PowerShell 查詢服務主體 Object ID 的方法

還有一種取得 **Object ID** 的方法是透過 [Windows PowerShell 的 AzureAD 模組](https://learn.microsoft.com/en-us/powershell/azure/active-directory/install-adv2?view=azureadps-2.0&WT.mc_id=DT-MVP-4015686) 下的 `Get-AzureADServicePrincipal` Cmdlet，這個 Cmdlet 可以直接透過 Service Principal (服務主體) 的 **顯示名稱** (displayName) 來獲取 Azure AD 中的完整資訊，其中當然包含了 **Object ID** 屬性！

1.  請開啟 Windows PowerShell 視窗
    
2.  安裝 AzureAD 模組
    
    ```powershell
    Install-Module AzureAD
    ```
    
3.  匯入 AzureAD 模組
    
    ```powershell
    Import-Module AzureAD
    ```
    
    如果你使用 PowerShell Core 的話，請務必改用以下命令匯入，否則你將無法連接 AzureAD：
    
    ```powershell
    Import-Module AzureAD -UseWindowsPowershell
    ```
    
4.  指定 TenantId 連接 AzureAD 目錄
    
    ```powershell
    $tenantId = '00000000-b057-4d4d-b7a8-ec2b4e8b9fd0'
    Connect-AzureAD -TenantId $tenantId
    ```
    
5.  指定 TenantId 連接 AzureAD 目錄
    
    ```powershell
    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
    ```
    

### 相關連結

-   [使用 Azure CLI 來建立 Azure 服務主體](https://learn.microsoft.com/zh-tw/cli/azure/create-an-azure-service-principal-azure-cli?WT.mc_id=DT-MVP-4015686)
-   [Get started with AzCopy | Microsoft Docs](https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10?WT.mc_id=DT-MVP-4015686)
-   [Restrict guest user access permissions - Azure Active Directory | Microsoft Docs](https://learn.microsoft.com/en-us/azure/active-directory/enterprise-users/users-restrict-guest-permissions?WT.mc_id=DT-MVP-4015686)
-   [Create a user delegation SAS for a container or blob with the Azure CLI](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-user-delegation-sas-create-cli?WT.mc_id=DT-MVP-4015686)
-   [Exchange Online - Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core · Issue #11070 · PowerShell/PowerShell](https://github.com/PowerShell/PowerShell/issues/11070#issuecomment-722472302)
