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

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

你可以使用 Azure 资源管理器服务连接来连接到 Azure 资源,例如管道中的 Azure Key Vault。 通过此连接,你可以使用管道部署到 Azure 资源(例如 Azure 应用程序服务应用),无需每次都进行身份验证。

有多个身份验证选项可用于使用 Azure 资源管理器服务连接来连接到 Azure。 建议的选项是将工作负荷联合身份验证与应用注册或托管标识配合使用。

建议的 Azure 资源管理器服务连接选项包括:

本文未包含其他 Azure 资源管理器服务连接身份验证选项:

创建 Azure 资源管理器应用程序注册(自动)

创建 Azure 资源管理器服务连接时,你将在两种不同的凭据类型(工作负荷联合身份验证或机密)之间进行选择。

使用工作负荷联合身份验证创建 Azure 资源管理器应用注册(自动)

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

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

通过此选项,Azure DevOps 会自动查询您要连接到的订阅、管理组或机器学习工作区,并创建用于身份验证的工作负载联合身份验证。

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

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

  2. 依次选择新建服务连接Azure 资源管理器下一步

    显示选择“Azure 资源管理器”选项的屏幕截图。

  3. 选择应用注册(自动)工作负荷联合身份验证凭据。

    选择了工作负荷标识的应用注册(自动)身份验证方法选择的屏幕截图。

  4. 选择范围级别。 选择订阅管理组机器学习工作区管理组是一些容器,可以帮助跨多个订阅管理访问权限、策略和符合性。 机器学习工作区用于创建机器学习项目。

    • 对于订阅范围,请输入以下参数:

      参数 说明
      订阅 必需。 选择 Azure 订阅。
      资源组 可选。 选择 Azure 资源组。
    • 对于管理组范围,请选择 Azure 管理组

    • 对于机器学习工作区范围,请输入以下参数:

      参数 说明
      订阅 必需。 选择 Azure 订阅。
      资源组 必需。 选择包含工作区的资源组。
      机器学习工作区 必需。 选择 Azure 机器学习工作区。
  5. 输入服务连接名称

  6. (可选)输入服务连接的说明。

  7. 选择授予对所有管道的访问权限,以允许所有管道使用此服务连接。 如果未选择此选项,则必须手动授予对使用此服务连接的每个管道的访问权限。

  8. 选择保存

创建新的服务连接后,将连接名称作为 azureSubscription 值复制并粘贴到代码中。

使用机密创建 Azure 资源管理器应用注册(自动)

通过此选项,Azure DevOps 会自动查询您要连接到的订阅、管理组或机器学习工作区,并创建用于身份验证的机密。

警告

使用机密需要手动轮换和管理,不建议这样做。 工作负荷联合身份验证是首选凭据类型。

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

  • 你已以 Azure Pipelines 组织和 Azure 订阅的所有者身份登录。
  • 不需要进一步限制用户通过服务连接访问的 Azure 资源的权限。
  • 未连接到 Azure StackAzure US Government 环境。
  • 你不是从 Azure DevOps Server 2019 或早期版本的 Team Foundation Server 进行连接。
  1. >在 Azure DevOps 项目中,转到“项目设置”“服务连接”。

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

  2. 依次选择新建服务连接Azure 资源管理器下一步

    显示选择“Azure 资源管理器”选项的屏幕截图。

  3. 选择具有凭据机密应用注册(自动)

    工作负载联合身份验证应用注册(自动)身份验证方法选择的屏幕截图。

  4. 选择范围级别。 选择订阅管理组机器学习工作区管理组是一些容器,可以帮助跨多个订阅管理访问权限、策略和符合性。 机器学习工作区用于创建机器学习项目。

    • 对于订阅范围,请输入以下参数:

      参数 说明
      订阅 必需。 选择 Azure 订阅。
      资源组 必需。 选择 Azure 资源组。
    • 对于管理组范围,请选择 Azure 管理组

    • 对于机器学习工作区范围,请输入以下参数:

      参数 说明
      订阅 必需。 选择 Azure 订阅。
      资源组 必需。 选择包含工作区的资源组。
      机器学习工作区 必需。 选择 Azure 机器学习工作区。
  5. 输入服务连接名称

  6. (可选)输入服务连接的说明。

  7. 选择授予对所有管道的访问权限,以允许所有管道使用此服务连接。 如果未选择此选项,则必须手动授予对使用此服务连接的每个管道的访问权限。

  8. 选择保存

创建新的服务连接后,将连接名称作为 azureSubscription 值复制并粘贴到代码中。

为现有用户分配的托管标识创建 Azure 资源管理器服务连接

