在 Azure 容器執行個體 中使用受管理身份

使用 Azure 資源的管理身份 ,在 Azure 容器實例中執行程式碼,與其他 Azure 服務互動。 你不需要在程式碼中保留任何秘密或憑證。 此功能提供容器實例部署,並以 Microsoft Entra ID 自動管理身份。

在本文中,您將進一步了解容器實例中的受管理身份。 你也:

  • 在容器群組中啟用使用者指派或系統指派的身份。
  • 授予身份存取權限至 Azure 金鑰保存庫。
  • 利用管理身份從運行中的容器存取金鑰保險庫。

調整範例以啟用並使用容器實例中的身份,以存取其他 Azure 服務。 這些範例為互動式範例。 實務上,你的容器映像會執行程式碼來存取 Azure 服務。

為什麼要使用受控識別?

您可以在執行中的容器使用受控身分識別,向任何支援 Microsoft Entra 驗證的服務進行驗證,而無須在您的容器程式碼中管理認證。 對於不支援 Microsoft Entra 認證的服務,你可以將秘密存放在 Azure 金鑰庫中,並利用管理身份存取金鑰庫以取得憑證。 欲了解更多關於使用受管理身份的資訊,請參閱「Azure 資源的受管理身份是什麼?」。

啟用受控識別

當您建立容器群組時,可藉由設定 ContainerGroupIdentity 屬性來啟用一或多個受控識別。 你也可以在容器群組運行後啟用或更新受管理身份。 任一動作都會讓容器群組重新啟動。 要在新建或現有容器群組上設定身份,請使用 Azure CLI、Azure Resource Manager 範本、YAML 檔案或其他 Azure 工具。

容器實例支援兩種類型的 Azure 受管理身份:使用者指派與系統指派。 在容器群組上,您可以啟用一個系統指派的身分識別,一或多個使用者指派的身分識別,或是同時啟用這兩種身分識別。 如果您不熟悉 Azure 資源的受控識別,請參閱概觀。

建立受控識別

若要使用受控識別,必須將訂閱中一或多個 Azure 服務資源 (例如 Web 應用程式、金鑰保存庫或儲存體帳戶) 的存取權授與該身分識別。 在運行中的容器中使用管理身份,類似於在 Azure 虛擬機(VM)中使用身份。 欲了解更多資訊,請參閱 VM 指引中關於使用 權杖、 Azure PowerShell 或 Azure CLI 或 Azure SDK 的指引。

先決條件

  • 本文需要 2.0.49 版或更新版本的 Azure CLI。 如果您使用 Azure Cloud Shell,則已安裝最新版本。

建立 Azure 金鑰保存庫

本文範例使用容器實例中的管理身份來存取 Azure Key Vault 的秘密。

首先,使用下列 az group create 命令,在 eastus 位置中建立一個名為 myResourceGroup 的資源群組:

az group create --name myResourceGroup --location eastus

使用 az keyvault create 命令來建立金鑰保存庫。 請務必指定一個唯一的金鑰保存庫名稱。

az keyvault create \
  --name mykeyvault \
  --resource-group myResourceGroup \
  --location eastus

透過 az keyvault secret set 指令,將範例秘密儲存在金鑰庫中:

az keyvault secret set \
  --name SampleSecret \
  --value "Hello Container Instances" \
  --description ACIsecret --vault-name mykeyvault

請繼續以下範例,透過容器實例中使用者指派或系統指派的管理身份來存取金鑰庫。

範例 1:使用使用者指派的身份來存取 Azure 金鑰保險庫

建立身分識別

首先,請使用 az identity create 指令在訂閱中建立一個身份。 你可以使用與建立金鑰保險庫相同的資源群組。 你也可以使用其他的。

az identity create \
  --resource-group myResourceGroup \
  --name myACIId

若要在接下來的步驟中使用身分識別,請使用 az identity show 命令,以將身分識別的服務主體識別碼和資源識別碼儲存在變數中。

# Get service principal ID of the user-assigned identity
SP_ID=$(az identity show \
  --resource-group myResourceGroup \
  --name myACIId \
  --query principalId --output tsv)

# Get resource ID of the user-assigned identity
RESOURCE_ID=$(az identity show \
  --resource-group myResourceGroup \
  --name myACIId \
  --query id --output tsv)

將金鑰保存庫存取權授與使用者指派的身分識別

請執行下列 az keyvault set-policy 命令,以針對金鑰保存庫設定存取原則。 下列範例會允許使用者指派的身分識別從金鑰保存庫取得祕密:

 az keyvault set-policy \
    --name mykeyvault \
    --resource-group myResourceGroup \
    --object-id $SP_ID \
    --secret-permissions get

