对 Azure 自动化帐户使用用户分配的托管标识

本文介绍如何为 Azure 自动化帐户添加用户分配的托管标识,以及如何使用该标识来访问其他资源。 有关托管标识如何与 Azure 自动化配合使用的详细信息,请参阅托管标识

注意

在已为自动化帐户创建托管标识(无论是系统分配的还是用户分配的)的情况下,无法在混合 Runbook 辅助角色上使用用户分配的托管标识。 如果托管标识尚未分配给自动化帐户,则可在混合 Runbook 辅助角色(具有已分配的托管标识的 Azure VM)上使用 VM 的系统分配或用户分配的托管标识。

如果没有 Azure 订阅,可在开始前创建一个试用帐户

先决条件

  • 一个 Azure 自动化帐户。 有关说明,请参阅创建 Azure 自动化帐户

  • 用户分配的托管标识以及 runbook 使用该标识管理的目标 Azure 资源可位于不同的 Azure 订阅中。

  • Azure 帐户模块的最新版本。 当前版本为 2.2.8。 (请参阅 Az.Accounts,了解此版本的相关详情。)

  • 要从自动化 runbook 访问的 Azure 资源。 此资源需要为用户分配的托管标识定义角色,以帮助自动化 Runbook 对资源访问进行身份验证。 若要添加角色,需要成为相应 Microsoft Entra 租户中资源的所有者。

  • 若要分配 Azure 角色,必须拥有 Microsoft.Authorization/roleAssignments/write 权限,例如Microsoft.Authorization/roleAssignments/write所有者

为 Azure 自动化帐户添加用户分配的托管标识

可以使用 Azure 门户、PowerShell、Azure REST API 或 ARM 模板为 Azure 自动化帐户添加用户分配的托管标识。 如需有关在 PowerShell 中启用的示例,请先使用 Connect-AzAccount cmdlet 以交互方式登录到 Azure,然后按照说明进行操作。

# Sign in to your Azure subscription
$sub = Get-AzSubscription -ErrorAction SilentlyContinue
if(-not($sub))
{
    Connect-AzAccount -Environment AzureChinaCloud
}

# If you have multiple subscriptions, set the one to use
# Select-AzSubscription -SubscriptionId "<SUBSCRIPTIONID>"

然后初始化一组要在整个示例中使用的变量。 修改以下值,然后执行

$subscriptionID = "subscriptionID"
$resourceGroup = "resourceGroupName"
$automationAccount = "automationAccountName"
$userAssignedOne = "userAssignedIdentityOne"
$userAssignedTwo = "userAssignedIdentityTwo"

使用 Azure 门户添加

执行以下步骤:

  1. 登录 Azure 门户

  2. 在 Azure 门户中,导航到自动化帐户。

  3. 在“帐户设置”下选择“标识” 。

  4. 选择“用户分配”选项卡,然后选择“添加” 。

  5. 选择现有的用户分配的托管标识,然后选择“添加”。 随后你将返回到“用户分配”选项卡。

    Output from Portal.

使用 PowerShell 添加

使用 PowerShell cmdlet Set-AzAutomationAccount 添加用户分配的托管标识。 首先必须考虑是否有现有的系统分配的托管标识。 以下示例将两个现有的用户分配的托管标识添加到现有自动化帐户,并禁用系统分配的托管标识(如果存在)。

$output = Set-AzAutomationAccount `
    -ResourceGroupName $resourceGroup `
    -Name $automationAccount `
    -AssignUserIdentity "/subscriptions/$subscriptionID/resourcegroups/$resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$userAssignedOne", `
        "/subscriptions/$subscriptionID/resourcegroups/$resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$userAssignedTwo"

$output

若要保留现有的系统分配的托管标识,请使用以下命令:

$output = Set-AzAutomationAccount `
    -ResourceGroupName $resourceGroup `
    -Name $automationAccount `
    -AssignUserIdentity "/subscriptions/$subscriptionID/resourcegroups/$resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$userAssignedOne", `
        "/subscriptions/$subscriptionID/resourcegroups/$resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$userAssignedTwo" `
    -AssignSystemIdentity

$output

输出应如下所示:

Output from Set-AzAutomationAccount command.

对于其他输出,请执行:$output.identity | ConvertTo-Json

使用 REST API 添加

下面提供了语法和示例步骤。

语法

以下示例正文语法启用系统分配的托管标识(如果尚未启用),并将两个现有的用户分配的托管标识分配给现有自动化帐户。

修补程序

{
  "identity": {
    "type": "SystemAssigned, UserAssigned",
    "userAssignedIdentities": {
      "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resource-group-name/providers/Microsoft.ManagedIdentity/userAssignedIdentities/firstIdentity": {},
      "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resource-group-name/providers/Microsoft.ManagedIdentity/userAssignedIdentities/secondIdentity": {}
    }
  }
}

API 的语法如下:

https://management.chinacloudapi.cn/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resource-group-name/providers/Microsoft.Automation/automationAccounts/automation-account-name?api-version=2020-01-13-preview 

示例

执行以下步骤。

  1. 修改上面的正文语法并将其保存到名为 body_ua.json 的文件中。 将该文件保存在本地计算机或 Azure 存储帐户中。

  2. 修改以下变量值,然后执行。

    $file = "path\body_ua.json"
    
  3. 此示例使用 PowerShell cmdlet Invoke-RestMethod 将 PATCH 请求发送到自动化帐户。

    # build URI
    $URI = "https://management.chinacloudapi.cn/subscriptions/$subscriptionID/resourceGroups/$resourceGroup/providers/Microsoft.Automation/automationAccounts/$automationAccount`?api-version=2020-01-13-preview"
    
    # build body
    $body = Get-Content $file
    
    # obtain access token
    $azContext = Get-AzContext
    $azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
    $profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
    $token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId)
    $authHeader = @{
        'Content-Type'='application/json'
        'Authorization'='Bearer ' + $token.AccessToken
    }
    
    # Invoke the REST API
    $response = Invoke-RestMethod -Uri $URI -Method PATCH -Headers $authHeader -Body $body
    
    # Review output
    $response.identity | ConvertTo-Json
    

    输出应如下所示:

    {
    "type": "SystemAssigned, UserAssigned",
    "principalId": "00000000-0000-0000-0000-000000000000",
    "tenantId": "00000000-0000-0000-0000-000000000000",
    "userAssignedIdentities":  {
        "/subscriptions/ContosoID/resourcegroups/ContosoLab/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ContosoUAMI1":  {
                "PrincipalId":  "00000000-0000-0000-0000-000000000000",
                "ClientId":  "00000000-0000-0000-0000-000000000000"
                    },
        "/subscriptions/ContosoID/resourcegroups/ContosoLab/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ContosoUAMI2":  {
                "PrincipalId":  "00000000-0000-0000-0000-000000000000",
                "ClientId":  "00000000-0000-0000-0000-000000000000"
                    }
        }
    }
    

使用 ARM 模板添加

下面提供了语法和示例步骤。

模板语法

以下示例模板语法启用系统分配的托管标识(如果尚未启用),并将两个现有的用户分配的托管标识分配给现有自动化帐户。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "automationAccountName": {
     "defaultValue": "YourAutomationAccount",
      "type": "String",
      "metadata": {
        "description": "Automation account name"
      }
    },
    "userAssignedOne": {
     "defaultValue": "userAssignedOne",
      "type": "String",
      "metadata": {
        "description": "User-assigned managed identity"
      }
	  },
    "userAssignedTwo": {
     "defaultValue": "userAssignedTwo",
      "type": "String",
      "metadata": {
        "description": "User-assigned managed identity"
      }
	  }
   },
  "resources": [
    {
      "type": "Microsoft.Automation/automationAccounts",
      "apiVersion": "2020-01-13-preview",
      "name": "[parameters('automationAccountName')]",
      "location": "[resourceGroup().location]",
      "identity": {
        "type": "SystemAssigned, UserAssigned",
        "userAssignedIdentities": {
          "[resourceID('Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('userAssignedOne'))]": {},
          "[resourceID('Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('userAssignedTwo'))]": {}
        }
      },
      "properties": {
        "sku": {
          "name": "Basic"
        },
        "encryption": {
          "keySource": "Microsoft.Automation",
          "identity": {}
        }
      }
    }
  ]
}

示例

执行以下步骤。

  1. 将模板复制并粘贴到名为 template_ua.json 的文件中。 将该文件保存在本地计算机或 Azure 存储帐户中。

  2. 修改以下变量值,然后执行。

    $templateFile = "path\template_ua.json"
    
  3. 使用 PowerShell cmdlet New-AzResourceGroupDeployment 部署模板。

    New-AzResourceGroupDeployment `
        -Name "UserAssignedDeployment" `
        -ResourceGroupName $resourceGroup `
        -TemplateFile $templateFile `
        -automationAccountName $automationAccount `
        -userAssignedOne $userAssignedOne `
        -userAssignedTwo $userAssignedTwo
    

    该命令不会生成输出;但是,你可以使用以下代码进行验证:

    (Get-AzAutomationAccount `
    -ResourceGroupName $resourceGroup `
    -Name $automationAccount).Identity | ConvertTo-Json
    

    输出类似于前面 REST API 示例显示的输出。

为用户分配的托管标识分配角色

自动化帐户可以使用其用户分配的托管标识获取令牌,以访问其他受 Microsoft Entra ID 保护的资源(例如 Azure Key Vault)。 这些令牌不代表应用程序的任何特定用户。 它们代表访问资源的应用程序。 例如,在本例中,令牌表示自动化帐户。

在能够使用用户分配的托管标识进行身份验证之前,需要为该标识设置对你打算在其中使用该标识的 Azure 资源的访问权限。 若要完成此任务,请在目标 Azure 资源上向该标识分配适当的角色。

遵循最小权限原则,仔细分配仅执行 runbook 所需的权限。 例如,如果启动或停止 Azure VM 仅需自动化帐户,则分配给运行方式帐户或托管标识的权限需仅用于启动或停止 VM。 同样,如果 runbook 要从 Blob 存储读取,则分配只读权限。

