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

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

注意

我们正在推出新的 Azure 服务连接创建体验。 在你的组织中接收它取决于各种因素,你仍可能会看到较旧的用户体验。

你可以使用 Azure 资源管理器服务连接来连接到 Azure 资源,例如管道中的 Azure Key Vault。 通过此连接,你可以使用管道部署到 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. 选择保存

为现有用户分配的托管标识创建服务连接

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

  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 DevOps 中使用服务连接转换工具:

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

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

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

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

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

  3. 选择“转换”

    显示

    如果现有凭据的机密已过期,你将看到一个不同的转换选项。

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

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

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

使用脚本转换多个服务连接

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

此示例 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)'"
}

恢复使用密钥的现有服务连接

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

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

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

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

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

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

    显示

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

创建使用现有服务主体的服务连接

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

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

  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 资源管理器服务连接问题

帮助和支持