在容器群祖上啟用使用者指派的身分識別

執行下列 az container create 命令,以根據 Microsoft 的 azure-cli 影像建立容器執行個體。 這個範例提供了一個單一容器群組,你可以互動式地執行 Azure CLI 以存取其他 Azure 服務。 在本節中,只會使用基底作業系統。 如需在容器中使用 Azure CLI 的範例,請參閱在容器群組上啟用系統指派的身分識別 (部分機器翻譯)。

--assign-identity 參數會將使用者指派的受控識別傳遞給群組。 長時間執行的命令會讓容器保持執行。 這個範例使用了與建立金鑰保險庫相同的資源群組,但你可以指定不同的資源群組。

az container create \
  --resource-group myResourceGroup \
  --name mycontainer \
  --image mcr.microsoft.com/azure-cli \
  --assign-identity $RESOURCE_ID \
  --command-line "tail -f /dev/null"

幾秒內,Azure CLI 就會回覆,表示部署已完成。 請使用 az container show 命令來檢查其狀態。

az container show \
  --resource-group myResourceGroup \
  --name mycontainer

identity輸出中的該區段與以下範例相似,顯示身份元設定在容器群組中。 principalID 是位於 userAssignedIdentities 下方的你在 Microsoft Entra ID 中建立的身份的服務主體:

[...]
"identity": {
    "principalId": "null",
    "tenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
    "type": "UserAssigned",
    "userAssignedIdentities": {
      "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/danlep1018/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myACIId": {
        "clientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
        "principalId": "aaaaaaaa-bbbb-cccc-1111-222222222222"
      }
    }
  },
[...]

使用用戶分配的身份從金鑰保險庫取得機密

現在,您可以使用執行中容器執行個體內的受控識別來存取金鑰保存庫。 首先,打開容器中的 Bash 外殼:

az container exec \
  --resource-group myResourceGroup \
  --name mycontainer \
  --exec-command "/bin/bash"

在容器裡的 Bash shell 執行以下指令。 要取得使用 Microsoft Entra ID 驗證金鑰庫的存取權杖,請執行以下指令:

client_id="00001111-aaaa-2222-bbbb-3333cccc4444"
curl "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net&client_id=$client_id" -H Metadata:true -s

輸出:

{"access_token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSJ9......xxxxxxxxxxxxxxxxx","refresh_token":"","expires_in":"28799","expires_on":"1539927532","not_before":"1539898432","resource":"https://vault.azure.net/","token_type":"Bearer"}

若要將存取權杖儲存在變數中以在後續命令中用來進行驗證,請執行下列命令:

