AI agents 正迅速进入生产系统,能够访问真实客户数据、内部工具链以及影响收入的工作流。一个支持自动化 Agent 可能会从 CRM 读取工单,总结对话历史,发放部分退款,创建内部升级工单,并在 Slack 发布状态更新,所有这些操作都在单个任务内完成。当这些 Agent 工作时,它们可以简化工作流并压缩例行操作的成本。当它们出错时,故障表现与传统自动化不同:具有非确定性、规模化,并且往往仍然掌握着完整的生产凭证。
要想发挥作用,Agent 需要足够的访问权限,以跨多种工具执行动态的多步骤工作流。但为了安全,它不能以具有永久、广泛权限的“超级用户”身份在这些工具上运行。大多数团队往往会沿用已知的访问模式,例如写入环境变量的长期有效 API 密钥或专为人类用户设计的 OAuth 流程,并很快发现这些模式根本不是为非确定性软件而设计的。配置错误的提示词、恶意的工具响应或一次简单的幻觉都可能演变成重大事件。
本指南将教你如何在自治系统中应用最小权限原则。你将学习如何根据能力而非资源来划分权限,发放与特定执行计划绑定的短期凭证,将身份、授权和执行分离到不同层,并为高风险操作引入人机回环审批。
访问模型不匹配
传统访问控制模型假设你是以下两类角色之一:
- 第一类是 人类用户:交互式,受会话限制,受 UI 约束,并且在单个工作流中通常具有可预测性。
- 第二类是 后端服务:具有确定性,工作流固定,可通过静态代码路径进行审计。AI Agent 既不属于此类也不属于前一类。
Agent 之设计即为非确定性。对同一数据使用相同提示词的两次运行可能会产生不同的工具调用序列。它们以开发者未显式编写的方式链式调用工具,并且可能通过两类 已文档化的威胁受到不可信输入的影响:
-
提示词注入:嵌入文档或网页中的指令会劫持 Agent 的行为。
-
工具输出中毒:工具响应会操纵链中的后续决策。
越来越多的 Agent 会生成子 Agent,因此从单个用户请求出发的委托链在完成之前可能会扩展到许多独立的上下文。
这些针对两类行为体构建的身份原语(会话令牌、服务账户以及 OAuth scopes)在孤立使用时并未损坏;在严格的范围限定、中介以及运行时强制下,它们可以工作良好。问题在于它们并非为非确定性、多步骤自主执行而设计,且它们的 典型的 使用模式——假设有界会话或确定性工作流——不再成立。会话令牌假设有界交互流。服务账户假设确定性行为。OAuth scope 如 billing:write 假设另一端的应用按用户意图解释它.. 当智能体在没有额外层的情况下继承这些机制时,它获得了权力,却缺乏使原始模型安全的对应问责结构。
常见反模式
在审视更好的模式之前,值得先看看团队通常会采取的捷径。每种方法在孤立使用时看起来都合理,但放在一起时可能会变得危险。
嵌入长期凭证
第一种常见的反模式是将长期有效的 API 密钥直接嵌入到智能体的配置或环境变量中。智能体持有根凭证,授予对工具的广泛访问权限;一旦智能体进程、日志或内存被泄露,该凭证就会暴露。虽然这在非智能体软件中也是问题,但对智能体而言风险更高——因为根据其配置方式,智能体更容易被诱导或胁迫去执行不应执行的操作,或泄露其可访问的凭证,而传统带长期凭证的软件被利用的难度要大得多。
即使通过 Vault 或 AWS Secrets Manager 等方式实现了轮换,真正的问题在于爆炸半径;轮换往往不一致或缓慢,而在被入侵与完成轮换之间的时间窗口足以让攻击者(或行为异常的智能体)造成严重损害。
完整继承用户 OAuth 权限范围
第二种反模式是让Agent完全继承用户的OAuth权限范围。用户把自己拥有的全部CRM权限授予Agent后,这些权限就永久归Agent所有,此后无论执行什么任务,Agent都能动用这些权限。用户本意只是有选择地行使某些权限,结果Agent全盘继承了。可Agent既不具备用户那样的判断力和情境感知能力,也不承担相应的责任,滥用这些过宽权限只是时间问题。
实际拥有超级用户权限的Agent
第三种反模式危害最大:Agent在调用所编排的工具时,拥有实际的超级用户权限,而且通常是系统级权限,而非用户级。这种情况往往是无意中造成的——开发者没有定义更窄的权限范围,而是直接选了权限最宽的那个。前面提到的客服Agent可能被赋予billing:write权限,只因这是账务类唯一的权限项。于是它可以退款任意金额、修改任何客户的支付方式、取消任何订阅,而它真正的职责其实只是在既定政策范围内处理小额补偿性退款。
想象一下:一个持有billing:write权限的客服运营Agent收到用户指令,“为订单#12345办理全额退款”,而订单金额高达一万美元。由于无法区分哪些退款金额是允许的、哪些不允许,Agent直接照办了。访问控制层没有任何机制能拦住它,损害在毫秒间造成,审计记录里只剩一条与任何正常退款毫无二致的退款流水。
基于能力的权限设计
解决Agent权限问题的第一步,是抛弃以资源为中心的权限思路,改用以能力为中心。像billing:write这样的权限范围只描述了资源类别和操作动词,而像billing.refund.issue_under_50_usd这样的能力则同时编码了具体的操作类型、资源上限和隐含的风险边界。当然,由于权限范围数量会随之爆炸式增长,实践中通常不会把能力校验直接编码进权限范围。
基于能力的权限以业务实际考量的方式表达授权。产品经理若决定支持智能体可发放最高 50 美元的礼遇退款,此决定应写入授权系统会评估的声明式策略。而不应将其散落在调用 API 的应用代码里的强制性检查中。无论这 50 美元的阈值是由授权引擎自身强制执行,还是由在发放令牌前咨询的专用策略层实现,都只是实现细节;关键在于该规则能够集中管理并可审计。
这就是细粒度授权系统发挥作用的地方,虽然它们能解决拼图中的特定一块,但并不总是一揽子解决方案。
OpenFGA, 由 Auth0 的 FGA 团队创建的开源授权引擎,现为云原生计算基金会(CNCF)项目,实现了 Relationship-Based Access Control(ReBAC)。ReBAC 在建模 谁能对什么进行操作 方面表现出色。支持智能体不仅仅是一个角色,而是一个与特定资源类型具有特定且有限关系的实体,这些关系会产生不同的权限。可以表达类似这样的规则:只有当订单所属的客户与智能体存在活跃工单时,智能体才能退款该订单。

