← 返回信息流

dev.to #ai观点

为什么 AI 智能体需要独立的权限模型

dev.to作者:Cameron Pavey观点AI评分:70/100

文章主张 AI 智能体在接入生产环境时,必须建立专门的权限管理体系。作者指出智能体在处理客户数据、调用内部工具和执行影响收入的工作流(如退款、创建工单)时,若缺乏精细的权限控制,一旦失败将导致严重后果,因此传统的访问控制不足以应对智能体的自动化操作风险。

AI 代理正迅速进入生产系统,访问真实的客户数据、内部工具和影响收入的流程。一个支持自动化代理可能会在单个任务的时间跨度内,从 CRM 读取工单、总结对话历史、发放部分退款、创建内部升级工单,并发布状态更新到 Slack。当这些代理正常运行时,它们可以简化工作流程并压缩常规操作的成本。但当它们失败时,其失败方式与传统自动化不同:具有非确定性、规模性,且通常手握完整的生产环境凭据。

为了有用,代理需要足够的权限来跨多个工具执行动态的多步工作流。但为了安全,它不能以拥有永久且广泛权限的“超级用户”身份操作这些相同的工具。大多数团队倾向于默认使用他们已经熟悉的访问模式,例如嵌入在环境变量中的长期 API 密钥,或为人类用户设计的 OAuth 流程,并很快发现这些模式从未为非确定性软件构建。配置错误的提示词、恶意的工具响应或简单的幻觉都可能演变成重大事故。

本指南教你如何将最小权限原则应用于自主系统。你将学习如何根据能力而非资源来限定权限范围,颁发与特定执行计划挂钩的短期凭据,将身份、授权和执行分离为不同的层,并为高风险行动引入人工审批环节。

访问模型的不匹配

传统的访问控制模型假设你是以下两种角色之一:

  • 第一种是人类用户:交互式,受会话限制,受 UI 约束,通常在单一工作流中可预测。
  • 第二种是后端服务:确定性的,工作流固定,可通过静态代码路径进行审计。AI 代理都不属于这两类。

代理在设计上就是非确定性的。对相同数据运行相同的提示词两次,可能会产生不同的工具调用序列。它们以开发者未明确编写的方式链接工具调用,并且可能通过两个有据可查的威胁类别受到不可信输入的影响:

  • 提示注入:嵌入在文档或网页中的指令劫持代理的行为。
  • 工具输出投毒:工具响应操纵链中的后续决策。

越来越多地,代理还会生成子代理,因此始于单个用户请求的委托链在完成之前可能会扩展到许多独立的上下文中。

为这两种类型的角色构建的身份原语(会话令牌、服务账户和 OAuth 作用域)单独来看并没有损坏;在严格的作用域限定、中介和运行时执行的配合下,它们可以很好地工作。问题在于,它们并非为非确定性、多步自主执行而设计,其典型的使用模式(假设存在有界的会话或确定性的工作流)不再适用。会话令牌假设存在有界的交互流程。服务账户假设行为是确定性的。像 billing:write 这样的 OAuth 作用域假设另一端的应用程序会按用户的意图解释它。当代理继承其中任何一项而没有额外的保护层时,它就获得了权力,却缺乏使原始模型安全的相应问责结构。

常见的反模式

在回顾更好的模式之前,值得看看团队通常会采取的捷径。每一个单独看似乎都合理,但合在一起可能是危险的。

嵌入长期凭据

第一个常见的反模式是将长期有效的 API 密钥直接嵌入代理配置或环境变量中。代理持有授予对工具广泛访问权限的根凭据,一旦代理进程、日志或内存遭到破坏,该凭据就会暴露。虽然这在非代理软件中也是一个问题,但在代理场景下风险更高,因为根据配置方式的不同,代理比拥有长期凭据的传统软件更容易被欺骗或胁迫去执行不应执行的操作,或泄露其有权访问的凭据。

