Agent时代RBAC为什么只完成了一半

32 阅读18分钟

Agent 时代,RBAC 为什么只完成了一半

RBAC 没有过时。它仍然适合回答“这类人通常能做什么”,但 Agent 执行还要回答:哪个 Agent,为了哪次任务,在什么条件下,可以对哪些具体对象执行多少次什么动作。

企业给 Agent 接入 CRM、ERP、HR 或财务系统时,最常见的一句话是:

不用再做权限,沿用现有 RBAC 就行。

这句话有一半是对的。

现有 RBAC 不应该被绕过。员工原本不能查看的客户、不能审批的付款、不能修改的合同,Agent 也不能因为接入了 MCP 就突然获得权限。

但如果方案到这里结束,另一半问题会被漏掉:

这个用户有权限
≠
这个 Agent 在这次任务中已获得同样范围的自动执行授权

传统 RBAC 主要围绕用户、角色和权限展开。Agent 场景又增加了执行主体、资源关系、任务意图、时间窗口、调用次数、批量规模和运行时风险。

所以标题不是“RBAC 已死”,而是“RBAC 只完成了一半”。

RBAC 仍然是底座,只是不再是完整答案。

RBAC 解决了什么

RBAC 的价值首先是降低权限管理成本。

如果没有角色,管理员可能要给每名员工逐项配置权限:

张三 → 查看客户
张三 → 修改商机
李四 → 查看客户
李四 → 修改商机
……

使用 RBAC 后,可以先把权限赋给角色,再把人员分配到角色:

角色:销售经理
权限:查看客户、修改商机、提交折扣申请

张三 → 销售经理
李四 → 销售经理

NIST 已归档的 RBAC 项目页对这一经典模型的介绍很清楚:RBAC 让安全管理贴近组织结构,用户被分配一个或多个角色,角色拥有相应权限;角色层级和互斥角色等复杂关系也可以由 RBAC 软件处理。这里引用它作为历史模型依据,不把该归档页面当成当前产品实施指南。

这几个能力在 Agent 时代仍然重要:

  • 大规模人员授权;
  • 岗位与基础权限映射;
  • 角色层级;
  • 静态或动态职责分离;
  • 入职、调岗和离职治理;
  • 权限申请与周期复核。

假设财务专员没有付款审批角色,代表他的 Agent 同样不能审批付款。

用户 RBAC Deny
→ Agent 必须 Deny

Agent 平台不能通过 MCP、Ontology、PDP 或共享服务账号把这条 Deny 改成 Allow。

RBAC 没有回答什么

RBAC 擅长表达:

销售经理可以修改商机

但一次 Agent 执行需要更具体的问题:

哪个销售经理?
哪个 Agent 和版本?
代表用户还是自主运行?
为了哪次任务?
修改哪个区域、项目或客户的商机?
允许改哪些字段?
当前业务状态是否允许修改?
最多处理多少条?
权限何时过期?
失败后能否重试?
累计影响是否超出预算?

这些问题并非都适合继续堆进角色名称。

如果强行使用 RBAC,角色会迅速膨胀:

华东区销售经理
华东区大客户销售经理
华东区项目 A 大客户销售经理
华东区项目 A 临时代理销售经理
华东区项目 A 可批量修改但不可删除销售经理
……

角色开始同时承载组织、区域、项目、时间、数据关系和任务范围,最终形成 Role Explosion。

这不是 RBAC 实现得不够好,而是把不同维度的问题都塞进了角色。

ABAC 补上运行时条件

NIST SP 800-162 将 ABAC 定义为一种逻辑访问控制方法:通过评估 Subject、Object、Requested Operation 以及某些情况下的 Environment 属性,并将其与策略、规则或关系比较,决定是否允许操作。

放到 Agent 场景中,可以得到:

Subject 属性
- 用户部门
- 用户职级
- 用户所属法人
- Agent 身份
- Agent 风险等级
- Agent 版本

Object 属性
- 客户所属区域
- 合同密级
- 发票金额
- 数据所属法人
- 记录当前状态

Action 属性
- read
- update
- approve
- refund
- export

Environment 属性
- 当前时间
- 来源网络
- 设备可信度
- 风险评分
- 是否完成 Step-up