纯 ReBAC 无法执行诸如“退款金额
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
}
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's Token Vault 在身份层实现了此模式。该保险库安全地存储了连接服务(Google、Slack、Salesforce、GitHub 等)的 OAuth tokens,而代理会请求一个仅在特定任务时使用的 access token,而不是自行处理长期凭证。Token Vault 实现了 OAuth 2.0 Token Exchange (RFC 8693),为其提供了基于标准的基础,而不是专有流程。根据所使用的流程,代理可能根本不会接触底层的 refresh token;在专为 SPA-plus-backend 架构设计的 access-token-exchange 流程中,refresh token 完全留在 Auth0 端。
本文提到的支持代理在决定发起退款时,并不已经持有具备退款能力的 token。运行时首先会根据策略层评估请求,提出诸如:金额是否在代理的自主阈值内、客户是否未被标记为欺诈审查、代理是否与该订单具有正确的关系等问题;只有在这些条件满足后,才会请求一个仅限于退款能力和特定客户的短期 access token。如果代理在任务之间被攻破,则不存在可被利用的永久退款权限;任何先前的 token 已经过期,重新签发一个新 token 需要再次通过策略检查。
身份、授权和执行是三个不同的层级
-
Identity 定义了代理是谁。它回答的问题是,“代表哪位用户的哪个代理正在发起此请求?” 身份相对稳定;代理通常在众多任务中保持一致的身份。
-
Authorization 决定已认证的行为体被允许做什么。它回答的问题是,“在这种情况下身份下,哪些能力适用?” 授权是一种策略决策,应为每次操作重新评估,而不应从长期授予中继承。
-
Execution enforcement 决定在特定运行时环境下实际上允许什么。它回答的问题是,“对于此特定调用,携带此特定有效载荷时,策略是否允许?” 这包括退款金额、目标资源以及只有在请求实际发出时才能知晓的任何上下文约束。
把这两者混为一谈会导致常见的失效模式。如果身份和授权被视为同一件事,那么权限会在认证时被固定,无法随执行的任务而调整。同样,如果授权与执行耦合,则策略无法进行集中管理、审计或更新。每一层都需要各自的边界,且每个边界应由不同的组件来强制执行。
Architectural Separation
在实际中,处理这三个问题意味着在任何生产级 Agent 系统中都需要设计三个独立的层次。
Identity provider layer
身份提供者层负责身份验证和令牌颁发。Auth0 负责验证用户,通过 Token Vault 管理已连接的账户,发放带作用域的令牌,并处理委托流程。身份提供者知道该 Agent 是谁以及它可用的能力有哪些,但不执行业务逻辑。
Runtime environment layer
运行时环境层负责解释 Agent 的计划,向身份提供者请求凭据,并在调用下游工具之前执行策略。这通常是你的 Agent 编排代码,常基于 LangChain、LlamaIndex 或 Vercel AI SDK 等框架构建。
在设计良好的系统中,运行时与 LLM 进程本身是分离的:LLM 生成工具调用,但运行时决定这些调用是否被允许,为它们请求凭据,并发出实际的 API 调用。许多实际的 Agent 系统做不到这一点,而是把 API 键直接传入工具包装器,或通过工具配置暴露令牌。将凭据隔离在 LLM 之外是值得刻意追求的设计目标,而非自带的属性。
Tool layer
工具层是下游系统,例如 CRM、计费服务或 Slack API,实际执行操作的地方。工具层负责自身的执行与日志记录,与 Agent 或运行时认为被允许的内容无关。这种防御机制确保即使运行时被攻破,工具仍会强制执行自身的授权规则。
当这种分离得到保持时,它带来一个关键的安全收益:LLM 进程本身永不持有凭据。运行时负责代理这些凭据,为每次 API 调用呈现它们,随后将其丢弃。试图说服 LLM 泄露“其凭据”的提示词注入攻击无从下手,因为 LLM 从未获得过任何凭据。

