4. Azure AD/Entra ID 实战:条件访问策略、托管身份与服务主体、Azure RBAC 与 ABAC
好,咱们进入 Azure 这一章。说实话,在多云身份治理里,Azure 的体系是最复杂的,但也是设计得最灵活的。它把身份分成了“人”和“非人”两条线,权限又分成了角色(RBAC)和属性(ABAC)两层。今天我就带你把这几个核心组件串起来,讲明白它们在实际项目中怎么配合。
4.1 条件访问策略:不只是“允许/拒绝”
条件访问策略,说白了就是“在什么条件下,允许谁用什么方式访问什么资源”。它不是简单的开关,而是一个策略引擎。
我刚开始接触时,觉得它跟防火墙规则差不多。后来在项目中踩了坑才明白——条件访问的评估顺序和策略组合,才是真正的难点。
4.1.1 核心组件
一条完整的条件访问策略,由三部分组成:
- 分配(Assignments):谁(用户/组)、什么(云应用)、什么条件(位置/设备状态/风险)
- 访问控制(Access Controls):允许、阻止、或要求多因素认证/合规设备
- 启用策略(Enable policy):开/关/仅报告模式
关键点:条件访问策略是“与”逻辑。所有分配条件必须同时满足,才会触发访问控制。如果某个条件不匹配,策略就不生效,而不是拒绝访问。
4.1.2 实战:配置一个“高危位置登录要求 MFA”的策略
我记得有一次,客户发现管理员账号经常从海外 IP 登录。我们立刻配了一条策略:
# 策略名称:Block-HighRisk-Locations
# 分配:
# 用户和组:所有管理员(角色组)
# 云应用:所有云应用
# 条件:
# - 位置:选择“不信任的国家/地区”
# - 客户端应用:浏览器 + 移动应用
# 访问控制:
# 授予:需要多因素认证
# 会话:使用应用强制限制
# 启用策略:开
配完之后,管理员从海外登录时,会先被要求 MFA。如果连续失败,策略会自动阻止。
我的习惯:上线前先用“仅报告”模式跑一周,看看会影响多少用户。别一上来就开“阻止”,容易把自己锁在外面。
4.1.3 避坑指南
- 策略优先级:条件访问没有优先级,所有匹配的策略都会生效。如果一条要求 MFA,另一条要求合规设备,用户必须同时满足。
- 排除紧急访问账号:我曾经见过一个客户,配了条件访问后把所有管理员都锁了,因为策略要求 MFA,但 MFA 服务本身也被策略覆盖了。所以一定要留 1-2 个紧急访问账号(Break Glass Account),排除在策略之外。
- 设备平台限制:如果策略要求“合规设备”,但用户用的是 Linux 或老旧手机,可能永远无法满足条件。记得加一个“其他客户端”的降级策略。
4.2 托管身份与服务主体:非人身份的两种形态
在 Azure 里,非人身份有两种:托管身份(Managed Identity)和服务主体(Service Principal)。很多人分不清,我简单说一下。
| 特性 | 托管身份 | 服务主体 |
|---|---|---|
| 创建方式 | 自动,绑定 Azure 资源 | 手动,通过应用注册 |
| 生命周期 | 随资源自动管理 | 需要手动管理密钥/证书 |
| 使用场景 | Azure 内部资源互访 | 外部应用、CI/CD、跨租户 |
| 密钥轮换 | Azure 自动处理 | 需要手动或脚本轮换 |
| 典型例子 | VM 访问 Key Vault | GitHub Actions 部署到 Azure |
4.2.1 托管身份实战
假设你有一个 Web App,需要读取 Key Vault 里的数据库密码。用托管身份是最优雅的方式:
# 1. 为 Web App 启用系统分配托管身份
az webapp identity assign --name myWebApp --resource-group myRG
# 2. 在 Key Vault 中授予托管身份读取权限
az keyvault set-policy --name myKeyVault \
--object-id <托管身份的对象ID> \
--secret-permissions get list
# 3. 在代码中通过 Azure SDK 获取令牌
# C# 示例
var credential = new DefaultAzureCredential();
var secretClient = new SecretClient(vaultUri, credential);
KeyVaultSecret secret = await secretClient.GetSecretAsync("db-password");
这样做的好处是:没有密钥文件,没有硬编码密码,Azure 自动帮你轮换身份。
注意:系统分配托管身份的生命周期和资源绑定。如果你删除了 Web App,这个身份也就没了。如果多个资源需要共享同一个身份,用用户分配托管身份。
4.2.2 服务主体实战
服务主体通常用于外部系统。比如你的 CI/CD 工具要部署到 Azure,就需要一个服务主体。
# 创建服务主体并分配 Contributor 角色
az ad sp create-for-rbac --name "github-actions-deployer" \
--role Contributor \
--scopes /subscriptions/<sub-id>/resourceGroups/myRG
# 输出类似:
# {
# "appId": "xxx",
# "displayName": "github-actions-deployer",
# "password": "yyy",
# "tenant": "zzz"
# }
然后把这个 appId 和 password 配置到 GitHub Secrets 里。注意,密码是一次性的,丢了就得重新创建。
我的建议:服务主体的密钥要定期轮换。我一般用 Azure Automation 或 GitHub Actions 写一个定时任务,每 90 天自动生成新密钥并更新到 Key Vault。
4.3 Azure RBAC 与 ABAC:从角色到属性的进化
RBAC 大家都很熟了——给用户分配角色,角色包含权限。但 RBAC 有个硬伤:它只能基于“你是谁”或“你在哪个组”来控制权限,不能基于“资源本身是什么”来做精细控制。
举个例子:你想让某个用户只能读取“标记为 Production”的存储账户。用 RBAC 做不到,因为 RBAC 的权限是静态的。这时候就需要 ABAC。
4.3.1 RBAC 实战:最小权限原则
我见过太多人直接给“Contributor”角色,这是不对的。正确的做法是:
- 先分析用户需要做什么(读日志?重启 VM?部署代码?)
- 找到对应的内置角色(Reader、Virtual Machine Contributor、Website Contributor)
- 如果内置角色权限太大,创建自定义角色
# 创建自定义角色:只允许重启 VM,不能做其他操作
az role definition create --role-definition '{
"Name": "VM Restart Operator",
"Description": "Can restart virtual machines",
"Actions": [
"Microsoft.Compute/virtualMachines/restart/action"
],
"NotActions": [],
"AssignableScopes": ["/subscriptions/<sub-id>"]
}'
4.3.2 ABAC 实战:基于属性的条件
ABAC 是 RBAC 的增强版。它在角色分配的基础上,增加了条件表达式。条件可以基于资源属性、请求属性或环境属性。
我记得有个项目,客户要求“开发人员只能读取自己部门的存储容器”。我们用 ABAC 实现了:
# 条件表达式(使用 Azure 条件语言)
(
(
!(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/read'})
)
OR
(
@Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name]
StringEquals 'dev-*'
)
)
这个条件的意思是:如果操作不是读取,允许;如果是读取,只允许读取名称以“dev-”开头的容器。
核心区别:RBAC 是“谁可以做什么”,ABAC 是“谁可以在什么条件下做什么”。ABAC 让权限从静态变成了动态。
4.3.3 什么时候用 ABAC?
- 资源数量巨大,无法手动分组(比如上千个存储容器)
- 权限需要根据资源标签、名称、地域动态变化
- 需要实现“数据层面”的细粒度控制(比如只读某些列)
但 ABAC 也有代价:条件表达式写起来复杂,调试困难。我建议先从 RBAC 开始,等确实遇到“RBAC 搞不定”的场景时,再引入 ABAC。
4.4 本章知识体系
下面这张图,把 Azure 身份治理的核心逻辑串起来了:
嗯,这张图把整个流程串起来了。你想想看,从身份到策略,再到权限模型,最后到资源,每一层都有对应的 Azure 服务。理解了这张图,你就掌握了 Azure 身份治理的骨架。
4.5 本章小结
这一章我们实战了三个核心组件:
- 条件访问策略:控制“谁在什么条件下能访问”,记得留紧急账号和用仅报告模式
- 托管身份与服务主体:非人身份的两条路,内部用托管身份,外部用服务主体
- RBAC 与 ABAC:从静态角色到动态属性,ABAC 是 RBAC 的补充,不是替代