策略可以写成:

用户具有“财务审批人”角色
且发票所属法人等于用户所属法人
且金额不超过用户审批上限
且 Agent 风险等级允许执行写操作
且当前会话已完成 Step-up
→ 可以进入审批动作

ABAC 解决的是“同一个角色,在不同对象和环境下,决策可能不同”。

它比继续增加组合角色更适合表达金额、时间、地域、敏感度和运行时风险。

ABAC 也不能包办所有关系

理论上,很多关系都可以转成属性:

user.project_ids = [A, B, C]
resource.project_id = A

然后判断两者是否匹配。

小规模系统这样做完全可行。

但在大型企业中,关系往往不是单层属性:

张三是项目 A 成员
项目 A 属于事业群 B
事业群 B 管理供应商 C
合同 D 属于供应商 C

还可能出现:

  • 文件由某个团队拥有;
  • 用户是团队成员;
  • Agent 被分配给某项任务;
  • 任务获得某个项目的写权限;
  • 项目下的工单继承项目权限;
  • 临时代理只对一个客户生效。

如果把这些关系全部展开为用户属性,缓存失效、关系更新和列表膨胀会变得困难。

这正是关系授权模型擅长的部分。

ReBAC 补上人与资源之间的关系

ReBAC 通常根据主体与对象之间的关系决定权限。

Google Zanzibar 展示了一种大规模关系授权系统:通过统一数据模型和配置语言表达访问控制列表,并为多个 Google 服务提供授权判断。OpenFGA 则以 Authorization Model 和 Relationship Tuple 表达用户、关系与对象之间的连接。

典型关系元组可以写成:

user:zhangsan
relation: member
object: project:east-2026

或者:

task:purchase-001
relation: write
object: project:east-2026

授权系统再根据模型计算:

项目成员可以读取项目
项目所有者可以编辑项目
项目管理员可以删除项目
工单继承所属项目的读取权限

ReBAC 对以下场景很自然:

  • 一人多岗;
  • 矩阵组织;
  • 项目成员关系;
  • 临时代理;
  • 资源所有者;
  • 上下级组织继承;
  • 文档共享;
  • 任务与 Agent 的绑定;
  • 项目到子资源的权限继承。

但 ReBAC 也不是新的万能权限中台。

它能证明张三与项目 A 有关系,却不会自动知道:

  • 当前金额是否超过限额;
  • 数据是否处于冻结状态;
  • 是否完成二次认证;
  • 这次任务最多可以执行几次;
  • 下游系统当前是否最终允许写入。

关系是授权输入,不是完整业务状态机。

Agent 场景还缺一个任务维度

到这里,我们已经有:

RBAC:用户长期拥有哪类基础权限
ABAC:当前主体、对象、动作和环境满足哪些条件
ReBAC:主体与具体资源之间存在什么关系

它们仍然没有完整表达用户这次究竟把什么交给了 Agent。

例如,客服人员长期拥有 5000 元以内的退款权限。

RBAC 可以判断他属于退款专员角色。

ABAC 可以判断退款金额不超过 5000 元,订单状态也允许退款。

ReBAC 可以判断该订单属于他的处理队列。

但用户说的可能只是:

给订单 A 退 300 元,原因是物流超时。

这次任务并没有授权 Agent 对处理队列中的其他订单退款,也没有授权它连续重试十次。

因此,还需要一个短生命周期的任务授权对象。

任务授权不是换一个角色名称

可以把任务建模为显式对象:

{
  "task_id": "refund-task-20260823-001",
  "subject_user": "user:customer-service-a",
  "actor_agent": "agent:after-sales-v12",
  "action": "refund_order",
  "resource": "order:20260823001",
  "constraints": {
    "max_amount": 300,
    "max_calls": 1,
    "expires_at": "2026-08-23T16:00:00+08:00"
  },
  "purpose": "物流超时补偿",
  "delegation_depth": 0
}

任务不是“临时退款专员”角色。

它是一份有来源、对象、动作、时间和预算边界的 Delegation Grant。

