使用 Azure 资源管理器服务连接连接到 Azure

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

可以使用 Azure 资源管理器服务连接通过服务主体身份验证或 Azure 托管服务标识连接到 Azure 资源。 如果使用 Azure 资源管理器服务连接,可使用管道部署到 Azure 应用服务应用等 Azure 资源,不必每次重新进行身份验证。

有多个选项可用于使用 Azure 资源管理器服务连接来连接到 Azure:

  • 使用工作负载标识联合身份验证的服务主体或托管标识
  • 具有机密的服务主体
  • 代理分配的托管标识

若要了解其他类型的连接以及有关创建和使用连接的一般信息,请参阅生成和发布的服务连接

使用工作负载标识联合身份验证创建 Azure 资源管理器服务连接

工作负载标识联合身份验证使用 OpenID Connect (OIDC) 对 Microsoft Entra 保护的资源进行身份验证,而不使用机密。

如果以下所有项都适用于你的方案,建议使用此方法:

  • 你拥有 Azure 订阅的所有者角色。
  • 未连接到 Azure StackAzure 政府云
  • 你使用的任何市场扩展任务都经过了更新,以支持工作负载标识联合身份验证。

创建新的工作负载标识联合身份验证服务连接

  1. >在 Azure DevOps 项目中,转到“项目设置”“服务连接”。

    有关详细信息,请参阅打开项目设置

  2. 依次选择“新建服务连接”和“Azure 资源管理器”。

    显示选择工作负荷标识服务连接类型的屏幕截图。

  3. 选择“工作负载联合身份验证(自动)”。

    显示选择工作负荷标识服务连接类型的屏幕截图。

  4. 指定下列参数:

    参数 说明
    订阅 选择现有的 Azure 订阅。 如果未显示任何 Azure 订阅或实例,请参阅排查 Azure 资源管理器服务连接问题
    资源组 留空以允许用户访问订阅中定义的所有资源。 若要限制用户对资源的访问,请输入资源组名称。 然后,用户只能访问为该资源组定义的资源。
    服务连接名称 必需。 在任务属性中引用此服务连接时将使用的名称。 不是 Azure 订阅的名称。
  5. 创建新的服务连接后,将连接名称作为 azureSubscription 值复制并粘贴到代码中。

  6. 若要部署到特定的 Azure 资源,该任务需要有关该资源的更多数据。 转到 Azure 门户中的资源,然后将数据复制到代码中。 例如,若要部署 Web 应用,请复制 Azure 应用服务应用的名称,并将其作为 WebAppName 值粘贴到代码中。

转换现有的 Azure 资源管理器服务连接以使用工作负载标识联合身份验证

你可以快速转换现有的 Azure 资源管理器服务连接,以使用工作负载标识联合身份验证而不是服务主体进行身份验证。 如果服务连接满足这些要求,则可以在 Azure DevOps 中使用服务连接转换工具:

  • Azure DevOps 最初创建了服务连接。 如果你手动创建服务连接,则无法使用服务连接转换工具转换服务连接,因为 Azure DevOps 无权修改自己的凭据。
  • 只有一个项目使用服务连接。 无法转换跨项目服务连接

若要转换服务连接,请执行以下操作:

  1. >在 Azure DevOps 项目中,转到“项目设置”“服务连接”。

    有关详细信息,请参阅打开项目设置

  2. 选择要转换为使用工作负载标识的服务连接。

  3. 选择“转换”

    显示

    如果现有服务主体凭据的机密已过期,会看到一个不同的转换选项。

    一个屏幕截图,其中显示了在证书过期时用于转换为使用联合凭据的选项。

  4. 再次选择“转换”,确认你想要创建新的服务连接。

    转换可能需要几分钟时间。 如果要还原连接,必须在七天内还原它。

使用脚本转换多个 Azure 资源管理器服务连接

使用脚本同时更新多个服务连接,以立即使用工作负荷标识联合身份验证进行身份验证。

