跳至正文

机器翻译。英文版本为权威来源,母语审校尚未完成。

Least privilege

最小权限漂移:在事故发生前发现权限过高的 AI 代理

作者 Olivares AI 4 分钟阅读

最小权限是安全领域最古老、最可靠的理念之一。给一个身份恰好它所需要的访问权限,不多不少,那么任何一次失陷的影响范围都会被控制得很小。对于人类账户和长期存在的服务账户而言,这套模型运作得相当不错:角色会被审查,授权会被限定范围,访问认证会按季度周期进行。

AI 代理悄然打破了这套模型。一个代理被授予一份凭据、一个工具、一条 MCP 服务器连接,从那一刻起,它的行为就是动态的。它在运行时自行决定读取哪些资源、写入哪些资源、接下来调用哪个工具。您在第一天写下的授权描述的是一个上限,而非代理实际所做之事。而且由于代理高效能产,这个上限往往设得很宽松:宽泛的数据库角色、“以防万一”的写入权限、一个被半打工作流共享的服务账户。其结果就是这样一个环境——被允许的访问与实际使用的访问每天都在悄然漂移、渐行渐远。

独立的行业研究揭示了这一盲区的规模:约 82% 的组织报告称存在自己并不知情的、正在运行的 AI 代理(CSA/Token Security,n=418)。您无法对一个看不见的环境强制执行最小权限。

定义最小权限漂移

最小权限漂移,就是代理“被允许的访问”与“被观测到使用的访问”之间不断扩大的差距。 它有两个失效方向,而其中只有一个是显而易见的。

显而易见的方向是权限未充分使用:一个代理持有对某张表的写入权限,却从未向其写入过任何内容。这是死权限,是您承担了却毫无收益的风险。而危险的方向,是它所暗示的反向信号:当观测集合中出现了某个授予集合从未刻意授予的内容时,就意味着有一个无人审查过的操作正在发生。一个导出任务突然向一个它一向只读取的存储桶写入数据;一个被策略限定在某一个 schema 内的代理却横跨到了另一个 schema。这些都不是什么稀奇之事;它们正是用粗粒度授权拼接起来的代理们的日常面貌。

之所以这件事很难,之所以它是代理特有而非人类特有的问题,是因为这种行为是被生成的,而非被配置的。一个权限过高的人类,大多数情况下并不会去行使那些权限。而一个权限过高的代理,则会行使任何有助于它完成眼前任务的能力,包括无人预料到的路径。静态的策略审查跟不上每次运行都在变化的行为。

把漂移转化为可审查的信号

漂移只有在不可见时才是危险的。要做的工作就是把它变成一个人类可以审查的信号,而这需要两件事协同运作:对代理实际触及内容的持续观测,以及对它们曾被允许触及内容的稳定记录。

观测必须是读取优先的。一个从日志、OpenTelemetry 追踪和 eBPF 内核信号进行观测的采集器,处在代理数据路径之外。它不是代理,它不拦截调用,而且即便它发生故障,也是在安全意义上“失效即放行”——代理照常工作,您失去的是可见性而非可用性。这种不对称性至关重要:一个会拖垮生产环境的安全控件,正是会被团队悄悄禁用的那种控件。其中 eBPF 这一层尤其充当了内核级的事实基准,是代理无法绕开的部分(内核层面的捕获来自您自行部署的 Tetragon 传感器;Olivares AI 读取 Tetragon 的导出数据,自身不加载 eBPF 程序),这也正是为什么诸如 MCP 工具注解(readOnlyHint、destructiveHint)这类协议层提示要拿来与它互证,而非直接信任。MCP 规范本身就声明这些注解是不可信的;内核信号才是让互证成真的东西。

观测产出的,是一张访问地图:对于每个代理,它触及了哪些资源,以及它是读取(R)还是读/写(RW)。这张地图存储的是访问关系,而非载荷、密钥或 PII。有意思的部分在于差异比对:

代理资源已授予已观测漂移
data-export-jobprod-postgresRR无
data-export-jobs3://billing-exportsRRW未经审查的写入
report-builderanalytics-dbR(未使用)死权限

真正要紧的是中间那一行。策略授予的是对导出存储桶的读取权限;采集器却观测到了一次写入。这一行就是最小权限漂移本应揭示的首要风险:一项无人审查过却被行使的权限,而且它被归因到一个具体的代理,而非一个共享的服务账户——因为正是按代理粒度的身份,才让这种归因和审计在根本上成为可能。

