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

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

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

先决条件

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

  • 最新版本的 Az PowerShell 模块 Az.Accounts、Az.Resources、Az.Automation、Az.KeyVault。

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

  • 如果要使用托管标识执行混合作业,请将基于代理的混合 Runbook 辅助角色更新到最新版本。 基于扩展的混合 Runbook 辅助角色没有最低版本要求,所有版本都可以工作。 基于代理的混合辅助角色所需的最低版本是:

    • Windows 混合 Runbook 辅助角色:版本 7.3.1125.0
    • Linux 混合 Runbook 辅助角色:版本 1.7.4.0

    检查版本:

    • Windows 混合 Runbook 辅助角色:转到安装路径 - C:\ProgramFiles\Microsoft Monitoring Agent\Agent\AzureAutomation\.,“Azure 自动化”文件夹包含版本号为子文件夹名称的子文件夹。
    • Linux 混合 Runbook 辅助角色:转到路径 - vi/opt/microsoft/omsconfig/modules/nxOMSAutomationWorker/VERSION.,“VERSION”文件包含混合辅助角色的版本号。
  • 若要分配 Azure 角色,必须拥有 Microsoft.Authorization/roleAssignments/write 权限,例如用户访问管理员所有者

为 Azure 自动化帐户启用系统分配的托管标识

启用后,以下属性将分配给系统分配的托管标识。

属性 (JSON) 说明
principalid <principal-ID> 系统分配的托管标识的服务主体对象的全局唯一标识符 (GUID),表示 Microsoft Entra 租户中的自动化帐户。 此 GUID 有时显示为“对象 ID”或 objectID。
tenantid <Azure-AD-tenant-ID> 全局唯一标识符 (GUID),表示自动化帐户现在是其中的一名成员的 Microsoft Entra AD 租户。 在 Microsoft Entra 租户内,服务主体与自动化帐户具有相同的名称。

可以使用 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 -Identity -Environment AzureChinaCloud
}

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

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

$subscriptionID = "subscriptionID"
$resourceGroup = "resourceGroupName"
$automationAccount = "automationAccountName"

重要

新自动化帐户级别标识会替代以前任何 VM 级别系统分配的标识,这些标识在将 Runbook 身份验证与托管标识结合使用中进行了介绍。 如果在使用 VM 系统分配的标识访问 runbook 资源的 Azure VM 上运行混合作业,则会将自动化帐户标识用于混合作业。 这意味着,如果在使用自动化帐户的客户管理的密钥 (CMK) 功能,则可能会影响现有作业执行。

如果要继续使用 VM 的托管标识,则不应启用自动化帐户级别标识。 如果已启用该标识,可以禁用自动化帐户的系统分配的托管标识。 请参阅禁用 Azure 自动化帐户托管标识

使用 Azure 门户启用

执行以下步骤:

  1. 登录 Azure 门户

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

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

  4. 将“系统分配”选项设置为“开启”,然后按“保存” 。 当系统提示确认时,请选择“是”。

    在 Azure 门户中启用系统分配的标识。

    自动化帐户现在可以使用系统分配的标识,该标识已注册到 Microsoft Entra ID,并由对象 ID 表示。

    托管标识对象 ID。

使用 PowerShell 进行启用

使用 PowerShell cmdlet Set-AzAutomationAccount 启用系统分配的托管标识。