即使通过 Vault 或 AWS Secrets Manager 等机制实施了轮换策略,真正的问题在于爆炸半径;轮换往往不一致或缓慢,而在遭受到损害与实施轮换之间的时间窗口足以让攻击者(或行为不端的代理)造成重大损害。

完整的用户 OAuth 作用域继承

第二个反模式是完整的用户 OAuth 作用域继承。用户授予代理对其 CRM 系统的访问权限,使用的是用户自身拥有的权限,而代理现在永久拥有这些作用域,用于未来的每一次操作,无论其实际执行的任务是什么。代理继承了用户原本只打算选择性行使的权限。然而,代理不具备用户所拥有的判断力、上下文感知能力或问责机制,代理意外滥用这些过于宽泛的权限只是时间问题。

拥有有效超级用户特权的代理

第三个,也是最具破坏性的反模式,是代理在它们编排的工具上以有效的超级用户特权运行,通常是在系统级别而非单个用户级别。当你使用最宽松可用的作用域而不是定义更窄的作用域时,这种情况会隐式发生。前面提到的支持代理可能被赋予 billing:write 作用域,因为这是唯一可用的计费作用域,而现在它可以发起任意金额的退款、修改任何客户的支付方式以及取消任何订阅,尽管它的实际工作是在狭窄的政策范围内发起小额善意退款。

考虑一下当具有 billing:write 权限的支持运营代理被用户要求“处理订单 #12345 的全额退款”时会发生什么。订单总额为 10,000 美元。由于无法区分它被允许处理的退款金额和不被允许的退款金额,代理会径直执行操作。访问层没有任何内容能阻止它。损害在毫秒间完成,唯一的审计线索是一条看起来与任何合法记录完全相同的退款记录。

基于能力的权限

解决代理权限问题的第一步是停止从资源角度思考权限,转而开始从能力角度思考。billing:write 这样的作用域描述了一个资源类别和一个动词。而 billing.refund.issue_under_50_usd 这样的能力编码了特定的操作类型、资源限制和隐含的风险边界,尽管你通常不会将此类能力检查编码到这样的作用域中,因为这会导致作用域的不可避免爆炸。

基于能力的权限用业务实际推理的方式来表达授权。当产品经理决定支持代理应能够发起最高 50 美元的礼貌性退款时,这一决定应存在于授权系统评估的声明式策略中,而不是分散在调用 API 的应用程序代码中的命令式检查里。无论是 50 美元的阈值由授权引擎本身强制执行,还是通过代码内的检查(例如在令牌颁发之前咨询的专用策略层)来强制执行,这都是实现细节;重要的是规则是集中管理且可审计的。

这正是细粒度授权系统发挥作用的地方,虽然它们解决了拼图的一块特定部分,但它们并不总是全能的解决方案。

OpenFGA 是由 Auth0 的 FGA 团队创建、现已成为云原生计算基金会(CNCF)项目的开源授权引擎,它实现了基于关系的访问控制(ReBAC)。ReBAC 擅长建模“谁可以对什么采取行动”。支持代理不仅仅是一个角色,而是一个具有与特定资源类型相关的具体且有限关系的实体,这些关系会产生不同的权限。你可以表达诸如“仅当订单属于该代理拥有活跃工单的客户时,代理才能退款”之类的规则。

Diagram showing an authorization flow
Diagram showing an authorization flow

纯 ReBAC 无法执行的是像“退款金额低于 100 美元”这样的数值或基于属性的约束。OpenFGA 通过引入条件(Conditions)扩展了基础 ReBAC 模型,允许你将谓词附加到关系上,以便在授权检查中评估数值限制、有时效限制的授权以及上下文属性。

在上图中,OpenFGA 将两层合并为一次检查:关系及其条件被一起评估,任一条件均可拒绝访问。类似于“代理可以退款金额小于配置限额的订单”这种能力,可以通过 OpenFGA 中的条件直接表达,其中金额既可以作为元组的一部分提供,也可以在检查时以上下文形式提供。对于希望将纯授权策略与声明式策略代码保持分离的团队来说,在其上层使用 Cedar 或 OPA 等专用引擎是一种合法的替代方案,但这并非必需;OpenFGA 能够同时处理关系图和属性约束。

