Microsoft Entra 工作负载身份(Workload Identity)
工作负载身份是应用、服务、脚本和流水线用于访问受 Microsoft Entra 保护资源的非人类身份。在近期的事后事件报告中,它们是云入侵的首要来源——通常是因为客户端密钥泄露、服务主体权限过大或证书过期无人管理。
本技能涵盖选择正确的身份类型、通过联合消除密钥、加固服务主体,以及应用 Workload Identities Premium 控制项。
何时使用
设计 Azure 资源、GitHub Action、Azure DevOps 流水线、AKS Pod 或外部工作负载如何向受 Entra 保护的 API(Azure Resource Manager、Microsoft Graph、Key Vault、Storage 等)进行身份验证时使用。
不要将本技能用于人类身份(entra-id)、多云权限分析(entra-permissions-management)或专门针对 AI 智能体身份治理(agent-identity-governance)的场景。
选择正确的身份
工作负载 / 最佳身份
Azure 托管资源(App Service、Function、VM、AKS Pod、Container Apps):托管标识(若为 1:1 则用系统分配,若共享或生命周期解耦则用用户分配)
GitHub Actions / GitLab CI / Azure DevOps / Jenkins:工作负载身份联合到用户分配的托管标识或应用注册
Azure 之外且具有 OIDC 颁发者的工作负载(Kubernetes、AWS、GCP):工作负载身份联合
无 OIDC 的旧式本地服务:使用证书的应用注册(绝不用密钥)
仅向 Microsoft Graph 进行身份验证的任何场景:应用注册 + 联合/证书
经验法则:如果你的设计文档中出现客户端密钥,说明你错过了联合的机会。先尝试联合;退而求其次用证书;新构建绝不使用客户端密钥。
方法
清点现有服务主体和凭据。使用 Microsoft Graph(servicePrincipals、applications)列出每个应用注册、其密钥/密钥凭据、到期日期和已分配角色。大多数租户会发现过期密钥、十年前的测试应用以及无人拥有的管理员已同意应用。
在联合可行处消除密钥:
GitHub Actions → Azure:在用户分配的托管标识(或应用注册)上配置联合凭据,主题为 repo:org/repo:environment:prod。GitHub 中无需密钥。
AKS 工作负载身份:在集群上启用,为服务账户添加注解,投影令牌;Pod 以绑定到的用户分配托管标识进行身份验证。
Azure DevOps:使用工作负载身份联合服务连接。
外部 OIDC 颁发者(GCP、AWS、Okta):添加带有颁发者 URL 和主题声明的联合凭据。
在必须保留凭据的地方,使用由 Key Vault 轮换的证书,而非客户端密钥。设置较短有效期(≤180 天)并自动轮换。
应用最小权限 RBAC。默认在资源或资源组级别进行范围化角色分配——除非有正当理由,绝不使用订阅所有者。当存在范围化或按应用集合的权限(Sites.Selected、通过应用访问策略的特定邮箱 Mail.Send)时,避免 Microsoft Graph .All 权限(如 Files.ReadWrite.All)。
Workload Identities Premium(单独 SKU)。解锁:
工作负载的条件访问——阻止来自意外 IP 范围的服务主体登录,要求命名位置,按客户端应用限制。
工作负载身份风险检测——泄露的凭据、异常登录、可疑管理员活动。
工作负载身份的访问评审——定期由所有者评审服务主体角色。适用于面向外部或高权限的工作负载身份;不必对租户中每个服务主体都应用。
生命周期:每个应用注册必须有所有者(不是已离职人员,也不是空列表)。每季度评审无主和未使用的应用;先禁用再删除。
监控。将 ServicePrincipalSignInLogs 流式传输到 Sentinel。对以下情况告警:
来自预期基线之外的国家/IP 的登录。
新增凭据(尤其是由所有者之外的其他身份添加)。
非工作时间高权限角色的令牌颁发。
护栏
新设计中不使用客户端密钥。联合 > 证书 > 密钥。
系统分配的托管标识与资源生命周期绑定。删除资源,标识(及其角色分配)随之消失——通常是好事,有时令人意外。
跨资源共享的用户分配托管标识很方便,但会破坏爆炸半径隔离。仅当生命周期和信任边界真正匹配时才共享。
联合凭据必须具体。主题 repo:org/repo:* 接受每个分支和 PR——包括攻击者的 fork。固定到环境或受保护分支。
没有明确理由不使用 .All Graph 权限。使用 Sites.Selected、邮件应用访问策略或仅应用 RBAC 范围化。
不要为每个环境创建一个应用注册。每个工作负载一个应用,多个联合凭据(每个环境一个)——保持角色清单整洁。
所有者 = 一个人 + 一个组。单一所有者的应用在人员离职后会变成孤儿。
工作负载的 CA 是单独的、高级策略类型。如果依赖它满足合规,请确保已启用。
常见反模式
“GitHub Action 将 AZURE_CREDENTIALS 存储为 JSON 密钥”——泄露密钥风险。改用 OIDC 联合。
“整个 DevOps 平台用一个巨型服务主体,在每个订阅上拥有所有者”——一次入侵 = 整个租户。应按流水线划分身份并范围化。
“客户端密钥 2099 年到期”——长期有效的持有者密钥使任何轮换策略失效。上限 180 天,自动化。
“AKS Pod 使用节点池 MSI 访问应用数据”——节点上每个 Pod 拥有相同身份。按服务账户使用 AKS 工作负载身份。
“联合凭据主题 = repo:org/repo:**”——接受任何分支包括 PR。固定到 environment:prod。
“服务主体被授予全局管理员以运行报告脚本”——只读 Graph 权限、范围化,本已足够。
“应用注册所有者列表为空”——无人评审或轮换。孤儿应用是审计发现项。
示例提示
将我们 GitHub Actions Azure 部署中的客户端密钥替换为工作负载身份联合。
将 12 个 AKS 工作负载从 kiam/pod-identity 迁移到 AKS 工作负载身份。
清点所有 30 天内密钥到期的应用注册,并优先安排证书轮换。
对薪资集成服务主体应用条件访问,将 IP 限制为合作伙伴 CIDR。
为 Azure DevOps 设计联合凭据,使用环境范围化的主题声明区分生产与开发。
审计具有 Microsoft Graph .All 权限的服务主体,并提出范围化替代方案。
使用 Workload Identities Premium 为高权限工作负载身份推出季度访问评审。
在 Sentinel 中搜寻异常服务主体登录——KQL 检测。
Microsoft Learn
工作负载身份概述:https://learn.microsoft.com/entra/workload-id/workload-identities-overview
托管标识:https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview
工作负载身份联合:https://learn.microsoft.com/entra/workload-id/workload-identity-federation
GitHub Actions OIDC:https://learn.microsoft.com/entra/workload-id/workload-identity-federation-create-trust?pivots=identity-wif-apps-methods-azp
AKS 工作负载身份:https://learn.microsoft.com/azure/aks/workload-identity-overview
Azure DevOps 工作负载身份:https://learn.microsoft.com/azure/devops/pipelines/library/connect-to-azure?view=azure-devops#create-an-azure-resource-manager-service-connection-that-uses-workload-identity-federation
工作负载身份的条件访问:https://learn.microsoft.com/entra/identity/conditional-access/workload-identity
工作负载身份风险:https://learn.microsoft.com/entra/id-protection/concept-workload-identity-risk
Microsoft Graph 应用程序权限参考:https://learn.microsoft.com/graph/permissions-reference