此示例 PowerShell 脚本需要两个参数:Azure DevOps 组织(示例:https://dev.azure.com/fabrikam-tailspin)和 Azure DevOps 项目(示例:Space game web agent)。 然后,该脚本检索 Azure DevOps 项目和组织的相关服务连接。 系统将要求你确认要转换不使用工作负荷联合身份验证的每个关联服务连接。 如果确认,该脚本使用 Azure DevOps REST API 更新每个服务连接,以使用工作负荷联合身份验证。 该脚本需要 PowerShell 7.3 或更高版本以及 Azure CLI 才能运行。 将此脚本保存为 .ps1 文件,然后用 Powershell 7 运行此文件。

#!/usr/bin/env pwsh
<# 
.SYNOPSIS 
    Convert multiple Azure Resource Manager service connection(s) to use Workload identity federation

.LINK
    https://aka.ms/azdo-rm-workload-identity-conversion

.EXAMPLE
    ./convert_azurerm_service_connection_to_oidc_simple.ps1 -Project <project> -OrganizationUrl https://dev.azure.com/<organization>
#> 

#Requires -Version 7.3

param ( 
    [parameter(Mandatory=$true,HelpMessage="Name of the Azure DevOps Project")]
    [string]
    [ValidateNotNullOrEmpty()]
    $Project,

    [parameter(Mandatory=$true,HelpMessage="Url of the Azure DevOps Organization")]
    [uri]
    [ValidateNotNullOrEmpty()]
    $OrganizationUrl
) 
$apiVersion = "7.1"
$PSNativeCommandArgumentPassing = "Standard" 

#-----------------------------------------------------------
# Log in to Azure
$azdoResource = "499b84ac-1321-427f-aa17-267ca6975798" # application id of Azure DevOps 
az login --allow-no-subscriptions --scope ${azdoResource}/.default
$OrganizationUrl = $OrganizationUrl.ToString().Trim('/')

#-----------------------------------------------------------
# Retrieve the service connection
$getApiUrl = "${OrganizationUrl}/${Project}/_apis/serviceendpoint/endpoints?authSchemes=ServicePrincipal&type=azurerm&includeFailed=false&includeDetails=true&api-version=${apiVersion}"
az rest --resource $azdoResource -u "${getApiUrl} " -m GET --query "sort_by(value[?authorization.scheme=='ServicePrincipal' && data.creationMode=='Automatic' && !(isShared && serviceEndpointProjectReferences[0].projectReference.name!='${Project}')],&name)" -o json `
        | Tee-Object -Variable rawResponse | ConvertFrom-Json | Tee-Object -Variable serviceEndpoints | Format-List | Out-String | Write-Debug
if (!$serviceEndpoints -or ($serviceEndpoints.count-eq 0)) {
    Write-Warning "No convertible service connections found"
    exit 1
}

foreach ($serviceEndpoint in $serviceEndpoints) {
    # Prompt user to confirm conversion
    $choices = @(
        [System.Management.Automation.Host.ChoiceDescription]::new("&Convert", "Converting service connection '$($serviceEndpoint.name)'...")
        [System.Management.Automation.Host.ChoiceDescription]::new("&Skip", "Skipping service connection '$($serviceEndpoint.name)'...")
        [System.Management.Automation.Host.ChoiceDescription]::new("&Exit", "Exit script")
    )
    $prompt = $serviceEndpoint.isShared ? "Convert shared service connection '$($serviceEndpoint.name)'?" : "Convert service connection '$($serviceEndpoint.name)'?"
    $decision = $Host.UI.PromptForChoice([string]::Empty, $prompt, $choices, $serviceEndpoint.isShared ? 1 : 0)

    if ($decision -eq 0) {

        Write-Host "$($choices[$decision].HelpMessage)"
    } elseif ($decision -eq 1) {
        Write-Host "$($PSStyle.Formatting.Warning)$($choices[$decision].HelpMessage)$($PSStyle.Reset)"
        continue 
    } elseif ($decision -ge 2) {
        Write-Host "$($PSStyle.Formatting.Warning)$($choices[$decision].HelpMessage)$($PSStyle.Reset)"
        exit 
    }

    # Prepare request body
    $serviceEndpoint.authorization.scheme = "WorkloadIdentityFederation"
    $serviceEndpoint.data.PSObject.Properties.Remove('revertSchemeDeadline')
    $serviceEndpoint | ConvertTo-Json -Depth 4 | Write-Debug
    $serviceEndpoint | ConvertTo-Json -Depth 4 -Compress | Set-Variable serviceEndpointRequest
    $putApiUrl = "${OrganizationUrl}/${Project}/_apis/serviceendpoint/endpoints/$($serviceEndpoint.id)?operation=ConvertAuthenticationScheme&api-version=${apiVersion}"
    # Convert service connection
    az rest -u "${putApiUrl} " -m PUT -b $serviceEndpointRequest --headers content-type=application/json --resource $azdoResource -o json `
            | ConvertFrom-Json | Set-Variable updatedServiceEndpoint

    $updatedServiceEndpoint | ConvertTo-Json -Depth 4 | Write-Debug
    if (!$updatedServiceEndpoint) {
        Write-Debug "Empty response"
        Write-Error "Failed to convert service connection '$($serviceEndpoint.name)'"
        exit 1
    }
    Write-Host "Successfully converted service connection '$($serviceEndpoint.name)'"
}