高风险操作的审批边界
即使具备能力范围和任务范围的凭证,某些操作仍需要额外的一步:在执行时进行明确的人工批准。这不是对损坏的权限模型的后备方案,而是一种有意的设计选择,适用于风险程度足以证明额外摩擦合理性的操作。
问题在于,哪些操作会越过这条线。支持智能体发放5美元退款大概不需要人工批准;自动化的价值在于无需干预地处理这些操作。而同一智能体若试图发放2,000美元退款、向被标记为欺诈审查的账户退款,或对客户记录执行任何破坏性操作,则完全是另一回事。这些操作更看重做对而非做快。
Auth0 使用 客户端发起的后通道认证(CIBA)标准 实现异步批准,这是 OpenID 基金会的一项规范,允许客户端(如智能体后端)从单独的受信设备带外请求用户批准。如今,大多数生产环境的智能体系统通过定制流程、内部策略引擎或类似 Temporal 的工作流系统来处理批准。CIBA 提供了一种基于标准的替代方案,它可以直接融入现有的 OAuth 基础设施,而无需构建并行的批准系统。当支持智能体检测到某项操作超出其自主阈值时,其后端会向 Auth0 发送 CIBA 请求。用户会通过 Auth0 Guardian 应用在其已注册的移动设备上收到推送通知(短信或电子邮件也作为支持渠道),而智能体会轮询等待响应。如果用户批准,智能体将获得一个仅限于该特定操作的令牌;如果用户拒绝或请求超时,则什么也不发生。

CIBA 与 Rich Authorization Requests (RAR) 结合后变得更强大。Rich Authorization Requests (RAR) 是 OAuth 2.0 的扩展,它让授权请求能够携带关于实际正在批准内容的详细、结构化上下文。与其看到泛泛的“批准访问账单?”提示,用户会看到具体的内容,例如“批准向客户 Jane Doe 退款 2,000 美元,订单号 #12345。”结构化的 authorization_details 有效载荷使得批准可验证且可审计,这是泛泛的授权范围所无法实现的。
此模式直接针对 10,000 美元退款场景。智能体的能力范围允许它在低阈值下自主进行退款。对于超过该阈值的情况,智能体必须触发 CIBA 流程才能继续,用户在批准前会看到确切的金额和目标。智能体无法绕过这一点,因为它执行退款所需的令牌仅在批准后才会被发放。
可观性和控制
最终层是可观性。在严格的权限控制下运作的智能体仍然在多个系统上自主运行,了解它做了什么、为什么以及代表谁进行操作对于调试、事件响应和合规性至关重要。
三个要素至关重要:
- 审计轨迹应捕获智能体的决策,而不仅仅是行为。仅知道已经发放了退款是不够的;您需要了解智能体正在执行哪个计划,哪些工具调用导致了这一步骤,以及哪些上下文影响了决策。
- 授权链应当明确,以便给定的 API 调用可通过 user → agent → sub-agent → tool → resource 追溯,每一跳都应被记录。
- 撤销必须快速且精确。如果智能体行为异常,您需要吊销其现有授权,使飞行中的令牌失效,并停止进一步的工具调用,而不必关闭整个系统。
Auth0 平台通过集中化令牌发放来提供此基础设施,这意味着发送给智能体的每个令牌都会经过单一控制平面。在 Token Vault 中撤销连接会立即使未来的令牌交易失效,审计日志将反映每一次令牌的发放和使用。
智能体的权限模型
AI 智能体需要为非确定性、自主工作流设计的访问控制模型。直接继承自人类用户或静态服务账号的权限并不适用。智能体会以用户和开发者都未预料到的方式使用这些权限,而现有的访问层也不会察觉。
构成生产就绪型智能体架构基础的三种模式是:
- 基于能力的权限,用于编码具体操作和限制,而非宽泛的资源动词
- 基于任务的凭证,生命周期短暂,绑定到特定执行计划,而非持久授权
- 分层执行,将身份、授权和执行分离为独立的组件
这些模式共同限制了智能体错误的影响范围,同时保留了使智能体变得有用的自主性。