在 Azure DevOps 中使用服务主体和托管标识

Azure DevOps Services

服务主体和托管标识为 Azure DevOps 自动化工作流提供安全的可缩放身份验证。 这些 Microsoft Entra 标识类型通过传统个人访问令牌(PAT)提供增强的安全性。 它们使用自动凭据管理、较短的令牌生存期和企业级访问控制。

服务主体和托管标识的优点

增强的安全性

  • 生存期短的令牌:Microsoft Entra 令牌每小时过期一次,这可降低与 PAT 相比的风险(最长可持续一年)。
  • 自动轮换:托管标识自动处理凭据轮换。
  • 没有存储机密:无需在代码或配置中存储长期凭据。

卓越运营

  • 集中管理:通过Microsoft Entra ID 策略和 Azure DevOps 权限来控制访问。
  • 审核功能:通过全面的日志记录跟踪身份验证和访问模式。
  • 高效缩放:支持没有单个用户依赖项的企业自动化方案。

新式身份验证

  • 基于标准:使用 OAuth 2.0 和 OpenID Connect 协议。
  • 多重身份验证支持:继承组织安全策略。
  • 条件访问:基于上下文应用高级安全策略。

了解服务主体和托管标识

服务主体

服务主体 是 Microsoft Entra 中表示租户内应用程序的对象。 它们定义应用程序可以执行的作、可以访问的资源以及谁可以使用它。 在 Microsoft Entra ID 中注册应用程序时,会自动创建服务主体,并为应用程序提供一种安全的方式来对资源进行身份验证和访问。

主要特征

  • 通过Microsoft Entra ID 中的应用程序注册创建。
  • 支持多租户方案。
  • 需要显式凭据管理(证书或客户端机密)。
  • 非常适合需要在不同环境中进行身份验证的应用程序。

托管标识

托管标识是 Azure 自动管理的一种特殊类型的服务主体。 通过在 Azure 资源的 Microsoft Entra ID 中提供自动托管标识,无需开发人员管理凭据。

托管标识的类型

系统分配的托管标识:

  • 自动创建并绑定到特定 Azure 资源。
  • Azure 管理的生命周期(删除资源时已删除)。
  • 与 Azure 资源的一对一关系。
  • 最适合在单个 Azure 资源上部署的应用程序。

用户分配的托管标识:

  • 创建为独立的 Azure 资源。
  • 可以分配给多个 Azure 资源。
  • 独立于关联资源管理的生命周期。
  • 最适合在多个资源上运行或需要共享标识的应用程序。

何时使用每种类型:

  • 服务主体:跨云部署、持续集成和持续交付(CI/CD)管道、Azure 外部的应用程序。
  • 系统分配的托管标识:单个 Azure 资源应用程序(Azure Functions、Azure 应用服务)。
  • 用户分配的托管标识:多资源应用程序、共享标识方案。

实施指南

请按照以下步骤为 Azure DevOps 身份验证实现服务主体或托管身份。 有关完整的代码示例,请参阅示例 应用程序

步骤 1:创建标识

根据部署方案选择适当的标识类型。

选项 A:创建服务主体(应用程序注册)

服务主体在 CI/CD 管道、跨云场景以及需要灵活部署选项的应用程序中表现良好。

  1. Microsoft Entra 管理中心注册应用程序。

  2. 转到 应用注册>“新建注册”。

  3. 配置应用程序:

    • 名称:对应用程序使用描述性名称。
    • 帐户类型:选择适当的租户支持。
    • 重定向 URI:为服务到服务方案留空。
  4. 创建身份验证凭据:

    • 建议:上传证书以提高安全性。
    • 替代方法:创建客户端密码(需要定期轮换)。

重要

注册应用程序时,Azure 将同时创建应用程序对象和服务主体对象。 将 服务主体的对象 ID (在 “企业应用程序 ”窗格中找到)添加到 Azure DevOps 时使用,而不是应用程序的对象 ID。

如需了解更多信息,请参阅以下文章:

选项 B:创建托管标识

托管标识为 Azure 托管的应用程序提供最简单的身份验证体验。

对于系统分配的托管标识:

  1. 转到 Azure 资源,例如应用服务或 Azure Functions 应用。
  2. 转到标识>系统分配
  3. 将状态切换到 “开”。
  4. 选择 “保存” 以保存配置。

对于用户分配的托管标识:

  1. 在 Azure 门户中创建托管标识。
  2. 转到 “创建资源>托管身份”。
  3. 配置基本设置并创建资源。
  4. 根据需要分配给资源。

如需了解更多信息,请参阅以下文章:

步骤 2:将标识添加到 Azure DevOps

在 Microsoft Entra ID 中创建标识后,将其添加到 Azure DevOps 组织,以授予对资源的访问权限。

先决条件

  • 项目集合管理员角色。
  • 邀请策略 允许团队管理员添加用户时,项目管理员或团队管理员角色。

添加标识