还原使用服务主体机密的现有 Azure 资源管理器服务连接

你可以在七天内还原转换后的自动服务连接及其机密。 7 天后,手动创建新机密。

如果你手动创建和还原服务连接,则无法使用服务连接转换工具转换服务连接,因为 Azure DevOps 无权修改自己的凭据。

若要转换服务连接,请执行以下操作:

  1. >在 Azure DevOps 项目中,转到“管道”“服务连接”。

  2. 选择要还原的现有服务连接。

  3. 选择“将转换还原到原始方案”。

    显示

  4. 再次选择“还原”以确认所做选择。

使用服务主体机密创建 Azure 资源管理器服务连接

如果以下所有项都适用于你的方案,建议使用此方法:

  • 你已以 Azure Pipelines 组织和 Azure 订阅的所有者身份登录。
  • 不需要进一步限制用户通过服务连接访问的 Azure 资源的权限。
  • 未连接到 Azure StackAzure 政府云
  • 你不是从 Azure DevOps Server 2019 或早期版本的 Team Foundation Server 进行连接。

若要创建服务连接,请执行以下操作:

  1. >在 Azure DevOps 项目中,转到“项目设置”“服务连接”。

    在 Team Foundation Server 中,选择顶部菜单栏中的“设置”图标以转到“服务”页。

    有关详细信息,请参阅打开项目设置

  2. 依次选择“新建服务连接”和“Azure 资源管理器”。

    显示选择服务连接类型的屏幕截图。

  3. 输入或选择以下参数:

    参数 说明
    连接名称 必需。 在任务属性中引用此服务连接时将使用的名称。 不是 Azure 订阅的名称。
    范围级别 选择“订阅”或“管理组”。 管理组是一些容器,可以帮助跨多个订阅管理访问权限、策略和符合性。
    订阅 如果为范围选择了“订阅”,请选择现有的 Azure 订阅。 如果未显示任何 Azure 订阅或实例,请参阅排查 Azure 资源管理器服务连接问题
    管理组 如果为范围选择了“管理组”,请选择现有的 Azure 管理组。 有关详细信息,请参阅创建管理组
    资源组 留空以允许用户访问订阅中定义的所有资源。 若要限制用户对资源的访问,请输入资源组名称。 然后,用户只能访问为该资源组定义的资源。
  4. 创建新服务连接后:

    • 如果使用经典编辑器,请选择在管道的“Azure 订阅”设置中分配的连接名称。
    • 如果使用 YAML 文件,请将连接名称作为 azureSubscription 值复制到代码中。
  5. 若要部署到特定的 Azure 资源,请将有关该资源的详细信息添加到任务:

    • 如果使用经典编辑器,请选择要添加到任务的数据。 例如,选择应用服务名称。
    • 如果使用 YAML 文件,请转到 Azure 门户中的资源。 复制所需的数据并将其粘贴到任务代码中。 例如,若要部署 Web 应用,请复制应用服务应用的名称,并将其粘贴为任务 YAML 中 WebAppName 的值。

注意

采用此方法时,Azure DevOps 与 Microsoft Entra ID 进行连接,并使用有效期为 3 个月的机密创建应用注册。 当服务连接即将过期时,Microsoft Entra ID 会显示以下提示:证书或机密即将过期。请新建一个。 在这种情况下,必须刷新服务连接。

若要刷新服务连接,请在 Azure DevOps 门户中编辑连接,然后选择“验证”。 保存编辑后,服务连接的有效期将再延长 3 个月。

建议使用工作负载联合身份验证,而不是创建机密。 如果使用工作负载联合身份验证,则无需轮换机密,应用注册将保留其预期目的。 要开始使用工作负载联合身份验证,请转到服务连接详细信息页,然后选择“转换”。 这会将服务连接转换为使用工作负载联合身份验证,而非机密。 有关详细信息,请参阅转换现有的 Azure 资源管理器服务连接以使用工作负载联合身份验证

有关详细信息,请参阅排查 Azure 资源管理器服务连接问题

如果使用此方法时遇到问题(例如下拉列表中未显示任何订阅),或者想要进一步限制用户的权限,则可以改用服务主体具有托管服务标识的虚拟机