在访问时强制执行,而不只是记录

检测告诉您漂移发生了。要把闭环合上,您希望那次未经审查的写入成为一条被拒绝的路径,而不是一条被记录的路径。这正是在访问时评估的策略发挥作用之处。

Olivares AI 把 Cedar 作为叠加在默认拒绝角色之上的 forbid 覆盖层来评估,因此规则只能收回访问权限;下面这条规则会拒绝任何触及机密凭据的请求,无论角色怎么说。

permit(principal, action, resource);

forbid(principal, action, resource)
  when { resource.kind == "credential" && resource.sensitivity == "secret" };

编写自己的 Cedar 规则需要 Business;Community 则执行内置角色、原生拒绝覆盖层以及 kill switch;自定义角色和限定范围的授权属于 Business。

让我们具体地走一遍前后对比。

之前。 编码代理持有一个宽泛的角色,调用一个会写入 s3://billing-exports 的 MCP 工具。没有任何东西能阻止它。操作成功了,融入了正常流量之中,然后在数天之后(如果还能被注意到的话)才作为访问地图中的一个异常浮现出来。被允许与被观测之间的差距扩大了,而唯一留下的痕迹是一行无人阅读的日志。

之后。 同一次工具调用抵达 MCP 关卡。该代理的角色不允许这次写入,因此关卡在调用执行之前就将其拒绝(deny-closed),并把这次拒绝记入带签名、可发现篡改的审计日志。这次未经审查的写入,永远不会变成一次未经审查的变更。Olivares AI 只在四个强制执行点上阻断操作:Claude Code 内部、模型代理、每一次 MCP 工具调用,以及代理之间。绕开这些节点、直接写入 S3 的作业不会被阻断:访问地图会记录这次写入,并将其标记为待审查的漂移。

有两个属性让这一切保持诚实。其一,对访问地图的每一次特权查看本身都会被审计——谁查看了什么——因为这张地图很敏感,而一个无法对自己的操作者负责的安全工具是不可信的。其二,置信度被明白地展示出来:来源携带每个代理独立身份的边会被标记为 attributed,仅由内核观测到的边则标记为 approximate,因为内核信号指向的是进程、cgroup 或容器,而不是代理。您永远不会被要求基于一个被捏造的确定性去采取行动。

要点总结

最小权限并没有在 AI 代理上失灵;失灵的是审查周期。授权是粗粒度的,行为是动态的,而按季度进行的认证无法追踪一个每次运行都在变化的访问面。解决之道不是在关键路径上塞进一个更重的代理。它是持续的、读取优先的观测——产出一份“授予 vs 观测”的差异比对,再加上 policy-as-code 在访问时强制执行那条被修正过的边界,从而让一个权限过高的代理早在酿成事故之前,就作为一个可审查的信号被捕获。

如果您想了解采集器、访问地图与访问时强制执行是如何在不横亘于您代理数据路径的前提下协同运作的,架构页面会逐步讲解这套设计,而产品页面则展示了“授予 vs 观测”视图在一个真实环境上的样子。

相关文章

常见问题

什么是 AI 代理的最小权限漂移?

它指的是代理“被允许执行的操作”与“被观测到实际执行的操作”之间不断扩大的差距。粗粒度的授权加上动态的行为,意味着代理可能在任何人察觉之前,就开始访问无人批准的资源。漂移就是这种差距悄然累积的过程,而只有持续地将授予集合与观测集合进行比对,它才是可审查的。

如何在不破坏生产环境的前提下发现权限过高的代理?

采用观测而非拦截的方式。读取优先的采集器从日志、OpenTelemetry 和 eBPF 内核信号中读取数据,而不是横亘在代理的数据路径上,因此采集器故障绝不会阻断代理。这些观测数据驱动“授予 vs 观测”的差异比对。强制执行则发生在四个强制执行点(Claude Code 内部、模型代理、每一次 MCP 工具调用,以及代理之间):经由关卡的未经审查的写入会被拒绝并记入审计日志;绕开这些节点的直接写入则被标记为漂移。

查看您的智能体能触及哪些资源

Olivares AI 是面向您 AI 资产体系的开放式自托管平台。将其部署在您自己的基础设施上,即可获得安全与平台团队一直期待的访问关系图。