$output = Set-AzAutomationAccount `
    -ResourceGroupName $resourceGroup `
    -Name $automationAccount `
    -AssignSystemIdentity

$output

输出应如下所示:

set-azautomationaccount 命令的输出。

对于其他输出,请修改该示例以指定以下内容:$output.identity | ConvertTo-Json

使用 REST API 启用

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

语法

下面的正文语法使用 HTTP PATCH 方法为现有自动化帐户启用系统分配的托管标识。 但是,此语法会删除与该自动化帐户关联的所有现有用户分配的托管标识。

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

如果定义了多个用户分配的标识,而又要保留这些标识并仅删除系统分配的标识,则需要使用逗号分隔的列表指定每个用户分配的标识。 下例使用的是 HTTP PATCH 方法。

{ 
  "identity" : {
    "type": "SystemAssigned, UserAssigned",
    "userAssignedIdentities": {
        "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/resourceGroupName/providers/Microsoft.ManagedIdentity/userAssignedIdentities/cmkID": {},
        "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/resourceGroupName/providers/Microsoft.ManagedIdentity/userAssignedIdentities/cmkID2": {}
    }
  }
}

API 的语法如下:

PATCH https://management.chinacloudapi.cn/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/resource-group-name/providers/Microsoft.Automation/automationAccounts/automation-account-name?api-version=2020-01-13-preview

示例

执行以下步骤。

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

  2. 更新以下变量值,然后执行。

    $file = "path\body_sa.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
    

    输出应如下所示:

    {
        "PrincipalId":  "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
        "TenantId":  "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
        "Type":  0,
        "UserAssignedIdentities":  null
    }
    

使用 ARM 模板启用

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

模板语法

以下示例模板语法将为现有自动化帐户启用系统分配的托管标识。 但是,此语法会删除与该自动化帐户关联的所有现有用户分配的托管标识。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.Automation/automationAccounts",
      "apiVersion": "2020-01-13-preview",
      "name": "yourAutomationAccount",
      "location": "[resourceGroup().location]",
      "identity": {
        "type": "SystemAssigned"
        },
      "properties": {
        "sku": {
          "name": "Basic"
        }
      }
    }
  ]
}

示例

执行以下步骤。

  1. 将上述模板语法修改为使用你的自动化帐户,并将其保存到名为 template_sa.json 的文件中。

  2. 更新以下变量值,然后执行。

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

    New-AzResourceGroupDeployment `
        -Name "SystemAssignedDeployment" `
        -ResourceGroupName $resourceGroup `
        -TemplateFile $templateFile
    

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

    (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 资源。 参与者角色用作示例,在你的情况中可能需要也可能不需要。

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

验证对系统管理身份的角色分配

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

  1. 登录 Azure 门户

  2. 返回到自动化帐户。

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

    在 Azure 门户的“系统分配的标识”中分配角色。

  4. 在“权限”下,单击“Azure 角色分配” 。

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

    在 Azure 门户中查看你具有权限的角色分配。

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

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

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

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

  9. 单击“保存” 。

    在 Azure 门户中添加角色分配。

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

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

为自动化帐户启用托管标识并向标识授予对目标资源的访问权限后,可以在 runbook 中针对支持托管标识的资源指定该标识。 对于标识支持,请使用 Az cmdlet Connect-AzAccount cmdlet。 请参阅 PowerShell 参考中的 Connect-AzAccount

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

# Connect to Azure with system-assigned managed identity
$AzureContext = (Connect-AzAccount -Identity -Environment AzureChinaCloud).context

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

注意

如果你的组织仍在使用已弃用的 AzureRM cmdlet,则可以使用 Connect-AzureRMAccount -Identity -Environment AzureChinaCloud

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

使用系统分配的托管标识访问 Azure PowerShell 中的 Azure Key Vault

有关详细信息,请参阅 Get-AzKeyVaultSecret

Write-Output "Connecting to azure via  Connect-AzAccount -Identity" 
Connect-AzAccount -Identity -Environment AzureChinaCloud
Write-Output "Successfully connected with Automation account's Managed Identity" 
Write-Output "Trying to fetch value from key vault using MI. 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  
# printing environment variables 
endPoint = os.getenv('IDENTITY_ENDPOINT')+"?resource=https://management.chinacloudapi.cn/" 
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) 

使用系统分配的托管标识访问 SQL 数据库

要了解如何预配 Azure SQL 数据库访问权限,请参阅预配 Microsoft Entra 管理员(SQL 数据库)

$queryParameter = "?resource=https://database.chinacloudapi.cn/" 
$url = $env:IDENTITY_ENDPOINT + $queryParameter
$Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" 
$Headers.Add("X-IDENTITY-HEADER", $env:IDENTITY_HEADER) 
$Headers.Add("Metadata", "True") 
$content =[System.Text.Encoding]::Default.GetString((Invoke-WebRequest -UseBasicParsing -Uri $url -Method 'GET' -Headers $Headers).RawContentStream.ToArray()) | ConvertFrom-Json 
$Token = $content.access_token 
echo "The managed identities for Azure resources access token is $Token" 
$SQLServerName = "<ServerName>"    # Azure SQL logical server name  
$DatabaseName = "<DBname>"     # Azure SQL database name 
Write-Host "Create SQL connection string" 
$conn = New-Object System.Data.SqlClient.SQLConnection  
$conn.ConnectionString = "Data Source=$SQLServerName.database.chinacloudapi.cn;Initial Catalog=$DatabaseName;Connect Timeout=30" 
$conn.AccessToken = $Token 
Write-host "Connect to database and execute SQL script" 
$conn.Open()  
$ddlstmt = "CREATE TABLE Person( PersonId INT IDENTITY PRIMARY KEY, FirstName NVARCHAR(128) NOT NULL)" 
Write-host " " 
Write-host "SQL DDL command" 
$ddlstmt 
$command = New-Object -TypeName System.Data.SqlClient.SqlCommand($ddlstmt, $conn) 
Write-host "results" 
$command.ExecuteNonQuery() 
$conn.Close()

从现有的运行方式帐户迁移到托管标识

Azure 自动化可验证管理 Azure 资源管理器资源或运行方式帐户在经典部署模型上部署的资源。 要从运行方式帐户切换到托管标识进行 runbook 身份验证,请执行以下步骤。

  1. 启用系统分配的托管标识、用户分配的托管标识,或同时启用两者。

  2. 向托管标识授予与已分配运行方式帐户匹配的 Azure 资源相同的权限。

  3. 更新 runbook 以使用托管标识执行身份验证。

  4. 修改 runbook 以使用托管标识。 对于标识支持,请使用 Az cmdlet Connect-AzAccount cmdlet。 请参阅 PowerShell 参考中的 Connect-AzAccount

    • 如果使用 AzureRM 模块,请将 AzureRM.Profile 更新至最新版本,并将 Add-AzureRMAccount cmdlet 替换为 Connect-AzureRMAccount –Identity
    • 如果使用 Az 模块,请遵循更新 Azure PowerShell 模块一文中的步骤更新到最新版本。

后续步骤