创建使用现有服务主体的 Azure 资源管理器服务连接

  1. 如果要使用一组预定义的访问权限,但尚未为此目的定义服务主体,请按照以下教程之一创建新的服务主体:

  2. >在 Azure DevOps 项目中,转到“项目设置”“服务连接”。

    在 Team Foundation Server 中,选择顶部菜单栏中的“设置”图标以转到“服务”页。

    有关详细信息,请参阅打开项目设置

  3. 依次选择“新建服务连接”和“Azure 资源管理器”。

    显示选择服务连接类型的屏幕截图。

  4. 选择“服务主体(手动)”选项,然后输入服务主体详细信息。

    显示打开完整版服务对话框的屏幕截图。

  5. 对于“连接名称”,请输入用于引用此服务连接的显示名称。

  6. 对于“环境”,请选择环境名称(Azure CloudAzure StackAzure 政府云)。

  7. 如果未选择“Azure 云”,请输入“环境 URL”。 对于 Azure Stack,环境 URL 类似于 https://management.local.azurestack.external

  8. 对于“范围级别”,请选择连接的范围:

  9. 在“Azure 订阅”对话框中,输入以下有关服务主体的信息:

    • 订阅 ID
    • 订阅名称
    • 服务主体 ID
    • 服务主体客户端密钥,或者,如果已选择“证书”,请输入 *.pem 文件的证书和私钥部分的内容。
    • 租户 ID

    可以通过下载并运行 Azure PowerShell 脚本来获取此信息。 出现提示时,输入订阅名称、密码、角色(可选)和云类型,例如 Azure 云(默认)、Azure Stack 或 Azure 政府云。

  10. 选择“验证连接”以验证输入的设置。

  11. 创建新服务连接后:

    • 如果在 UI 中使用此服务连接,请选择在管道的“Azure 订阅”设置中分配的连接名称。
    • 如果在 YAML 文件中使用服务连接,请复制连接名称并将其作为 azureSubscription 值粘贴到代码中。
  12. 如有必要,请修改服务主体以公开相应的权限。

    有关使用服务主体进行身份验证的详细信息,请参阅使用基于角色的访问控制来管理对 Azure 订阅资源的访问权限,或在 Visual Studio 中使用服务主体自动执行 Azure 资源组部署博客文章。

有关详细信息,请参阅排查 Azure 资源管理器服务连接问题

创建与使用托管服务标识的 VM 的 Azure 资源管理器服务连接

注意

若要使用托管服务标识进行身份验证,必须在 Azure 虚拟机 (VM) 上使用自托管代理。

可在 Microsoft Entra ID 中将基于 Azure VM 的代理配置为使用 Azure 托管服务标识。 在此方案中,你可使用系统分配的标识(服务主体)向基于 Azure VM 的代理授权,使其可访问支持 Microsoft Entra ID 的任何 Azure 资源(例如 Azure Key Vault 的实例),而不是在 Azure DevOps 中保留凭据来用于连接。

  1. >在 Azure DevOps 项目中,转到“项目设置”“服务连接”。

    在 Team Foundation Server 中,选择顶部菜单栏中的“设置”图标以转到“服务”页。

    有关详细信息,请参阅打开项目设置

  2. 依次选择“新建服务连接”和“Azure 资源管理器”。

    显示选择服务连接类型的屏幕截图。

  3. 选择“托管标识身份验证”选项。

    显示转到托管服务标识设置的屏幕截图。

  4. 对于“连接名称”,请输入用于引用此服务连接的显示名称。

  5. 对于“环境”,请选择环境名称(Azure CloudAzure StackAzure 政府云)。

  6. 在“连接”对话框中,输入订阅中的以下值:

    • 订阅 ID
    • 订阅名称
    • 租户 ID
  7. 创建新服务连接后:

    • 如果在 UI 中使用此服务连接,请选择在管道的“Azure 订阅”设置中分配的连接名称。
    • 如果在 YAML 文件中使用服务连接,请将连接名称作为 azureSubscription 值复制到代码中。
  8. 确保 VM(代理)具有适当的权限。

    例如,如果你的代码需要调用 Azure 资源管理器,请在 Microsoft Entra ID 中使用基于角色的访问控制 (RBAC) 为 VM 分配适当的角色。

    有关详细信息,请参阅如何使用 Azure 资源的托管标识?使用基于角色的访问控制来管理对 Azure 订阅资源的访问

有关该过程的详细信息,请参阅排查 Azure 资源管理器服务连接问题

连接到 Azure 政府云

有关连接到 Azure 政府云的信息,请参阅从 Azure Pipelines(Azure 政府云)进行连接

连接到 Azure Stack

有关连接到 Azure Stack 的信息,请参阅以下文章:

帮助和支持