改进之处,以及它止步的地方
给 AI 代理一个随任务结束而失效的凭证,你就消除了访问管理中最古老的问题之一:长期有效的持有者令牌躺在配置文件里,数月内一直有效,在代理进程早已消失之后仍对攻击者有用。1Password 式的框架以及更广泛的面向代理的 IAM 提案都朝这个方向推进。凭证按任务铸造,绑定到会话,并在任务关闭时撤销。泄露令牌可被利用的窗口从数月缩短到数分钟。这是实实在在的收益。
但这一收益与大多数安全审查真正关心的问题正交:这个凭证在存活期间能触及什么?一个生命周期五分钟、却对 * 拥有 s3:GetObject 的任务范围令牌,仍然是一个通向整个存储桶的五分钟窗口。生命周期是窄的。范围不是。而范围并不是凭证签发系统自己决定的——它继承自更早的一个决策,由另一个组件、用另一套词汇做出。
范围是分解的产物
考虑编排器可能交给子代理的两条指令:
subtask: reconcile the account
subtask: read invoice 4417
第一条是合理且常见的请求。从访问控制的角度看,它也是对账单台账、支付提供商、客户记录以及任何对账逻辑所触及内容的读取权限请求。第二条是对单个文档的请求。两者都是“任务”。作为对意图的描述,两者都不比对方更正确。但它们产生的凭证广度天差地别,而签发系统——那个铸造短期令牌的系统——无从得知第一条是懒惰的分解,第二条是谨慎的分解。它看到的是一个任务标识符和一个请求的范围,如果范围与任务匹配,它就授予。
换句话说,规划器无论是否有人这样看待它,都在做访问控制。当它把“处理客户投诉”拆成“读取工单、读取订单、发起退款”时,它刚刚决定了集群需要哪些凭证。当它把同一个请求拆成“读取工单、读取订单、读取支付历史、读取物流记录、读取账户备注”时,它决定了一个更宽的范围。下游的 IAM 层只是形式;实质性的决策发生在上游,发生在一个大多数团队仍称之为编排的组件里。

这正是按任务发放凭证的模型没有解决的部分。它修复了生命周期问题,因为生命周期是签发者控制的属性。它没有修复范围问题,因为范围是分解的属性,而分解是由语言模型对用户请求进行推理产生的,不是由策略引擎对最小权限进行推理产生的。
可审计性要求什么
如果范围是分解的下游,那么审计访问就意味着审计分解。一份记录 agent-7 requested scope X, granted scope X 的令牌签发日志,对审查者来说无法说明 X 是否合理。它记录了形式上的步骤,却省略了实质性的步骤。
由此得出的设计规则并不复杂,尽管它比听起来更具侵入性。每个凭证请求都应携带两个标识符:它所属的子任务,以及产生该子任务的父计划节点。如果请求的范围超出所声明子任务可能需要的范围,授予就应被拒绝——这里的“可能”指的是分解必须满足的策略,而不是签发者临时做出的判断。授予一旦发出,就应与促成它的分解一起记录,以便审查者重建推理过程:这个令牌存在,是因为计划节点 P 派生了子任务 S,而 S 的范围限定为发票 4417,且该令牌可以读取发票 4417。
{
"plan_node": "P-118",
"subtask": "S-118-3",
"intent": "read invoice 4417",
"requested_scope": ["billing:invoices:read:4417"],
"granted_scope": ["billing:invoices:read:4417"],
"parent_scope_ceiling": ["billing:invoices:read:*"]
}
parent_scope_ceiling 字段是最重要的。它是计划节点允许分配给其子节点的最大范围,并且在计划创建时设定,而不是在请求凭证时设定。这给审查者两件要检查的事:子任务是否留在了父节点的上限之内,以及父节点的上限本身是否由原始请求所证明合理。第二项检查才能抓住那种悄悄认定“对账”意味着“读取一切”的规划器。
重试循环才是范围蔓延的地方
要警惕的失败模式不是恶意代理,而是乐于助人的代理。代理遇到权限错误——它试图读取发票 4417,范围是 billing:invoices:read:4417,但发票位于另一个系统,或者对账还需要支付记录——于是它重试。如果重试逻辑被允许扩大范围
重试时的范围蔓延应是一等事件信号,而不是一行日志。具体来说:请求的范围严格大于原始子任务范围的重试应失败关闭,发出事件,并要求由不是撞墙的那个代理的组件重新分解计划。重新分解才是修复。扩大的授予才是失败。如果系统无法区分两者,它最终会授予扩大的范围,因为那是对处于截止期限压力下的代理阻力最小的路径。
诚实的权衡
这一切都不是免费的。要求每个凭证请求携带子任务标识符和计划节点上限,意味着规划器必须输出结构化的分解,而不是自由文本的任务描述。这意味着编排层必须维护一个带范围注解的计划图,而该图必须被版本化并可审计。这意味着一些合理的任务会失败,因为分解太粗,代理无法在其范围内自我纠正——而对这种失败的正确回应是更慢、人类可见的重新规划,而不是更宽的令牌。
这就是权衡:更窄的范围,代价是分解出错时更多的摩擦。另一种选择——按任务发放凭证、采用任务级范围,其中“任务”是规划器碰巧写下的任何东西——给出的是最小权限的表象,以及规划器随心所欲的实质。任务范围的凭证是一种改进。它们不是范围问题的解决方案,因为范围问题不是凭证问题。它是分解问题,而且它位于上一层。
该构建什么
- 把规划器当作安全相关组件。它的输出就是访问控制决策。
- 要求每个凭证请求都带有子任务和父计划标识符。
- 强制执行在计划创建时而非凭证签发时设定的父范围上限。
- 将分解与授予一起记录,使理由可被重建。
- 对以更宽范围重试的情况失败关闭,并将失败路由到重新分解,而不是更宽的授予。
凭证的窄度只能与产生它的任务一样。如果任务以错误的粒度陈述,凭证也会如此。
封面照片:panumas nikhomkhai / Pexels。