具体而言,在 OpenFGA 的 DSL 中,带有每个代理限额的支持代理退款能力如下所示:

model  
  schema 1.1

type user  
type agent  
type customer

type order  
  relations  
    define owner: [customer]  
    define can_refund: [agent with refund_within_limit]

condition refund_within_limit(refund_amount: int, agent_limit: int) {  
  refund_amount <= agent_limit  
}  

该能力通过写入携带代理配置限额作为持久化条件上下文的元组来授予。对于一个上限为 50 美元的支持代理:

await fgaClient.write({  
  writes: [  
    {  
      user: "agent:support_agent_01",  
      relation: "can_refund",  
      object: "order:12345",  
      condition: {  
        name: "refund_within_limit",  
        context: { agent_limit: 50 },  
      },  
    },  
  ],  
});  

在检查时,运行时提供条件上下文中请求特定的另一半(即正在尝试的实际退款金额):

const { allowed } = await fgaClient.check({  
  user: "agent:support_agent_01",  
  relation: "can_refund",  
  object: "order:12345",  
  context: { refund_amount: 75 },  
});  

在评估条件时,OpenFGA 会合并这两部分,如果键同时出现在两者中,则持久化的元组上下文优先于请求上下文。由于元组中存储的 agent_limit 为 50,而检查时提供的 refund_amount 为 75,条件 refund_amount <= agent_limit 的计算结果为 false,因此 allowed 返回 false;代理不能自主发出 75 美元的退款,运行时的下一步操作是触发人工审批流程(本文稍后介绍),而不是请求具备退款能力的令牌。

实际的经验教训是定义符合实际业务边界的能力。不是 billing:write,而是 billing.refund.issue_under_50_usd。不是 crm:read,而是 crm.contact.read_for_assigned_tickets。当你发现自己定义了一个感觉过于宽泛的能力时,花点时间考虑是否可以将其缩减为权限更少的内容,而不影响你正在构建的功能。

任务范围凭证

能力范围解决了代理能做什么的问题。任务范围解决了它能何时以及多久做这些问题。这是两个独立的问题,将它们混为一谈是一个常见的错误。

设计良好的智能体应尽可能最小化或消除持久性凭据。它不持有永久访问权限,而是针对每个操作的执行计划请求短期令牌。该令牌仅包含执行该计划所需的权限,有效期很短(以分钟计,而非天数),并在每次使用后丢弃。在实际应用中,某些系统仍会缓存短期令牌,或依赖作用域化的服务账户来处理基础设施相关事务。其目标并非追求纯粹性,而是尽量减少任何给定凭据有效的窗口期。

这种模式具有几个有用的特性:

  • 凭据泄露事件的影响窗口大幅缩小,因此从智能体内存中泄露的令牌仅在短时间内有效。
  • 被攻陷的智能体的破坏范围缩小,因为智能体只能使用其当前持有的短期令牌进行操作。
  • 智能体本身从不接触根凭据。一个单独的组件代表智能体代理令牌,因此即使智能体进程被攻陷,底层的 OAuth 刷新令牌或 API 密钥也不会暴露。

Auth0 的 Token Vault 在身份层实现了这一模式。Vault 安全地存储了已连接服务(如 Google、Slack、Salesforce、GitHub 等)的 OAuth 令牌,而智能体请求的是针对特定任务的即时访问令牌,而不是自己处理长期凭据。Token Vault 实现了 OAuth 2.0 令牌交换(RFC 8693),使其具备基于标准的坚实基础,而非专有流程。根据所使用的流程,智能体可能根本不会接触到底层的刷新令牌;在专为 SPA 加后端架构设计的访问令牌交换流程中,刷新令牌完全保留在 Auth0 端。