OpenFGA 当前的 Agent 授权指南给出了一种具体建模方式:Agent 默认没有权限,任务开始时才获得所需权限;任务可以绑定到具体工具资源,并增加有效期、最大调用次数、Session 范围和 Agent 绑定。任务结束后,删除相关关系元组以撤销权限。

这个实现证明任务可以成为授权关系中的一等对象。

不过,关系条件能表达“当前调用次数小于上限”,不代表授权系统会自动、原子地增加计数。高风险动作还需要 Action Service 或事务型计数器负责占用预算、避免并发穿透;任务结束后的关系清理也必须成为可靠的生命周期操作,不能只靠约定。

但要注意术语边界:

“任务级授权”是一种架构模式,并非所有产品都遵循同一个统一标准,也不意味着 OpenFGA 是唯一实现。

企业可以用关系授权、PDP、Capability Token、短期 Grant、工作流系统或业务 Action Service 实现同类约束。

四层模型不是四套互相打架的权限系统

很多团队听到 RBAC、ABAC、ReBAC 和任务授权,会担心再造四套权限真相。

如果四层都复制一份完整 ACL,担心是对的。

更合理的做法是分工:

RBAC
→ 管理长期、稳定、可审查的基础职责

ABAC
→ 评估主体、对象、动作和环境条件

ReBAC
→ 查询人与组织、项目、资源、Agent、任务之间的关系

Task Grant
→ 表达用户此次委托的对象、动作、时间、次数和预算

Source System
→ 执行最终记录权限、字段权限、状态机和业务规则

它们不是并列投票,而是逐层收窄。

最终允许
=
用户基础角色权限
∩ 用户与资源关系
∩ Agent 身份允许范围
∩ 当前任务委托
∩ 对象与环境条件
∩ Action 前置条件
∩ 源系统最终校验

任何一层拒绝,操作都不能继续。

一个采购场景

用户提出:

帮华东项目向供应商 A 提交 3 台测试服务器的采购申请,
总金额不超过 10 万元。

RBAC 判断

用户是否具有采购申请人角色?
Agent 是否允许进入采购数据域?

ReBAC 判断

用户是否是华东项目成员?
用户是否可以代表该项目申请采购?
供应商 A 是否属于该项目允许的供应商范围?
Agent 是否绑定到这次任务?

ABAC 判断

采购金额是否低于上限?
设备类别是否允许?
供应商状态是否有效?
当前是否处于预算冻结期?
操作环境风险是否可接受?

Task Grant 判断

只允许华东项目
只允许供应商 A
只允许 3 台测试服务器
累计金额不超过 10 万元
只允许创建草稿和提交审批
有效期 30 分钟
最多提交一次

源系统判断

预算余额是否仍然充足?
采购申请状态机是否允许提交?
必填字段是否完整?
供应商是否刚被停用?
是否命中业务系统的最终 Deny?

如果只使用 RBAC,“采购申请人”这个角色无法独立表达后面所有限制。

如果只使用 ABAC,又可能需要把项目、供应商和任务关系全部展平为动态属性。

如果只使用 ReBAC,金额、时间、库存和风险条件仍然需要其他策略。

组合才是答案。

PDP 应该怎样接收这些信息

一次授权请求可以包含:

{
  "subject": {
    "user_id": "user:zhangsan",
    "roles": ["purchase-requester"],
    "org_unit": "org:east-projects"
  },
  "actor": {
    "agent_id": "agent:procurement-assistant",
    "agent_version": "7.3.1",
    "risk_tier": "MEDIUM"
  },
  "task": {
    "task_id": "task:purchase-001",
    "purpose": "采购测试服务器",
    "max_amount": 100000,
    "max_calls": 1,
    "expires_at": "2026-08-23T16:30:00+08:00"
  },
  "action": "purchase_order.submit",
  "resource": {
    "project_id": "project:east-2026",
    "supplier_id": "supplier:a",
    "amount": 96000
  },
  "environment": {
    "current_time": "2026-08-23T16:10:00+08:00",
    "risk_score": 18,
    "step_up_completed": true
  }
}

PDP 可以查询:

  • IAM/IGA 提供的角色和身份状态;
  • 本体或关系授权系统提供的组织、项目和资源关系;
  • Delegation Service 提供的任务 Grant;
  • 风险引擎提供的环境属性;
  • 业务系统提供的当前对象状态。