若要通过 Azure DevOps 门户添加标识,请执行以下作:

  1. 转到 组织设置>用户

  2. 选择 “添加用户”。

  3. 输入服务主体或托管标识的显示名称。

  4. 选择适当的访问级别和项目访问权限。

  5. 发送邀请。

    显示用户中心中的服务主体和托管标识的屏幕截图。

以编程方式添加标识:

使用 ServicePrincipalEntitlements REST API 自动执行该过程。

其他注意事项:

  • 查找正确的 ID: 在Microsoft Entra 管理中心的 “企业应用程序 ”窗格中使用服务主体的对象 ID,而不是应用程序注册的对象 ID。
  • 租户限制: 只能从 Azure DevOps 组织连接到的同一租户添加标识。 有关跨租户方案,请参阅 常见问题解答解决方法

步骤 3:配置权限

在 Azure DevOps 中为服务主体或托管标识配置精细权限。 与其他 Azure 服务不同,Azure DevOps 使用自己的权限模型,而不是Microsoft Entra 应用程序权限。

权限选项:

  • 直接分配:将权限直接分配给标识。
  • 组成员身份:添加到 Azure DevOps 或Microsoft Entra 安全组。
  • 访问级别:分配适当的许可证级别(基本、基本 + 测试计划或 Visual Studio 订阅者)。

最佳实践:

  • 应用最低权限:仅授予所需的最低权限。
  • 使用组:通过组管理权限,以便更轻松地维护。
  • 定期评审:定期审核权限。

权限管理选项:

  • Azure DevOps 门户:选择 组织设置>权限
  • REST API:使用 服务主体图形 API 进行编程管理。

重要

Azure DevOps 与 Microsoft Entra 权限: Azure DevOps 不使用 Microsoft Entra ID 应用程序权限。 所有访问控制都通过 Azure DevOps 权限系统进行管理,该系统允许精细的项目和资源级权限。

步骤 4:获取Microsoft Entra ID 令牌

获取访问令牌,以使用 Azure DevOps API 和服务对应用程序进行身份验证。

对于服务主体

使用客户端凭据流:

POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

client_id={client-id}
&scope=https://app.vssps.visualstudio.com/.default
&client_secret={client-secret}
&grant_type=client_credentials

使用证书身份验证(建议):

using Microsoft.Identity.Client;

var app = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithCertificate(certificate)
    .WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
    .Build();

var result = await app
    .AcquireTokenForClient(new[] { "https://app.vssps.visualstudio.com/.default" })
    .ExecuteAsync();

string accessToken = result.AccessToken;

对于托管标识

从 Azure 资源:

using Azure.Identity;
using Azure.Core;

var credential = new ManagedIdentityCredential();
var tokenRequest = new TokenRequestContext(new[] { "https://app.vssps.visualstudio.com/.default" });
var token = await credential.GetTokenAsync(tokenRequest);

string accessToken = token.Token;

使用 Azure 实例元数据服务:

GET http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://app.vssps.visualstudio.com/
Metadata: true

用于即席作的 Azure CLI

针对一次性操作或测试,可以使用 Azure CLI。

# For service principal
az login --service-principal --username {client-id} --password {client-secret} --tenant {tenant-id}
az account get-access-token --resource https://app.vssps.visualstudio.com/

# For managed identity (from Azure resource)
az login --identity
az account get-access-token --resource https://app.vssps.visualstudio.com/

有关详细信息,请参阅 获取Microsoft Entra 令牌

步骤 5:将令牌与 Azure DevOps 配合使用

使用获取的令牌对 REST API 调用和其他 Azure DevOps 操作进行身份验证。

进行经过身份验证的 API 调用:

using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", accessToken);

var response = await client.GetAsync(
    "https://dev.azure.com/{organization}/_apis/projects?api-version=7.1");

视频示例

常见集成方案

有关完整的代码示例,请参阅示例 应用程序

管理注意事项

与用户帐户相比,服务主体和托管标识具有不同的管理特征。

许可

  • 每个标识都需要其加入的每个组织中的许可证。
  • 多组织计费 不适用于服务主体。
  • 基于组的许可规则不会自动应用。 必须直接分配许可证。

标识管理

  • 不使用电子邮件地址,因此没有通过电子邮件邀请。
  • Azure DevOps 中不会修改显示名称或头像。
  • 显示名称继承自 Microsoft Entra ID。

组成员身份

  • 可以添加到 Microsoft Entra 组和 Azure DevOps 组。
  • 具有阻止在Microsoft Entra 组成员列表中显示的技术限制(仅限 UI 限制)。
  • 仍可从其所属的 entra 组Microsoft继承权限。

物化

  • 必须显式添加到组织(没有像用户这样的自动具体化)。
  • 必需,因为服务主体无法以交互方式登录。

与用户帐户的主要区别

与普通用户相比,服务主体和托管标识具有特定的限制。

Capabilities

  • ✅ 生成用于 API 访问的Microsoft Entra 令牌。
  • ✅ 使用适当的权限访问 Azure DevOps 资源。
  • ✅ 加入安全组和团队。
  • ❌ 创建 PAT 或安全 Shell 密钥。
  • ❌ 通过 Web UI 以交互方式登录或访问。
  • ❌ 创建或拥有组织。
  • ❌ 支持 Azure DevOps OAuth 流。

