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 管道、跨云场景以及需要灵活部署选项的应用程序中表现良好。
在 Microsoft Entra 管理中心注册应用程序。
转到 应用注册>“新建注册”。
配置应用程序:
- 名称:对应用程序使用描述性名称。
- 帐户类型:选择适当的租户支持。
- 重定向 URI:为服务到服务方案留空。
创建身份验证凭据:
- 建议:上传证书以提高安全性。
- 替代方法:创建客户端密码(需要定期轮换)。
重要
注册应用程序时,Azure 将同时创建应用程序对象和服务主体对象。 将 服务主体的对象 ID (在 “企业应用程序 ”窗格中找到)添加到 Azure DevOps 时使用,而不是应用程序的对象 ID。
如需了解更多信息,请参阅以下文章:
选项 B:创建托管标识
托管标识为 Azure 托管的应用程序提供最简单的身份验证体验。
对于系统分配的托管标识:
- 转到 Azure 资源,例如应用服务或 Azure Functions 应用。
- 转到标识>系统分配。
- 将状态切换到 “开”。
- 选择 “保存” 以保存配置。
对于用户分配的托管标识:
- 在 Azure 门户中创建托管标识。
- 转到 “创建资源>托管身份”。
- 配置基本设置并创建资源。
- 根据需要分配给资源。
如需了解更多信息,请参阅以下文章:
步骤 2:将标识添加到 Azure DevOps
在 Microsoft Entra ID 中创建标识后,将其添加到 Azure DevOps 组织,以授予对资源的访问权限。
先决条件
- 项目集合管理员角色。
- 当 邀请策略 允许团队管理员添加用户时,项目管理员或团队管理员角色。
添加标识
若要通过 Azure DevOps 门户添加标识,请执行以下作:
转到 组织设置>用户。
选择 “添加用户”。
输入服务主体或托管标识的显示名称。
选择适当的访问级别和项目访问权限。
发送邀请。
以编程方式添加标识:
使用 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");
视频示例
常见集成方案
- NuGet 源:使用 NuGet.exe 或 dotnet CLI 进行连接。
- 市场发布: 通过命令行发布扩展。
- Azure Pipelines:创建受托管标识支持 的服务连接 。
- Git作: 使用 Git 凭据管理器克隆存储库。
有关完整的代码示例,请参阅示例 应用程序。
管理注意事项
与用户帐户相比,服务主体和托管标识具有不同的管理特征。
许可
- 每个标识都需要其加入的每个组织中的许可证。
- 多组织计费 不适用于服务主体。
- 基于组的许可规则不会自动应用。 必须直接分配许可证。
标识管理
- 不使用电子邮件地址,因此没有通过电子邮件邀请。
- 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. 是否可以将来自其他租户的托管标识添加到我的组织?
答: 只能直接从组织的已连接租户添加标识。 对于跨租户方案,请使用此解决方法。
若要设置跨租户托管标识,请执行以下作:
- 在资源租户中创建用户分配的托管标识。
- 将其分配给 Azure 资源,例如虚拟机或 Functions 应用)。
- 创建密钥保管库并生成证书(非 PEM 格式)。
- 使用 “获取 ”和 “列出 机密”权限授予对密钥保管库的托管标识访问权限。
- 仅下载 CER 格式(公钥)的证书。
- 在目标租户中注册应用程序。
- 将证书上传到应用程序注册。
- 将服务主体添加到 Azure DevOps 组织。
- 使用密钥保管库中的证书配置身份验证。
// 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,请执行以下作:
- 转到 Microsoft Entra 管理中心>企业应用程序。
- 搜索应用程序名称。
- 在 “企业应用程序 ”窗格中使用对象 ID。
拒绝访问:需要添加用户的权限
可能的原因和解决方案:
- 角色不足:必须是启用了邀请权限的项目集合管理员(PCA)或项目或团队管理员。
- 策略限制:检查是否已启用 允许团队和项目管理员邀请新用户 策略。
- 许可证分配:项目管理员无法在邀请期间分配许可证。 请联系 PCA 获取许可证更改。
Azure DevOps Graphs 列表接口返回空列表
溶液: 用于 continuationToken 循环访问所有页面。 由于 API 分页行为,服务主体可能会在以后的页面上显示。
TF401444:需要登录的错误
溶液: 确保服务主体已正确添加到具有所需权限的组织。 此错误表示组织中无法识别标识。