TOKEN=$(curl 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net' -H Metadata:true | jq -r '.access_token')

現在用存取存根驗證至金鑰管理庫並讀取一個機密。 請務必在 URL (https://mykeyvault.vault.azure.net/...) 中替換您的金鑰保存庫名稱:

curl https://mykeyvault.vault.azure.net/secrets/SampleSecret/?api-version=7.4 -H "Authorization: Bearer $TOKEN"

這個回應看起來和下面這個展示祕密的例子很相似。 在你的程式碼中,你會解析這個輸出來取得祕密。 接著,請在後續作業中使用此祕密來存取另一個 Azure 資源。

{"value":"Hello Container Instances","contentType":"ACIsecret","id":"https://mykeyvault.vault.azure.net/secrets/SampleSecret/xxxxxxxxxxxxxxxxxxxx","attributes":{"enabled":true,"created":1539965967,"updated":1539965967,"recoveryLevel":"Purgeable"},"tags":{"file-encoding":"utf-8"}}

範例 2:使用系統指派的身份來存取 Azure 金鑰保險庫

在容器群祖上啟用系統指派的身分識別

執行下列 az container create 命令,以根據 Microsoft 的 azure-cli 影像建立容器執行個體。 這個範例提供了一個單一容器群組,你可以互動式地執行 Azure CLI 以存取其他 Azure 服務。

沒有其他值的 --assign-identity 參數會在該群組上啟用系統指派的受控身份。 身分識別的範圍設為容器群組的資源群組。 長時間執行的命令會讓容器保持執行。 此範例會使用建立金鑰保存庫所使用的相同資源群組,其位於身分識別的範圍內。

# Get the resource ID of the resource group
RG_ID=$(az group show --name myResourceGroup --query id --output tsv)

# Create container group with system-managed identity
az container create \
  --resource-group myResourceGroup \
  --name mycontainer \
  --image mcr.microsoft.com/azure-cli \
  --assign-identity --scope $RG_ID \
  --command-line "tail -f /dev/null"

幾秒內,你應該會收到 Azure CLI 的回應,表示部署已完成。 請使用 az container show 命令來檢查其狀態。

az container show \
  --resource-group myResourceGroup \
  --name mycontainer

identity輸出中的部分看起來與以下範例相似,顯示系統指派的身份是在 Microsoft Entra ID 中建立的:

[...]
"identity": {
    "principalId": "bbbbbbbb-cccc-dddd-2222-333333333333",
    "tenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
    "type": "SystemAssigned",
    "userAssignedIdentities": null
},
[...]

將變數設定為身分識別之 principalId (服務主體識別碼) 的值,以在稍後的步驟中使用。

SP_ID=$(az container show \
  --resource-group myResourceGroup \
  --name mycontainer \
  --query identity.principalId --out tsv)

將金鑰保存庫存取權授與容器群組

請執行下列 az keyvault set-policy 命令,以針對金鑰保存庫設定存取原則。 下列範例會允許系統管理的身分識別從金鑰保存庫取得祕密:

 az keyvault set-policy \
   --name mykeyvault \
   --resource-group myResourceGroup \
   --object-id $SP_ID \
   --secret-permissions get

使用容器組身分識別從金鑰保存庫取得機密

現在,您可以使用受控識別來存取執行中容器執行個體內的金鑰保存庫。 首先,打開容器中的 Bash 外殼:

az container exec \
  --resource-group myResourceGroup \
  --name mycontainer \
  --exec-command "/bin/bash"

在容器裡的 Bash shell 執行以下指令。 首先,使用管理身份登入 Azure CLI:

az login --identity

從執行中的容器,從金鑰保存庫擷取祕密:

az keyvault secret show \
  --name SampleSecret \
  --vault-name mykeyvault --query value

擷取祕密的值:

"Hello Container Instances"

使用資源管理員範本啟用管理身份

若要使用資源管理器範本在容器群組中啟用受管理身份,請將identity物件的Microsoft.ContainerInstance/containerGroups屬性設為ContainerGroupIdentity物件。 下列程式碼片段顯示針對不同案例設定的 identity 屬性。 欲了解更多資訊,請參閱資源管理器範本參考。 指定 apiVersion 最低版本 2018-10-01。

使用者指派的身分識別

使用者指派身份是以下形式的資源識別碼:

"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}"

您可以啟用一或多個使用者指派的身分識別。

"identity": {
    "type": "UserAssigned",
    "userAssignedIdentities": {
        "myResourceID1": {
            }
        }
    }

系統指派的身分識別

"identity": {
    "type": "SystemAssigned"
    }

系統指派與使用者指派識別

在容器群組上,您可以啟用一個系統指派的身分識別及一或多個使用者指派的身分識別。

"identity": {
    "type": "SystemAssigned, UserAssigned",
    "userAssignedIdentities": {
        "myResourceID1": {
            }
        }
    }
...

透過使用 YAML 檔案啟用管理身份

若要在使用 YAML 檔案部署的容器群組中啟用受管理身份,請包含以下 YAML。 指定 apiVersion 最低版本 2018-10-01。

使用者指派的身分識別

使用者指派身份是以下形式的資源識別碼:

'/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}'

您可以啟用一或多個使用者指派的身分識別。

identity:
  type: UserAssigned
  userAssignedIdentities:
    {'myResourceID1':{}}

系統指派的身分識別

identity:
  type: SystemAssigned

系統指派與使用者指派識別

在容器群組上,您可以啟用一個系統指派的身分識別及一或多個使用者指派的身分識別。

identity:
  type: SystemAssigned, UserAssigned
  userAssignedIdentities:
   {'myResourceID1':{}}

Windows 容器中的受管身份

Windows 容器群組的管理身份與 Linux 容器群組的運作方式不同。 對於 Windows 容器,無法使用 metadata server (169.254.169.254) 來取得 Microsoft Entra 權杖。 相反地,將 token 請求發送到 IDENTITY_ENDPOINT 並包含 IDENTITY_HEADER 為秘密標頭。 Azure 會注入 IDENTITY_ENDPOINT 和 IDENTITY_HEADER 作為容器中的環境變數。

建立一個帶有管理身份的 Windows 容器群組

執行以下 az container create 指令,建立一個帶有使用者指派管理身份的 Windows 容器群組。 用你自己的值替換資源群組、名稱和身份資源 ID。

az container create \
  --resource-group myResourceGroup \
  --name mywindowscontainer \
  --image mcr.microsoft.com/windows/nanoserver:1809 \
  --assign-identity $RESOURCE_ID \
  --os-type windows \
  --command-line "ping -t localhost"

在 Windows 容器中取得一個令牌

如果你使用的是使用者指派的管理身份,請在請求中包含 principalId 。 如果你使用的是系統指派的管理身份,請省略 principalId。

curl -G "%IDENTITY_ENDPOINT%" ^
  --data-urlencode "resource=https://vault.azure.net" ^
  --data-urlencode "principalId=<principal-id>" ^
  -H "secret: %IDENTITY_HEADER%"

PowerShell 要求範例:

$identityEndpoint = $env:IDENTITY_ENDPOINT
$identityHeader = $env:IDENTITY_HEADER
$resource = "https://vault.azure.net"
$principalId = "aaaaaaaa-bbbb-cccc-1111-222222222222"

$response = Invoke-RestMethod -Uri $identityEndpoint `
    -Method Get `
    -Headers @{ secret = $identityHeader } `
    -Body @{ resource = $resource; principalId = $principalId } `
    -ContentType "application/x-www-form-urlencoded"

$response.access_token

az login依賴元資料伺服器(169.254.169.254)的指令函式庫和用戶端函式庫在 Windows 容器中無法運作。

虛擬網路中的 Windows 容器無法連接到受管理身份端點。 因此,在這種情況下你無法產生管理身份的令牌。

Tip

對於 使用者指派 的身份,請在令牌請求中包含該身份 principalId ,如前述腳本所示。 對於 系統指派 的身份,省略 principalId。

範例:在 Windows 容器中讀取 Azure 儲存體 Blob

這個端對端範例會部署具有使用者指派身分識別的 Windows 容器群組,接著在容器內使用該身分識別下載 Blob。

首先,授予使用者指定的身份存取儲存帳號(一次)。 儲存體 Blob 資料讀取者角色足以下載 Blob:

PRINCIPAL_ID=$(az identity show --resource-group myResourceGroup --name myACIId --query principalId --output tsv)
STORAGE_ID=$(az storage account show --name mystorageaccount --query id --output tsv)

az role assignment create \
  --assignee-object-id $PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Storage Blob Data Reader" \
  --scope $STORAGE_ID

接著,使用 YAML 檔案(deploy-aci.yaml)部署 Windows 容器群組。 長時間執行的命令會讓群組維持運作,讓你可以 az container exec 進入其中:

apiVersion: '2023-05-01'
location: eastus
name: mywindowscg
type: Microsoft.ContainerInstance/containerGroups
identity:
  type: UserAssigned
  userAssignedIdentities:
    '/subscriptions/<subscriptionId>/resourceGroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myACIId': {}
properties:
  osType: Windows
  restartPolicy: Always
  containers:
    - name: mycontainer
      properties:
        image: mcr.microsoft.com/powershell:lts-nanoserver-ltsc2022
        command:
          - pwsh
          - -NoProfile
          - -Command
          - 'while ($true) { Start-Sleep -Seconds 3600 }'
        resources:
          requests:
            cpu: 2
            memoryInGB: 4
az container create --resource-group myResourceGroup --file deploy-aci.yaml

群組運行後,請在容器中開啟一個 PowerShell 殼:

az container exec \
  --resource-group myResourceGroup \
  --name mywindowscg \
  --container-name mycontainer \
  --exec-command "pwsh"

在容器殼層內,請求一個指定為儲存範圍的憑證,並用它來下載該 blob。 因為容器沒有包含 Azure CLI,請直接傳遞身份:principalId

$principalId = "<user-assigned-identity-principalId>"
$storageAccount = "mystorageaccount"
$container = "mycontainer"
$blob = "hello.txt"

$tokenResponse = Invoke-RestMethod -Uri $env:IDENTITY_ENDPOINT `
    -Method Get `
    -Headers @{secret = $env:IDENTITY_HEADER} `
    -Body @{resource = "https://storage.azure.com/"; principalId = $principalId} `
    -ContentType "application/x-www-form-urlencoded"

$blobUrl = "https://$storageAccount.blob.core.windows.net/$container/$blob"
Invoke-WebRequest -Uri $blobUrl `
    -Headers @{ Authorization = "Bearer $($tokenResponse.access_token)"; "x-ms-version" = "2023-11-03" } `
    -OutFile "C:\$blob"

Get-Content "C:\$blob"

容器僅使用其管理身份來驗證儲存。 調整resource值與目標端點以呼叫其他 Azure 服務。