使用此选项为现有用户分配的托管标识自动创建工作负荷标识凭据。 在开始之前,你需要拥有现有的用户分配的托管标识

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

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

  2. 依次选择新建服务连接Azure 资源管理器下一步

    显示选择“Azure 资源管理器”选项的屏幕截图。

  3. 选择“托管标识” 。

    该屏幕截图显示了选择托管标识的 Azure 资源管理器选项,其中具有用户分配的标识。

  4. 步骤 1:托管标识详细信息中:

    1. 选择托管标识订阅。 这是包含托管标识的 Azure 订阅。
    2. 选择托管标识的资源组。 这是包含托管标识的资源组。
    3. 选择“托管标识”。 这是资源组中将用于访问资源的托管标识。
  5. 步骤 2:Azure 范围中:

    1. 选择范围级别。 选择订阅管理组机器学习工作区管理组是一些容器,可以帮助跨多个订阅管理访问权限、策略和符合性。 机器学习工作区用于创建机器学习项目。

      • 对于订阅范围,请输入以下参数:

        参数 说明
        服务连接订阅 必需。 选择托管标识将访问的 Azure 订阅名称。
        服务连接的资源组 可选。 输入数据以便只让一个资源组访问托管标识。
      • 对于管理组范围,请输入以下参数:

        参数 说明
        管理组 必需。 选择 Azure 管理组。
      • 对于机器学习工作区范围,请输入以下参数:

        参数 说明
        订阅 必需。 选择 Azure 订阅名称。
        服务连接的资源组 可选。 选择包含工作区的资源组。
        ML 工作区 必需。 输入现有 Azure 机器学习工作区的名称。
    2. 步骤 3:服务连接详细信息:部分中,输入或选择以下参数:

      参数 说明
      服务连接名称 必需。 在任务属性中引用此服务连接时将使用的名称。 不是 Azure 订阅的名称。
      服务管理参考 可选。 ITSM 数据库中的上下文信息。
      描述 可选。 输入服务连接的说明。
    3. 安全性部分中,选择向所有管道授予访问权限以允许所有管道使用此服务连接。 如果未选择此选项,则必须手动授予对使用此服务连接的每个管道的访问权限。

    4. 选择保存以验证并创建服务连接。

转换现有的 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 资源管理器服务连接

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

要创建使用现有服务主体的服务连接,请执行以下操作:

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

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

  2. 依次选择新建服务连接Azure 资源管理器下一步

    显示“Azure 资源管理器”选项的屏幕截图。

  3. 选择服务主体(手动),然后选择下一步

    显示选择服务主体(手动)身份验证方法选择的屏幕截图。

  4. 新建 Azure 服务连接对话框中,选择环境。 如果选择 Azure Stack,请输入环境 URL,如下所示:https://management.local.azurestack.external

  5. 选择范围级别选择“订阅”或“管理组”。 管理组是一些容器,可以帮助跨多个订阅管理访问权限、策略和符合性。

    • 对于订阅范围,请输入以下参数:

      参数 说明
      订阅 ID 必需。 输入 Azure 订阅 ID。
      订阅名称 必需。 输入 Azure 订阅名称。
    • 对于管理组范围,请输入以下参数:

      参数 说明
      管理组 ID 必需。 输入 Azure 管理组 ID。
      管理组名称 必需。 输入 Azure 管理组名称。
  6. 身份验证部分中,输入或选择以下参数:

    参数 说明
    服务主体 ID 必需。 输入服务主体 ID。
    凭据 选择服务主体密钥证书。 如果选择了服务主体密钥,请输入密钥(密码)。 如果选择了证书,请输入证书。
    Tenant Id 必需。 输入租户 ID。
    验证 选择此选项以验证你输入的设置。
  7. 在“详细信息”部分中,输入以下参数:

    参数 说明
    连接名称 必需。 在任务属性中引用此服务连接时将使用的名称。 不是 Azure 订阅的名称。
    描述 可选。 输入服务连接的说明。
    安全性 选择授予对所有管道的访问权限,以允许所有管道使用此服务连接。 如果未选择此选项,则必须手动授予对使用此服务连接的每个管道的访问权限。
  8. 选择验证并保存以验证并创建服务连接。

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

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

  2. 选择“新建服务连接”,然后选择“Azure 资源管理器”。

    显示“Azure 资源管理器”选项的屏幕截图。

  3. 在“添加 Azure 资源管理器服务连接”对话框中,填写字段,具体如下:

    “添加 Azure 资源管理器服务连接”的屏幕截图。

    1. 输入连接名称。

    2. 选择环境。 如果选择 Azure Stack,请输入环境 URL,如下所示:https://management.local.azurestack.external

    3. 选择范围级别、**订阅或管理组管理组是一些容器,可以帮助跨多个订阅管理访问权限、策略和符合性。

      • 对于订阅范围,请输入以下参数:

        参数 说明
        订阅 ID 必需。 输入 Azure 订阅 ID。
        订阅名称 必需。 输入 Azure 订阅名称。
      • 对于管理组范围,请输入以下参数:

        参数 说明
        管理组 ID 必需。 输入 Azure 管理组 ID。
        管理组名称 必需。 输入 Azure 管理组名称。
    4. 输入服务主体 ID。

    5. 选择凭据类型:

      • 服务主体密钥:输入服务主体密钥(密码)。
      • 证书:输入 .perm 文件的内容,包括证书和私钥部分。
    6. 输入租户 ID

    7. 选择“验证连接”以验证服务连接。

    8. 根据需要选择“允许所有管道使用此连接”。 如果未选择此选项,则必须手动授予对使用此服务连接的每个管道的访问权限。

    9. 选择“保存”以创建服务连接。

创建新服务连接后:

  • 如果在 UI 中使用此服务连接,请选择在管道的“Azure 订阅”设置中分配的连接名称。
  • 如果在 YAML 文件中使用服务连接,请复制连接名称并将其作为 azureSubscription 值粘贴到代码中。

如有必要,请修改服务主体以公开相应的权限。

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

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

帮助和支持