此示例使用 Azure PowerShell 演示如何将订阅中的参与者角色分配给目标 Azure 资源。 “参与者”角色用作示例,在你的案例中不一定需要用到。 或者,也可以将角色分配给 Azure 门户中的目标 Azure 资源。

New-AzRoleAssignment `
    -ObjectId <automation-Identity-object-id> `
    -Scope "/subscriptions/<subscription-id>" `
    -RoleDefinitionName "Contributor"

向用户管理的标识验证角色分配

若要向自动化帐户的用户分配的托管标识验证角色,请执行以下步骤:

  1. 登录到 Azure 门户

  2. 返回到自动化帐户。

  3. 在“帐户设置”下,依次选择“标识”、“用户分配”。

  4. 单击“用户分配的标识名称”。

    Assigning role in user-assigned identity in Azure portal.

    如果已将角色分配到所选的用户分配的托管标识,可以看到角色分配的列表。 此列表包括你有权读取的所有角色分配。

    View role-assignments that you have permission in Azure portal.

  5. 要更改订阅,请单击“订阅”下拉列表并选择适当的订阅。

  6. 单击“添加角色分配(预览版)”

  7. 在下拉列表中,选择角色分配适用的资源集:“订阅”、“资源组”、“角色”和“范围”。
    如果你没有进行角色分配,可以将选定范围的写入权限作为内联消息查看。

  8. 在“角色”下拉列表中,选择一个角色作为“虚拟机参与者”。

  9. 单击“保存” 。

    Add a role assignment in Azure portal.

片刻之后,就会在所选范围为托管标识分配角色。

使用用户分配的托管标识对访问进行身份验证

为自动化帐户启用用户分配的托管标识并向标识授予对目标资源的访问权限后,可以在 Runbook 中针对支持托管标识的资源指定该标识。 若要确认标识支持情况,请使用 Az cmdlet Connect-AzAccount

# Ensures you do not inherit an AzContext in your runbook
Disable-AzContextAutosave -Scope Process

# Connect to Azure with user-assigned managed identity
$AzureContext = (Connect-AzAccount -Identity -AccountId <user-assigned-identity-ClientId> -Environment AzureChinaCloud).context

# set and store context
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext

在不使用 Azure cmdlet 的情况下生成访问令牌

对于 HTTP 终结点,请确保以下事项。

  • 元数据标头必须存在并且应设置为“true”。
  • 资源必须作为 GET 请求的查询参数和 POST 请求的表单数据,与请求一起传递。
  • 将环境变量 IDENTITY_HEADER 的值设置为 X-IDENTITY-HEADER。
  • Post 请求的内容类型必须是 application/x-www-form-urlencoded

使用 HTTP Get 获取用户分配的托管标识的访问令牌

$resource= "?resource=https://management.chinacloudapi.cn/"
$client_id="&client_id=<ClientId of USI>"
$url = $env:IDENTITY_ENDPOINT + $resource + $client_id 
$Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"  
$Headers.Add("Metadata", "True")
$headers.Add("X-IDENTITY-HEADER", $env:IDENTITY_HEADER) 
$accessToken = Invoke-RestMethod -Uri $url -Method 'GET' -Headers $Headers
Write-Output $accessToken.access_token 

使用 HTTP Post 获取用户分配的托管标识的访问令牌

$url = $env:IDENTITY_ENDPOINT
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Metadata", "True")
$headers.Add("X-IDENTITY-HEADER", $env:IDENTITY_HEADER) 
$body = @{'resource'='https://management.chinacloudapi.cn/' 
'client_id'='<ClientId of USI>'}
$accessToken = Invoke-RestMethod $url -Method 'POST' -Headers $headers -ContentType 'application/x-www-form-urlencoded' -Body $body
Write-Output $accessToken.access_token 

在 Azure PowerShell 中使用用户分配的托管标识

Write-Output "Connecting to azure via  Connect-AzAccount -Identity -AccountId <ClientId of USI> -Environment AzureChinaCloud"  
Connect-AzAccount -Identity -AccountId <ClientId of USI> -Environment AzureChinaCloud
Write-Output "Successfully connected with Automation account's Managed Identity"  
Write-Output "Trying to fetch value from key vault using User Assigned Managed identity. Make sure you have given correct access to Managed Identity"  
$secret = Get-AzKeyVaultSecret -VaultName '<KVname>' -Name '<KeyName>'  
$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue)  
try {  
  $secretValueText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)  
    Write-Output $secretValueText  
} finally {  
    [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)  
} 

在 Python Runbook 中使用用户分配的托管标识

#!/usr/bin/env python3  
import os  
import requests   

resource = "?resource=https://management.chinacloudapi.cn/" 
client_id = "&client_id=<ClientId of USI>" 
endPoint = os.getenv('IDENTITY_ENDPOINT')+ resource +client_id 
identityHeader = os.getenv('IDENTITY_HEADER') 
payload={}  
headers = {  
  'X-IDENTITY-HEADER': identityHeader,
  'Metadata': 'True' 
}  
response = requests.request("GET", endPoint, headers=headers, data=payload)  
print(response.text) 

后续步骤