决策输出不应只有一个裸 true:

{
  "decision": "ALLOW_WITH_OBLIGATIONS",
  "policy_version": "policy-2026-08-23.4",
  "obligations": {
    "max_calls_remaining": 1,
    "require_idempotency_key": true,
    "require_expected_version": true,
    "require_post_action_readback": true
  },
  "evidence": {
    "matched_role": "purchase-requester",
    "matched_relation": "member of project:east-2026",
    "delegation_grant": "task:purchase-001"
  }
}

Action Service 还要执行这些 Obligation,并把下游结果读回。

PDP 的 Allow 不能覆盖源系统的最终 Deny。

不要把组织本体当成权限计算器的唯一数据源

企业本体很适合表达:

Person
Position
Assignment
OrganizationUnit
Project
Responsibility
DataDomain
Agent
Task
BusinessAction

这些数据可以支持 ABAC 和 ReBAC。

但本体中的关系必须有来源、版本和生效时间。尤其不能把自然语言职责直接变成生产权限:

“负责华东销售”
≠
“允许读取华东全部客户明细”

职责可以产生角色候选、关系候选或策略属性,最终权限仍需经过显式政策、委托和源系统校验。

如果本体只是外部业务系统的投影,它更不能复制 ACL 后覆盖原系统 Deny。

权限缓存为什么会成为新风险

组合授权会查询角色、属性、关系和任务状态,性能压力随之增加。

最简单的优化是缓存,但权限缓存可能让已撤销权限继续生效。

Agent 又会高频、并发调用,这会放大缓存陈旧窗口。

需要分别定义:

角色缓存 TTL
关系缓存 TTL
任务 Grant TTL
高风险 Deny 缓存策略
离职和禁用事件的主动失效
PDP 故障时的降级规则

高风险写操作不能只依赖数小时前的组织快照。

离职、Agent 禁用、任务取消和高风险策略变更,应触发主动失效,而不是等待 TTL 自然过期。

子 Agent 不能自动继承父 Agent 的全部权限

多 Agent 系统经常出现这样的调用链:

主 Agent
→ 采购子 Agent
→ 合同审查子 Agent
→ 通知 Agent

如果子 Agent 自动继承父 Agent 的全部权限,委托链会不断扩大攻击面。

任务级授权应遵守不可扩权:

子任务权限
⊆ 父任务权限

OpenFGA 的任务授权指南给出两种模式:共享同一任务,或者创建权限更窄的新任务。

生产环境更稳妥的默认值是:

  • 子 Agent 默认无权限;
  • 创建显式子任务;
  • 仅分配必要动作和资源;
  • 限制委托深度;
  • 父任务撤销时级联撤销;
  • 审计保留完整委托链。

模型决定使用哪个子 Agent,不等于模型有权扩大发放权限。

常见反对意见

“RBAC 加几个条件就够了”

在关系简单、资源规模小、任务不需要细粒度委托的系统中,这完全可能成立。

文章主张的不是必须部署四个独立产品,而是不要遗漏四类语义。它们可以由一个策略引擎实现,也可以由现有 IAM、源系统和 Action Service 分担。

“ABAC 可以表达关系,所以不需要 ReBAC”

理论上可以。关系可以被编码成属性,ReBAC 也可以表达部分角色语义。

选择取决于数据形态和更新方式。如果授权核心是大量、多跳、频繁变化的主体—对象关系,关系模型通常更自然;如果主要是金额、密级、时间和环境条件,ABAC 更直接。

没有必要为了模型纯洁性,把所有问题压进同一种表示。

“任务授权会制造大量临时记录”

是的,所以任务权限必须短生命周期、可批量清理、可按任务索引,并与业务任务状态机绑定。

但不记录任务权限的代价,是让 Agent 在整个用户会话甚至长期服务账号权限范围内持续运行。对于高风险写操作,前者更容易治理。

“源系统已经做最终权限检查,中间层没必要再判断”

低风险、单系统、只读场景可能只需要源系统权限和薄 MCP。

