3. Azure RBAC核心机制

Azure RBAC(基于角色的访问控制)是 Azure 资源访问控制的统一授权引擎。它的核心思想可以用一句话概括:“谁(安全主体)在什么范围(Scope)上拥有什么权限(角色定义)”。这三者组合起来,就形成一条角色分配(Role Assignment)。理解 RBAC,本质上就是理解这三个要素以及它们之间的组合规则。

很多初学者会把 RBAC 与 Entra ID 目录角色混淆。需要明确:Entra ID 角色(如全局管理员)管理的是目录对象(用户、组、应用注册);而 Azure RBAC 管理的是Azure 资源(虚拟机、存储账户、Key Vault、订阅本身)。两者是不同平面上的授权体系,不要混用。

角色定义:权限的“模板”

角色定义(Role Definition)是一份权限清单,它规定了“允许做什么”和“不允许做什么”。一份角色定义包含以下关键字段:

  • Name / Id:角色名称与唯一标识(内置角色有固定 GUID)。
  • IsCustom:是否为自定义角色。
  • Actions:允许的控制平面操作,例如 Microsoft.Compute/virtualMachines/start/action。
  • NotActions:从 Actions 中减去的操作,用于收窄权限,但不是拒绝。
  • DataActions / NotDataActions:数据平面操作,例如读取 Blob 内容 Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read。
  • AssignableScopes:该角色可以被分配的范围,自定义角色必须显式声明。
关键理解:NotActions 不是“拒绝”。它只是从 Actions 集合中做减法。如果另一个角色分配授予了同一操作,最终仍然允许。真正的拒绝需要拒绝分配(Deny Assignment),那是另一套机制。

范围层级:权限的“作用域”

Azure 的资源组织是树形结构,RBAC 的授权范围也沿这棵树继承:

  • 管理组(Management Group):树的根,用于跨订阅统一治理。
  • 订阅(Subscription):计费与配额边界。
  • 资源组(Resource Group):生命周期管理单元。
  • 资源(Resource):最细粒度,如单台 VM、单个存储账户。

继承规则是向下传递:在管理组授予的权限,会自动作用于其下所有订阅、资源组和资源。反过来,在资源上授予的权限不会向上影响。因此,范围越大,影响面越广,越应谨慎。

Azure RBAC 范围层级与权限继承 权限自上而下继承 · 范围越大影响面越广 管理组 Management Group 跨订阅治理 · 策略与 RBAC 统一入口 范围最大 订阅 Subscription 计费边界 · 配额边界 · 资源容器 资源组 Resource Group 生命周期管理单元 · 部署与删除边界 资源 Resource 单台 VM · 存储账户 · Key Vault · SQL 数据库 范围最小 继承方向 向下传递 示例:在订阅范围授予“读者”角色 → 该订阅下所有资源组与资源均获得读取权限

角色分配:把三者绑定起来

角色分配是 RBAC 的“执行动作”。一条角色分配由三个要素构成:安全主体 + 角色定义 + 范围。例如:

安全主体:user@contoso.com
角色定义:Reader(读者)
范围:/subscriptions/aaaa-bbbb-cccc-dddd
结果:该用户可读取此订阅下所有资源,但不能修改

角色分配是叠加的。如果同一主体在订阅范围有 Reader,在某个资源组范围有 Contributor,那么在该资源组内,Contributor 的权限生效(因为 Contributor 包含 Reader 的所有操作)。RBAC 是“允许模型”,没有显式拒绝时,权限取并集。

内置角色与自定义角色

Azure 提供了大量内置角色,常用的有:

角色典型权限适用场景
Owner(所有者)全部资源权限 + 可分配角色资源最高管理者
Contributor(参与者)可创建和管理资源,不能分配角色日常运维人员
Reader(读者)只读查看审计、监控、只读用户
User Access Administrator仅管理角色分配权限管理员
Virtual Machine Contributor管理 VM,不能改网络与存储VM 运维
Storage Blob Data Reader读取 Blob 数据(数据平面)数据读取应用

当内置角色无法满足最小权限原则时,就需要自定义角色。自定义角色的创建需要三个关键输入:

  1. Actions / DataActions:明确允许哪些操作。
  2. NotActions / NotDataActions:可选,用于收窄。
  3. AssignableScopes:声明该角色可在哪些范围被分配。

下面是一个自定义角色的 JSON 示例,目标:允许启动和重启虚拟机,但不能删除,且只能在指定订阅内分配。

{
  "Name": "VM Start Restart Operator",
  "Description": "可启动和重启虚拟机,不可删除或修改配置",
  "Actions": [
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/restart/action",
    "Microsoft.Compute/virtualMachines/read"
  ],
  "NotActions": [],
  "AssignableScopes": [
    "/subscriptions/aaaa-bbbb-cccc-dddd"
  ]
}

创建后,该角色会出现在该订阅的角色列表中,可以像内置角色一样被分配。注意:AssignableScopes 决定了角色的“可分配边界”,如果只写了某个订阅,就不能在管理组或其他订阅上分配它。

实践建议:自定义角色应遵循最小权限原则。先列出业务真正需要的操作,再逐步收窄。不要直接复制 Contributor 再删几条,那样容易留下过宽权限。

如何判断权限是否生效

当用户反馈“无法操作”时,排查顺序建议如下:

  1. 确认用户登录的身份是否正确(是否有多个账户)。
  2. 在目标范围(资源 → 资源组 → 订阅 → 管理组)逐层查看“访问控制 (IAM)”中的角色分配。
  3. 检查是否存在拒绝分配(Deny Assignment),它会覆盖允许。
  4. 确认操作属于控制平面还是数据平面。例如读取 Blob 内容需要 DataActions,而 Reader 只给控制平面读取。
  5. 使用 Check Access 或 az role assignment list 验证有效权限。
az role assignment list \
  --assignee user@contoso.com \
  --scope /subscriptions/aaaa-bbbb-cccc-dddd \
  --include-inherited \
  --output table

该命令会列出直接分配和继承的角色。如果结果为空,说明该主体在此范围没有任何 RBAC 授权。

范围选择的核心原则

范围选择直接决定安全边界。一个实用的判断方法是:“这个权限需要覆盖多少资源?” 如果只需要管理一个资源组内的资源,就不要在订阅范围授予。如果多个订阅需要统一策略,才考虑管理组。范围越小,爆炸半径越小,审计也越清晰。

同时要注意:角色分配数量本身也有配额限制(每个订阅默认约 4000 条,可申请提升)。大规模环境中,应优先使用安全组而非单个用户进行分配,这样人员变动时只需调整组成员,不必逐条修改角色分配。

总结来说,Azure RBAC 的四个关键词是:角色定义(能做什么)、角色分配(谁在什么范围拥有它)、范围层级(权限作用到哪里)、内置与自定义(用现成的还是自己裁剪)。把这四者串起来,就能在 Azure 中构建出既安全又可维护的访问控制体系。