AI Agent 安全控制
从权限边界到上线验收
员工让 Agent 查询本团队的指标和项目进展,再整理成报告。这个团队数据分析助手需要调用数据工具,并使用模型整理查询结果。可读数据、工具动作、工作文件保存范围和报告接收方各有边界,安全评估要用实际执行证据确认授权、隔离和停止控制是否有效。
模型之外,仍须限定执行后果
Agent 可能误解任务,也可能被邮件、网页或工具返回中的内容诱导。它偏离预期后,能读取哪些数据、调用哪些工具、对业务系统做哪些操作,取决于系统实际授予的权限。因此,身份校验、权限控制、执行隔离和停止机制,需要在模型之外独立生效。
这套控制围绕三个问题展开:
| 评估问题 | 需要回答的内容 |
|---|---|
| 能力上限 | Agent 通过工具、命令、网络和凭证实际能够到达哪些动作 |
| 逐次授权 | 当前请求由谁发起,针对什么资源、动作和参数,是否获得批准 |
| 发现与遏制 | 系统留下了哪些可对账证据,异常发生后可以停止哪些对象 |
能力上限描述最坏情况下的可达范围。逐次授权在这个范围内判断某一次请求是否应该执行。发现与遏制则处理已经发起或正在运行的动作,包括定位发起者、停止后续请求,以及检查仍然有效的凭证和下游任务。三者不能互相替代:能力收得很窄,不代表每次调用都经过正确授权;授权规则写得完整,也不代表失控会话能够及时停止。
评估从企业批准的用途开始。明确 Agent 被允许完成的业务动作之后,工具、数据、身份和停止机制才有各自需要限制的范围。
明确团队分析助手的业务边界
以团队数据分析助手作为评估场景,批准用途是查询本团队指标和项目进展、整理报告。工作文件可保存在获准的当前会话范围内。平台用 session 记录一次会话及其执行环境。这些许可不包含跨团队读取、修改业务数据或向未批准的外部地址发送数据。
同一查询工具,应允许本团队成员访问,拒绝跨团队身份调用。员工提出“整理报告”的要求,不能扩大工具权限。报告使用哪些数据、交给谁,也须处于批准范围。这些是上线验收条件,须用允许与拒绝的调用记录证明。
能力清单要覆盖所有可执行路径,包括 MCP 这一统一工具调用接口,以及 shell 命令、HTTP 网络请求、SQL 数据库语句和直连凭证。团队报表与项目查询可以通过 MCP 调用。假如删除了写入工具,却保留数据库写凭证,Agent 仍可能通过其他路径写入或删除数据。
只读用途也有数据和出站边界。查询本团队数据,不代表可以读取其他团队数据,或把查询结果发往未批准地址。业务数据只读与保存工作文件是不同权限;获准保存报告文件,不等于获准修改业务系统。
必要控制未通过,就应缩小用途后重新验收,或暂停上线。其他能力表现良好,不能抵消授权、隔离或停止控制的缺口。用途边界最终要落实到每次调用的授权判定。
一次工具调用中的身份、授权与凭证
一次工具调用经过多个系统时,身份、授权和凭证很容易混在一起。身份回答“请求代表谁”,授权回答“这个主体能否执行当前动作”,凭证则是系统向下一跳证明身份或调用资格时携带的材料。一个身份来源可以真实可信,但当前动作仍可能没有获得批准。
允许一次团队查询,要同时确认员工身份可信、所属团队匹配、目标团队数据接口可访问,以及查询动作获准。团队归属来自经校验的企业身份,不能相信模型在参数里自报的团队。模型可以组织请求,却不能制造授权事实。授权决策点应结合真实身份、可信的资源状态和请求参数,判定这次调用是否允许。
同一个用户身份,经过不同的服务
开源参考平台 sample-agent-platform-with-agentcore 提供团队查询示例,包含报表和项目查询工具,返回预设的模拟业务数据。三个团队数据接口分别为 team-a、team-b 和 team-c。示例对接企业统一登录(SSO),由身份提供方(IdP)认证员工并签发身份令牌,使用 Keycloak 提供身份服务。
用户登录后,IdP 签发带签名的身份令牌 JWT。入口按配置校验签名、签发方、接收方和有效期。audience 表示令牌预期由哪个服务接收,sub表示主体标识,team则是这个示例 IdP 签发的团队属性。平台使用 Amazon Bedrock AgentCore Runtime 托管 Agent 代码,并通过 AgentCore Gateway 接入企业工具。这条链路中的 Gateway 位于 Agent 与工具后端之间。
调用链从 IdP 签发令牌开始。以 JWT 鉴权方式暴露的 Runtime 验证入站身份,Runtime 调用 Gateway 时继续携带同一个用户令牌,Gateway 也按入口配置完成验证。Gateway 调用 team-a 或 team-b 后端时,再通过令牌交换(token exchange)取得面向目标后端的新令牌。该示例的新令牌保留 sub 和 team;其他实现需要根据自己的身份提供方和目标服务配置这些属性。
后端自行授权
网关拦截器授权
后端是否理解用户身份,决定授权放在哪里
team-a 和 team-b 构成第一个授权分支。后端通过 OIDC 身份验证中间件检查来自 IdP 的令牌。后端随后依据 team 判断调用者是否可以访问当前团队数据,跨团队请求在后端被拒绝。这里的调用凭证既能被目标服务验证,也带有后端执行授权所需的用户属性。参考实现的企业 SSO 说明和 server.py 展示了这一分支。
team-c 构成第二个分支。这个后端不支持企业 SSO,只接受 API key。API key 能够证明调用方持有服务凭证,但本身不包含最终用户所属团队。因而,Gateway 在调用后端之前运行由 Lambda 函数实现的请求拦截器(REQUEST interceptor)。它读取已经由 Gateway 验证的 team 属性,先判断当前工具调用是否越权;拒绝时请求不会到达后端,允许时再由 Gateway 注入 API key。deploy_team_gateway.py 定义了这一机制。
两个分支的共同点,是授权判断发生在模型之外。前一个分支由能够理解用户身份的工具后端执行,后一个分支由后端之前的网关拦截器执行。这些决策可以复用可信后端、网关拦截器或现有审批系统,前提是 Agent 不能修改规则,也不能绕过入口直连受保护目标。
策略执行与拒绝证据
AWS AgentCore Policy 提供了另一种可选实现。LOG_ONLY模式只记录策略评估结果,不会阻断请求;ENFORCE模式才会执行允许或拒绝决定。该模式通过 Gateway 级别的 policyEngineConfiguration 配置。规则可以对 Agent 公开;保障控制有效的条件包括限制策略修改权限、验证输入来源,以及关闭绕过受控入口的路径。官方 Policy 执行模式说明了两种模式的差别。参考平台在上述示例中采用 Lambda interceptor,与 AgentCore Policy 是不同实现。
验证授权链时,证据要从真实决策点开始。Gateway 或后端的拒绝记录应包含可关联的主体、目标、动作和判定,再与下游实际执行记录对账。如果 Gateway 已经拒绝请求,后端没有收到它,就不应要求后端生成一条并不存在的调用日志。相反,允许请求应能在授权记录和后端执行记录之间建立对应关系。验收还需要覆盖直连负例,证明 Agent 不能绕过 Gateway 直接访问工具后端。
执行环境、数据与模型密钥各有边界
如果应用需要保存查询材料和报告草稿,当前会话与工作文件也要有明确边界。计算环境是否隔离、用户是否正确绑定 session、文件权限是否限于获准范围,应分别验证。执行环境隔离,不能代替用户绑定和文件授权的检查。
Amazon Bedrock AgentCore Runtime 托管 Agent 代码,以微型虚拟机 microVM 为每个会话提供独立内核、内存和文件系统。参考平台的 Dev Workbench 是云端开发工作台,其工作文件(workspace)保存在对象存储 Amazon S3 中,权限按 session 前缀限制。团队查询与工作台是不同示例,分别展示工具授权和执行、存储控制;实际应用仍须落实自己的完整调用链。
会话 A
仅会话 A 前缀的 STS 凭证会话 B
仅会话 B 前缀的 STS 凭证workspaces/* 访问权。S3 权限由额外签发的会话凭证限定。计算隔离、会话归属与数据权限分开验证
AWS Runtime 安全文档明确把会话到用户的绑定责任交给平台后端。后端需要决定哪个用户能够连接哪个 Agent 会话(session)。即使两个会话分别运行在隔离的 microVM 中,如果平台把甲用户连接到了乙用户的 session,计算隔离也无法修复这个绑定错误。参考平台的云端开发环境 Dev Workbench 因此在服务端保存按用户分区的 session 记录,相关接口先验证当前用户是否拥有目标 session,再执行连接或管理操作。
数据权限是另一层。环境内代码调用 AWS 服务时,使用 IAM 执行角色所授予的权限。这项工作负载身份与员工登录身份分开管理。AWS 官方同时说明,运行环境内的代码能够读取执行角色凭证。把会话放进 microVM,并不会自动让共享执行角色识别当前用户或 session。如果整个 workspace 存储桶都由同一个 Runtime 角色读写,那么不同会话即使有计算隔离,仍可能通过这项共享身份访问彼此的数据。官方 Runtime 安全边界对此给出了会话隔离和后端绑定要求。
让 workspace 凭证只覆盖当前会话
参考平台把交互式执行角色与 workspace 对象权限分开。交互式执行角色本身没有 workspaces/* 的访问权。后端先从当前 session 记录中取得 runtimeSessionId,再请求 AWS 临时凭证服务 STS 签发 workspace 访问角色的临时凭证。签发时附加的会话策略(session policy),会进一步收窄这份凭证的权限。
这条 session policy 把对象读写范围限制为:
workspaces/{runtimeSessionId}/*
对存储桶执行 ListBucket 时,前缀条件也限定在同一 session 目录。容器获得临时凭证后,这些凭证仍应被视为容器内代码可以读取和使用的材料;安全边界来自它只能访问自己的前缀,而不是假设凭证不可见。workspace_credentials_service.py 与 iam.tf 展示了临时凭证的签发和权限限制。session policy 只能收窄该角色原本拥有的权限,不能自动修复平台取错 runtimeSessionId、错误绑定用户或把凭证发给错误 session 的问题。
采用托管 Runtime 或保留已有运行环境,取决于工作负载和现有平台能力。产品名称不能替代验收:批准用途所需的计算隔离、用户绑定、数据权限和出站控制,都需要分别提供证据。托管服务承担的计算隔离,也不会自动完成平台后端的用户绑定和业务数据授权。
模型客户端 → 本地代理
容器内可接触的材料,均按用户可读取的内容处理。
短期会话凭证llm-edge
读取后端授权记录,验证凭证、模型与路由。
在此注入真实网关密钥LLM 网关
处理获准的模型请求。
平台模型密钥留在 Agent 容器之外
团队分析助手调用模型整理内容时,模型访问凭证也有自己的边界。Dev Workbench 提供真实终端,其中运行的程序能读取环境变量、文件、内存和角色凭证。没有终端的 Agent,其工具代码仍可能读取凭证。因此,模型凭证的保护不能仅以是否开放终端来判断。
参考平台使用 llm-edge 将持有平台密钥的转发环节移出 Agent 容器。该中转服务由平台自身实现。模型客户端先连接容器内的本地代理(loopback shim),由它把请求转发给下一跳。请求随后进入私有网络 VPC 中的 llm-edge,再由它访问 LLM 网关。真实的模型网关密钥由 llm-edge 的角色读取,不直接放入 Agent 容器。
容器仍然持有短期 session 凭证。这套设计隔离的是平台模型网关密钥,其他会话凭证仍须按可被读取的材料限权;“仅保存在内存中”也不能保证拥有相应读取能力的进程无法接触凭证。
llm-edge 处理每次请求时,都会读取后端保存的会话授权记录(grant)。记录包含用户、模型白名单、上游路由和有效期等信息,与用于访问下游的 OAuth 令牌不同。服务核验 token 摘要和 grant 有效期,然后从记录中取得允许的上游与模型列表。请求体中指定的模型不在白名单时,请求被拒绝;容器自行报告的上游地址或密钥名称也不能决定真实路由。模型访问路径只允许:
POST /v1/messages
POST /v1/messages/count_tokens
GET /v1/models
私网、加密与其他模型访问路径
私网可以限制哪些地址可达,不能代替服务端授权,也不自动提供传输加密。参考实现中的 llm-edge 默认使用内网 HTTP,并支持配置证书启用 TLS。是否启用 TLS 传输加密,需要与网络可达范围、调用授权分别核验。
如果平台还允许 Agent 直接调用模型服务 Amazon Bedrock,就存在另一条模型访问路径。llm-edge 的模型白名单只约束经过该服务的请求,无法约束绕过它的直接调用。验收能力清单时,LLM 网关、Bedrock 直连权限以及其他可达端点都要按实际路径分别检查,不能用其中一条链路的控制结论覆盖其他路径。
停止会话之后,还要核验残余访问
分析助手出现异常时,执行记录要能回答:谁发起查询,经过哪个 session 和工具,在哪个点获准,数据服务实际返回了什么。平台日志记录会话和调用过程,授权记录说明允许或拒绝的依据,工具后端记录实际执行情况。Agent 对自身行为的描述不能替代完整执行证据。
团队分析助手的停止首先覆盖新请求、运行会话和已发凭证。用途若扩展到提交业务任务,还要单独核验已提交的下游任务。
| 对象 | 停止时要执行的操作 | 需要留下的证明 |
|---|---|---|
| 新请求 | 阻止新的查询和工具调用 | 再次请求被拒绝的记录 |
| 运行会话 | 停止指定运行会话及流式响应 | 会话终止和响应停止的记录 |
| 已发凭证 | 撤销或禁用;无法即时失效时实施补偿阻断 | 凭证重放结果与访问被阻断的证据 |
| 已提交业务任务(若有) | 若已提交,查询或取消下游任务 | 下游任务状态,以及查询或取消结果 |
一次停止不能代表全部凭证失效。OAuth 令牌、S3 临时凭证和模型 grant 要分别处置,是否存在这些凭证,以实际应用配置为准。作为扩展例子,研发 Agent 若已创建代码变更请求(PR),并触发 CI 系统自动构建和测试代码变更,停止 Agent 不会取消该任务,还须在 CI 中查询或取消。已经发生的不可逆业务操作,不能承诺回滚。
AWS 的 StopRuntimeSession 接口 可以停止指定运行会话及其流式响应。OAuth 授权和 S3 临时凭证须另行处置;如果应用已经提交下游任务,也须在对应系统中查询或取消。运行会话停止的证据,只覆盖该会话的停止结果。
平台停止接口的实际行为
平台停止接口的实现可以说明这几种状态的区别。在 sessions.py 中,POST /{session_id}/stop 会把平台记录中的会话状态标记为休眠(dormant),并调用 llm_credentials_service.revoke 删除对应模型网关 grant。该路由没有调用 StopRuntimeSession;代码注释描述的是等待 Runtime 空闲回收。
llm_credentials_service.py 中的 revoke 捕获 grant 删除异常后只记录 warning。因此,停止路由返回成功不能单独证明 grant 已经删除。平台状态变成 dormant、模型 grant 删除成功、Runtime session 实际终止,是三个需要分别取得证据的事实。
S3 临时凭证不会因为模型 grant 删除而自动失效,下游 OAuth 令牌也有自己的生命周期。停止验收需要逐项识别仍可能有效的访问材料,通过对应服务撤销或禁用;对于无法即时失效的凭证,需要采取经过验证的补偿阻断措施,不能只等待到期。允许的处置时限由业务风险确定,实际耗时通过演练测量。HTTP 成功响应或平台状态更新,只能证明相应步骤的结果,不能代表全部停止完成。
从查询请求到残余凭证,逐项演练停止操作
团队分析用例的停止演练,可以从触发停止开始,再次发起查询,核对运行会话是否终止,然后重放或核验实际签发的残余凭证。随后对齐平台、授权和后端日志,记录各项处置耗时及未完成事项。用途若还会提交下游任务,应单独核对和处置。演练最终要明确每类对象的责任人、失效时间,以及停止后仍存在的访问能力。
用证据决定上线与扩围
上线判断需要三份相互对应的证据。第一份是实际能力清单,包含工具名称之外的 shell、HTTP、SQL、直连凭证、数据范围和出站路径。第二份是允许与拒绝对照,使用真实身份、资源状态和请求参数,在授权决策与下游执行记录之间建立对应关系,并覆盖旁路负例。第三份是停止记录,逐项记录新请求、运行会话、已发凭证和下游任务的状态、耗时、残余访问与责任人。
必要控制与运营增强需要分开。批准用途所需的执行隔离、独立授权和可用停止流程,应在上线前具备证据。自动处置和规模化治理可以后续增强,但不能替代准入底线。基线未通过时,处置结果是缩小用途后重新验收,或暂停上线。
云服务提供 Runtime、Gateway、IAM、STS 和停止 API 等机制。企业仍需定义业务边界,并把已有 SSO、审批、权限和日志系统接入调用链。已有控制可以继续复用,平台负责把它们连接起来,并验证完整调用链。
参考仓库可以提供对照代码和测试用例,但源码中存在实现、仓库中存在测试文件、真实部署验证通过,是三种不同事实。e2e_session_isolation.py 使用 moto 模拟 AWS API,并以替身 Runtime 检查应用层 session 绑定,不能证明真实 microVM 的隔离结果。e2e_team_auth.py 定义了跨团队调用和直连负例等验收用例,但运行结果仍需单独保存。上线前仍需在实际部署中运行这些用例,保存对应的调用、拒绝和停止记录。
边界由业务定义,实现机制可以复用,是否能够上线则由实际执行证据回答。