对于本文提及的支持智能体而言,这意味着当它决定发起退款时,它并不已经持有一个具备退款能力的令牌。运行时首先将请求与策略层进行评估,提出诸如:金额是否在智能体的自主阈值内?客户是否未被标记为欺诈审查对象?智能体与该订单是否有正确的关系?只有在确认无误后,才会请求一个限定于退款能力且针对该特定客户的短期访问令牌。如果智能体在任务之间被攻陷,则不存在可被利用的永久性退款权限;任何早期的令牌均已过期,而要发放新令牌必须再次通过策略检查。

身份、授权和执行是三个不同的层级

在设计智能体访问控制时,一个有用的澄清是认识到通常有三个不同的关注点被合并到了同一个实现中。

  • 身份确定智能体是谁。它回答的问题是:“哪个智能体,代表哪个用户,正在发出此请求?”身份相对稳定;智能体通常在许多任务中保持一致的身份。
  • 授权确定经过身份验证的行为者被允许做什么。它回答的问题是:“鉴于此身份,适用哪些权限?”授权是一项策略决策,应对每个操作重新评估,而不是继承自长期授予。
  • 执行强制确定在特定运行时上下文中实际允许做什么。它回答的问题是:“对于此次特定调用,带有此特定负载,策略是否允许?”这包括退款金额、目标资源以及直到请求实际发出时才知晓的任何上下文约束。

混淆这些会导致熟悉的故障模式。如果身份和授权是同一回事,那么权限在认证时就被冻结,无法适应正在执行的任务。同样,如果授权和执行耦合在一起,那么策略就无法进行集中管理、审计或更新。每个层级都需要有自己的边界,并且每个边界应由不同的组件来强制执行。

架构分离

在实践中,处理这三个问题意味着在任何生产级智能体系统中设计三个不同的层级。

身份提供商层

身份提供商层负责身份验证和令牌发放。Auth0 对用户进行身份验证,通过 Token Vault 管理关联账户,发放作用域受限的令牌,并处理委派流程。身份提供商知道智能体的身份及其可用的能力,但不执行业务逻辑。

运行时环境层

运行时环境层解析智能体计划,从身份提供商请求凭据,并在调用下游工具之前执行策略。这通常是你用于编排智能体的代码,通常构建在 LangChain、LlamaIndex 或 Vercel AI SDK 等框架之上。

在设计良好的系统中,运行时与 LLM 进程本身是分离的:LLM 生成工具调用,但运行时决定这些调用是否被允许,为其请求凭据,并执行实际的 API 调用。许多现实世界的智能体系统未能达到这一标准,将 API 密钥传递给工具包装器或通过工具配置暴露令牌。将凭据排除在 LLM 的访问范围之外是一个值得刻意追求的设计目标,而不是你免费获得的属性。

工具层

工具层是下游系统,例如 CRM、计费服务或 Slack API,它们实际执行操作。工具层负责其自身的执行和日志记录,独立于智能体或运行时认为被允许的任何内容。这种防御确保即使运行时被攻破,工具仍会强制执行其自身的授权规则。

当保持这种分离时,它具有一个关键的安全优势:LLM 进程本身从不持有凭据。运行时充当中介,为单个 API 调用展示凭据,然后将其丢弃。试图说服 LLM 泄露“其凭据”的提示注入攻击没有任何东西可以泄露,因为 LLM 从未被赋予任何凭据。

Diagram showing architecture of a ReBAC enabled authorization flow
Diagram showing architecture of a ReBAC enabled authorization flow

高风险操作的审批边界

即使使用基于能力和任务范围的凭据,某些操作仍需额外步骤:在执行时刻获得明确的人工批准。这不是权限模型失效时的后备方案。这是针对风险特征证明需要额外摩擦的操作而做出的有意设计选择。