但源系统通常不知道 Agent 版本、任务目的、最大调用次数、跨系统累计金额和用户本次委托范围。高风险 Agent 动作仍需在执行前收窄,源系统再做最终校验。

“任务来自自然语言,无法生成可靠权限”

这正是必须保留人工门和结构化确认的原因。

模型可以把用户意图转换为 Action Proposal,但不能自行批准新增权限。无法确定对象、金额或影响范围时,应请求确认或拒绝,而不是猜测一个更宽的 Grant。

按风险分层落地

不是所有 Agent 都需要完整组合。

低风险只读

RBAC + 源系统 ACL + 短期用户委托

适合读取用户本来可见的数据,且源系统每次都会再次校验。

项目型协作

RBAC + ReBAC + 源系统 ACL

适合文件共享、项目成员、工单继承和资源所有权场景。

条件复杂的业务动作

RBAC + ABAC + Action Predicate + 源系统状态机

适合金额、地域、密级、时间和风险条件明显的操作。

高风险 Agent 写操作

RBAC
+ ABAC
+ ReBAC
+ Task Grant
+ 审批/SoD
+ Action Service
+ 源系统最终 Deny

适合付款、退款、删除、合同审批、批量修改和跨系统副作用。

架构强度应随风险增加,不应让低风险场景的便利路径自动扩展到高风险写入。

建议的落地顺序

第一步:保留现有 RBAC

不要先推翻角色体系。先把它定义为用户和 Agent 的长期权限上限。

第二步:找出角色爆炸的来源

识别哪些角色只是为了表达区域、项目、金额、时间或临时代理。这些维度可能更适合属性或关系。

第三步:把 Agent 和任务变成显式主体

授权请求必须携带 Agent Identity、版本、任务 ID 和委托证据。

第四步:先覆盖高风险动作

为付款、退款、删除、批量修改等动作增加资源范围、TTL、次数、金额和审批约束。

第五步:统一决策证据

每次决策记录角色、属性、关系、Grant、策略版本和源系统结果,避免只留下 allowed=true。

第六步:测试负面路径

至少验证:

  • 用户调岗后旧角色失效;
  • 项目成员移除后关系失效;
  • 任务取消后 Agent 不能继续调用;
  • Grant 过期后旧会话不能复用;
  • 子 Agent 不能扩大权限;
  • 缓存陈旧时高风险动作拒绝;
  • 源系统 Deny 不会被 PDP Allow 覆盖。

结论

RBAC 在 Agent 时代仍然不可替代。

它适合管理长期职责、基础权限、角色层级和职责分离,也能继续作为用户权限的稳定上限。

但它通常只回答:

这类主体通常可以做什么?

Agent 生产执行还要回答:

主体与这个资源有什么关系?
当前对象和环境满足什么条件?
哪个 Agent 正在执行?
用户这次到底委托了什么?
允许执行几次,何时失效?
下游业务系统当前是否仍然允许?

因此,长期方案不是 RBAC 与 ABAC、ReBAC 之间选一个赢家,而是让它们承担各自擅长的部分:

RBAC 管长期职责
ABAC 管动态条件
ReBAC 管资源关系
Task Grant 管本次委托
源系统保留最终 Deny

RBAC 没有死亡。

只是当执行者从人变成可以规划、循环和委托子任务的 Agent 时,角色不再足以独自描述完整授权边界。


参考资料

  1. NIST:Role Based Access Control
  2. NIST SP 800-162:Guide to Attribute Based Access Control
  3. Google Research:Zanzibar, Google’s Consistent, Global Authorization System
  4. OpenFGA:Authorization Concepts
  5. OpenFGA:Modeling Task-Based Authorization for Agents
  6. OAuth 2.0 Token Exchange(RFC 8693)

发布摘要

RBAC 没有过时,但它主要解决“这类人通常能做什么”。当 Agent 代表用户自主规划、循环调用工具并委托子任务时,企业还要表达资源关系、运行时条件和本次任务边界。本文用一个采购案例拆解 RBAC、ABAC、ReBAC 与 Task Grant 的分工,并给出逐层收窄、源系统保留最终 Deny 的落地模型。

标签

AI Agent MCP RBAC ABAC ReBAC IAM OpenFGA 权限系统 企业架构 零信任