账单管理

  • 计入每个组织中的单独许可证。 (没有多组织折扣。
  • 必须直接分配访问级别。 (组规则不会自动应用。

常见问题

Q. 为何应使用服务主体或托管标识而不是 PAT?

答: 服务主体和托管标识比 PAT 具有显著的安全优势。

安全优势:

  • 较短的寿命:与 PAT 相比,Microsoft Entra 令牌每小时过期,最长可持续一年。
  • 自动轮换:托管标识自动轮换凭据。
  • 没有共享机密:消除了存储或意外公开长期令牌的风险。
  • 集中控制:使用企业安全策略通过 Microsoft Entra ID 进行管理。

运营优势:

  • 审核线索:完全记录身份验证和访问模式。
  • 条件访问:根据位置、设备和风险因素应用策略。
  • 无服务帐户:无需依赖单个用户帐户实现自动化。

有关迁移示例,请参阅 将 PAT 替换为 Microsoft Entra 令牌

Q. 服务主体和托管标识的速率限制是什么?

答: 服务主体和托管标识的 速率限制 与用户相同。

Q. 使用此功能的成本会更高吗?

答: 服务主体和托管标识的价格与基于访问级别的用户一样。 主要区别包括:

  • 无多组织计费折扣:每个标识都算作每个组织中的单独许可证。
  • 许可证分配:必须直接分配访问级别。 (组规则不会自动应用。
  • 相同的定价层:基本、基本 + 测试计划和 Visual Studio 订阅者费率适用。

Q. 是否可以将来自其他租户的托管标识添加到我的组织?

答: 只能直接从组织的已连接租户添加标识。 对于跨租户方案,请使用此解决方法。

若要设置跨租户托管标识,请执行以下作:

  1. 在资源租户中创建用户分配的托管标识。
  2. 将其分配给 Azure 资源,例如虚拟机或 Functions 应用)。
  3. 创建密钥保管库并生成证书(非 PEM 格式)。
  4. 使用 “获取 ”和 “列出 机密”权限授予对密钥保管库的托管标识访问权限。
  5. 仅下载 CER 格式(公钥)的证书。
  6. 在目标租户中注册应用程序。
  7. 将证书上传到应用程序注册。
  8. 将服务主体添加到 Azure DevOps 组织。
  9. 使用密钥保管库中的证书配置身份验证。
// Example: Acquire token using managed identity certificate
public static async Task<string> GetSecret(string keyVaultName, string secretName)
{
    var keyVaultUri = new Uri($"https://{keyVaultName}.vault.azure.net");
    var client = new SecretClient(keyVaultUri, new ManagedIdentityCredential());
    var keyVaultSecret = await client.GetSecretAsync(secretName);
    return keyVaultSecret.Value.Value;
}

private static async Task<AuthenticationResult> GetAppRegistrationAADAccessToken(
    string applicationClientID, string appTenantId)
{
    byte[] privateKeyBytes = Convert.FromBase64String(await GetSecret(keyVaultName, secretName));
    var certificate = new X509Certificate2(privateKeyBytes, (string)null, X509KeyStorageFlags.MachineKeySet);

    var app = ConfidentialClientApplicationBuilder.Create(applicationClientID)
        .WithCertificate(certificate)
        .WithAuthority(new Uri($"https://login.microsoftonline.com/{appTenantId}"))
        .Build();

    var result = await app.AcquireTokenForClient(
        new[] { "499b84ac-1321-427f-aa17-267ca6975798/.default" })
        .ExecuteAsync();

    return result;
}

重要

定期轮换证书以获取安全最佳做法。

常见错误和解决方法

名称或标识符的 Git 存储库不存在,或者你没有权限

溶液: 确保服务主体至少具有基本许可证。 利益干系人许可证不提供存储库访问权限。

未能使用对象 ID 创建服务主体

溶液: 验证你是否在 企业应用程序 窗格中使用服务主体的对象 ID,而不是应用程序注册的对象 ID。

若要查找正确的 ID,请执行以下作:

  1. 转到 Microsoft Entra 管理中心>企业应用程序
  2. 搜索应用程序名称。
  3. “企业应用程序 ”窗格中使用对象 ID。

拒绝访问:需要添加用户的权限

可能的原因和解决方案:

  • 角色不足:必须是启用了邀请权限的项目集合管理员(PCA)或项目或团队管理员。
  • 策略限制:检查是否已启用 允许团队和项目管理员邀请新用户 策略。
  • 许可证分配:项目管理员无法在邀请期间分配许可证。 请联系 PCA 获取许可证更改。

Azure DevOps Graphs 列表接口返回空列表

溶液: 用于 continuationToken 循环访问所有页面。 由于 API 分页行为,服务主体可能会在以后的页面上显示。

TF401444:需要登录的错误

溶液: 确保服务主体已正确添加到具有所需权限的组织。 此错误表示组织中无法识别标识。