问题是,哪些操作跨越了这条界线。支持代理发出 5 美元退款可能不需要人工批准;自动化的价值在于无需干预即可处理这些操作。同一代理尝试发出 2,000 美元退款、向标记为欺诈审查的账户退款或对客户记录执行任何破坏性操作则是完全不同的情况。在这些操作中,做对比做得快更重要。

Auth0 使用客户端发起的后通道认证(CIBA)标准实现异步审批,这是 OpenID Foundation 的一项规范,允许客户端(如智能体后端)从单独的受信任设备以带外方式请求用户批准。如今大多数生产级智能体系统通过定制流程、内部策略引擎或 Temporal 等工作流系统来处理审批。CIBA 提供了一种基于标准的替代方案,可嵌入现有的 OAuth 基础设施中,而不是要求建立平行的审批系统。当支持代理识别出某项操作超出其自主阈值时,其后端会向 Auth0 发送 CIBA 请求。用户会通过 Auth0 Guardian 应用在其已注册的移动设备上收到推送通知(短信或电子邮件也作为支持的渠道),智能体会轮询响应。如果用户批准,智能体会收到针对该特定操作的作用域受限的令牌。如果用户拒绝或请求超时,则不会发生任何操作。

Diagram showing authorization flow
Diagram showing authorization flow

当 CIBA 与富授权请求(RAR)结合使用时,其功能将更加强大。RAR 是 OAuth 2.0 的一项扩展,允许授权请求携带关于实际批准内容的详细、结构化上下文。用户看到的不再是通用的“批准访问账单?”提示,而是具体的内容,例如“批准为订单 #12345 向客户 Jane Doe 退款 2,000 美元”。结构化的 authorization_details 负载使得授权验证和审计成为可能,这是广泛范围的范围授予(broad scope grant)所无法做到的。

这种模式直接解决了 10,000 美元退款场景的问题。智能体的能力范围允许其在低阈值内自主执行退款操作。对于超过该阈值的任何操作,智能体必须触发 CIBA 流程才能继续,用户在批准前会看到确切的金额和目标对象。由于执行退款所需的令牌仅在获得批准后才会颁发,因此智能体无法绕过这一限制。

可观测性与控制

最后一层是可观测性。在严格权限控制下运行的智能体仍然在许多系统中自主运作,了解其行为、原因以及代表谁行事,对于调试、事件响应和合规性至关重要。

三个要素至关重要:

  • 审计轨迹应记录智能体的决策,而不仅仅是动作。仅仅知道已发出退款是不够的;你需要知道智能体正在执行哪个计划、哪些工具调用导致了这一结果,以及哪些上下文信息影响了决策。
  • 委托链应当明确,以便将特定的 API 调用追溯回用户 → 智能体 → 子智能体 → 工具 → 资源的路径,并记录每一步。
  • 撤销必须快速且精确。如果智能体行为不端,你需要撤销其现有授权、使进行中的令牌失效,并停止进一步的工具调用,而无需关闭整个系统。

Auth0 的平台通过集中化令牌颁发提供了这种基础设施,这意味着所有颁发给智能体的令牌都经过单一的控制平面。在 Token Vault 中撤销连接会立即使未来的令牌交换失效,并且审计日志会反映每一次颁发和使用。

面向智能体的权限模型

AI 智能体需要专为非确定性、自主工作流设计的访问控制模型。直接从人类用户或静态服务账户全盘继承的权限并不适用。智能体会以用户或开发者未曾预料的方式使用这些权限,而现有的访问层将无法察觉。

构成生产就绪型智能体架构基础的三种模式是:

  • 基于能力的权限,编码了具体的动作和限制,而非宽泛的资源动词
  • 基于任务的凭证,具有短期有效性,并与特定的执行计划相关联,而非持久性授权
  • 分层执行机制,将身份验证、授权和执行分离为独立的组件

通过这些模式的组合,可以在不剥夺使智能体变得有用的自主性的前提下,限制智能体错误造成的影响范围。

译文已达到本站中文翻译的字数上限,剩余内容请查看原文。

阅读原文