可变主体是 OpenID Connect(OIDC)subject(sub)声明值,外部签发方基于其允许更改或重复使用的名称构建该值。 Microsoft Entra 联合身份凭据通过匹配外部颁发者令牌中的声明(尤其是 sub 声明)来建立信任。 当该主题派生自可变值时,信任关系可能会变得不明确,因为同一标识符以后可能属于不同的工作负荷。
本文介绍哪些使主题可变、可变主题引入的安全风险以及如何将信任定位到不可变主题,以便联合标识凭据仅信任你预期的工作负荷。
使主题可变的内容
当主体是从颁发者允许更改或重复使用的值派生出来时,该主体就是可变的。 常见示例包括:
- 重命名、传输或删除并使用相同的名称重新创建的项目或存储库。
- 重命名后重复使用的组、命名空间或组织句柄。
- 基于用户名而不是稳定的内部 ID 的用户标识符。
相比之下,无法更改或回收不可变标识符。 它将永久地锚定到原始资源或工作负载。 如果颁发者提供不可变标识符,则应将信任锚定到这些值上。
可变主题的安全风险
将信任与可变主体进行匹配,会使联合身份凭据面临两种相关风险。
主题回收
对象重复使用是主要风险。 它可以按以下方式展开:
- 管理员创建一个信任基于名称的主体的联合身份凭据。
- 原始资源已删除、重命名或传输。
- 该标识符将再次可用。
- 另一方获取该标识符。
- 该方的令牌现在生成与现有联合标识凭据匹配的主题。
- 该方获得了原本仅供原始工作负载使用的访问权限。
悬空的联合身份凭据
悬空的联合身份凭据是指这样一种凭据:在其所信任的工作负载已不再存在后,该凭据仍然处于已配置状态。 悬空凭据尤其容易受到主体回收的影响:受信任名称现在可能会重新变为可复用,因此,来自其他工作负载的令牌也可能满足匹配条件。
建议的联合标识凭据卫生
租户管理员决定谁信任,Microsoft Entra提供精确表达信任的机制。 若要保持信任态势强劲,请遵循以下做法:
- 首选不可变的主题。 如果颁发者提供不可变主体,请配置联合标识凭据或灵活联合标识凭据,使其与该不可变主体匹配,而不是与名称匹配。
- 删除失效的凭据。 删除其工作负载已不存在的联合标识凭据。
- 定期审阅。 定期审核联合标识凭据,以确认它们是否仍与预期工作负荷相对应,并且匹配的值保持不可变。
- 将权限范围限定为最小。 仅授予工作负荷所需的权限,使任何不匹配都具有有限的影响。
将信任锚定到不可变主体
抵制主题回收的最强方法是信任不可变的主题。 某些颁发者允许工作负载提供一个基于稳定的内部 ID 而非名称构建的 sub 声明。 当颁发者支持此选项时,请将联合标识凭据配置为匹配不可变的主题。
可以通过两种方式匹配不可变的主题:
- 标准联合标识凭据与
sub值完全匹配。 -
灵活的联合身份凭据通过使用声明匹配表达式来匹配
sub声明,该表达式支持在多个分支或标记等场景中使用通配符。
GitLab:使用不可变主题
GitLab 是一个示例颁发者,它以前生成了可变主题,现在提供不可变的选项。 默认情况下,GitLab 从基于名称且可变的项目路径生成 sub 声明:
{
"iss": "https://gitlab.com",
"sub": "project_path:acme-group/billing-service:ref_type:branch:ref:main"
}
由于组或项目路径可能被重命名、转移或重新占用,因此,以 project_path 开头的主体会面临主体被重复利用的风险。
GitLab 通过两种方式降低此风险:
- 平台保护。 当命名空间路径以前属于已删除或重命名的其他项目时,GitLab 会阻止 CI ID 令牌颁发。
- 不可变的主题。 GitLab 允许项目显示一个标题,该标题以不可变的
project_id开头,而不是project_path。 若要启用此功能,请通过 GitLab Projects API 将ci_id_token_sub_claim_components设置为诸如["project_id", "ref_type", "ref"]这样的值。 然后,主题以项目 ID 开头:
{
"iss": "https://gitlab.com",
"sub": "project_id:57382910:ref_type:branch:ref:main"
}
GitLab 主题要么以 project_path 开头,要么以 project_id 开头,绝不会同时以两者开头。 由于 project_id 只会被分配一次且不会被再次使用,因此,以其开头的主题即使在该路径之后被重命名或回收的情况下,仍会保持绑定到原始项目。
项目提供不可变主体后,请将 Microsoft Entra 信任锚定到该主体。 灵活的联合标识凭据可以匹配不可变的主题,并使用通配符覆盖每个分支和标记:
{
"name": "gitlab-billing-service-immutable",
"issuer": "https://gitlab.com",
"claimsMatchingExpression": {
"value": "claims['sub'] matches 'project_id:57382910:*'",
"languageVersion": 1
},
"audiences": ["api://AzureADTokenExchange"]
}
GitLab:将所需的不可变声明添加到灵活的联合标识凭据
对于 GitLab,灵活的联合标识凭据必须与声明和以下一个或多个附加声明匹配 sub :
-
project_id标识运行作业的项目。 -
namespace_id标识项目的命名空间。 -
user_id标识运行作业的用户。
无论sub以还是project_path从头project_id开始,都需要这些附加声明。 包括表示预期信任边界的声明。
以下凭据与不可变项目主体匹配,并单独验证项目和命名空间:
{
"name": "gitlab-billing-service-immutable",
"issuer": "https://gitlab.com",
"claimsMatchingExpression": {
"value": "claims['sub'] matches 'project_id:57382910:*' and claims['project_id'] eq '57382910' and claims['namespace_id'] eq '<namespace-id>'",
"languageVersion": 1
},
"audiences": ["api://AzureADTokenExchange"]
}
若要将信任限制为特定用户运行的作业,还匹配 user_id:
{
"name": "gitlab-billing-service-user",
"issuer": "https://gitlab.com",
"claimsMatchingExpression": {
"value": "claims['sub'] matches 'project_id:57382910:*' and claims['project_id'] eq '57382910' and claims['namespace_id'] eq '<namespace-id>' and claims['user_id'] eq '<user-id>'",
"languageVersion": 1
},
"audiences": ["api://AzureADTokenExchange"]
}
将占位符值替换为 GitLab ID 令牌中的 ID。 GitLab 包括 project_id每个 namespace_idID 令牌和 user_id 每个 ID 令牌中。
使用Azure CLI创建灵活的联合标识凭据
若要使用Azure CLI创建灵活的联合标识凭据,请将凭据正文保存到文件,例如credential.json,并将其发布到Microsoft Graph:az rest
az rest --method POST \
--uri "https://microsoftgraph.chinacloudapi.cn/beta/applications/<app-object-id>/federatedIdentityCredentials" \
--headers "Content-Type=application/json" \
--body "@credential.json"
将 <app-object-id> 替换为你的应用注册的对象 ID。 Microsoft Graph在请求成功时返回创建的凭据,包括claimsMatchingExpression值。
若要配置 GitLab 主题和Microsoft Entra凭据,请参阅以下资源: