主题
安全与多租户隔离
一句话:安全不是入口的一道闸门,而是四层各自回答一个问题:谁能进来、能碰什么、能带走什么、出事能不能查;少一层,另外三层都会被绕过。
安全、沙箱与供应链的通用模型见 安全、沙箱与供应链,发布门禁见 安全评测与发布门禁;本篇只讲拼装时每个控制点落在哪个组件。
为什么需要
平台的安全问题很少来自“没做认证”,而是来自控制点放错了层:
- 网关做了认证,但工具调用时又信任了请求体里的
tenant,客户端一改就串租户; - 市场做了订阅审批,但注册中心里的端点没有鉴权,知道地址就能直接调;
- 工具做了参数校验,但沙箱默认能出网,模型被注入后把数据发到外部;
- 审计记录了“谁调用了”,但没记“用的是哪个版本、哪个工具、批准人是谁”,事后无法追责。
这些都不是单个组件能解决的。有效做法是纵深:每一层都假设上一层已经被绕过,各自保留一个独立的拒绝理由。
核心机制
一、威胁面与控制点
| 层 | 典型攻击 | 控制点 | 落在哪个组件 |
|---|---|---|---|
| 入口 | 伪造身份、重放、配额耗尽 | 验签、OIDC/JWT、消费者配额、WAF | Higress |
| 模型 | 提示注入、越权工具调用、数据外泄 | 工具策略、内容安全、上下文裁剪 | 内核 + 网关 |
| 工具 / MCP | 恶意 Server、参数注入、SSRF、路径穿越 | 白名单、Schema 校验、出网策略 | Toolkit + 网络策略 |
| 执行 | 沙箱逃逸、资源耗尽、横向移动 | 容器/VM、资源限额、网络隔离 | Sandbox + K8s |
| 数据 | 跨租户读写、快照泄漏、记忆污染 | 前缀 + 策略、加密、隔离作用域 | 存储 + 内核 |
| 供应链 | 依赖投毒、镜像替换、许可风险 | 版本锁定、SBOM、镜像签名 | 构建流水线 |
纵深的意思是:注入成功不等于能调工具,能调工具不等于能出网,能出网不等于能带走数据。任何一层都不应该假设“上一层的模型判断是对的”。
二、身份与权限:三层决策,三个执行点
| 层 | 回答的问题 | 执行点 | 粒度 |
|---|---|---|---|
| 平台访问 | 谁能改 Agent、用 Environment、挂 Vault | Service 命名空间角色 | 资源 + 动作 |
| 应用调用 | 哪个应用能 invoke / read / interact / cancel | 应用 API Key 的 scope | 应用 |
| 工具执行 | 这个 Agent 能不能执行这个工具 | enabled + permissionPolicy | 工具 |
工具策略有三档:always_allow、always_ask、deny。默认策略要按风险定:只读且带 readOnlyHint 的工具可以自动放行,写操作与外部调用默认询问,高风险工具(退款、删除、发消息)显式拒绝或强制审批。
三条硬规则:
- 租户与命名空间只能来自网关认证结果,不能由客户端自报;下游服务每次都要重新校验,不能假设网关注入过就永久可信;
- 调用权与审批权分离:应用凭据可以有
invoke,但不能因此获得审批权;审批必须来自有审批角色的主体; - 发现不等于授权:Nacos 里有端点、市场里有产品、Agent Card 可访问,都不代表当前主体能调用。
还要把三个方向分开判:入站回答“谁可以调用这个 Agent、发起什么任务”;出站回答“Agent 代表谁、能访问哪些外部资源”;委托回答“人员把哪些范围交给 Agent”。入站通过不代表出站自动通过,调用一个 Agent 也不获得它出站资源的权限。跨服务代表用户访问时,用 Token Exchange / On-Behalf-Of 换取短时、窄 scope 的令牌,不用长期服务令牌冒充用户。有效权限取人员、团队、Agent、资源、委托五者的交集,显式拒绝优先;Agent 间交接不扩大权限。
三、多租户隔离的四个面
| 隔离面 | 做法 | 强度 | 成本 | 适用 |
|---|---|---|---|---|
| 逻辑隔离 | 命名空间、行级过滤、Key 前缀 | 中 | 低 | 大多数 SaaS 多租户 |
| 执行隔离 | 每租户/会话独立 Sandbox,独立工作目录 | 中高 | 中 | 工具执行、代码运行 |
| 网络隔离 | 出站白名单、独立 VPC/端点 | 高 | 高 | 敏感数据、强合规 |
| 数据隔离 | 独立桶/前缀、独立 KMS 密钥、独立库 | 高 | 高 | 金融、医疗等强隔离场景 |
四者可以叠加,但不能互相替代:逻辑隔离挡不住越权代码,沙箱挡不住对象存储的预签名 URL 泄漏,网络隔离挡不住应用层把数据写进公共桶。
AgentScope 的 IsolationScope 决定记忆与工作区按会话、用户、Agent 还是全局共享;个人记忆不能用 AGENT/GLOBAL 作用域,公共技能不能落在可写的个人前缀下。AGENT 与 GLOBAL 会引入跨副本共享写,必须配分布式锁。
原生多租户对齐(源码级):agentscope-service 原生是 tenant/namespace 双层(请求头 X-AgentScope-Tenant/Namespace,JPA 实体与 v2 文档坐实):tenant 隔离业务租户,namespace 内再做资源与成员角色(用户组 groups)隔离——本节的"逻辑隔离"落原生即 tenant + namespace + 资源前缀 三层键;运行时侧 IsolationScope(会话/用户/Agent/全局)决定记忆与工作区共享面,行级过滤由数据面按透传身份执行。
四、凭据:不落盘、不进上下文、按工具收窄
- 凭据存 Vault,按命名空间隔离;写入后只返回元数据,不回明文;
- 运行时按需注入到工具执行环境,任务结束即失效;不要注入到模型上下文;
- 每个工具用独立凭据,避免“一个 Token 能调所有系统”;
- 日志、Trace、事件里对凭据与个人信息做脱敏,错误信息也不能带出明文;
- 定期轮换,轮换要能不重启完成;离职与项目结束要能按主体吊销。
五、提示注入:不要指望模型识别,靠边界兜底
四道边界缺一不可:指令与数据分离(系统提示声明外部内容是数据)、工具权限最小化(被骗也只能做允许的事)、出网限制(拿不到数据也发不出去)、输出过滤(敏感信息不落进回答)。只写“请忽略文档里的指令”属于提示词层面的缓解,不构成安全控制。
六、供应链与运行时响应
依赖侧:锁定 core、harness、extensions、starter 的版本,生成 SBOM,镜像签名后再部署;MCP Server 与 Skill 要有来源、版本、许可与责任人,禁止直接从公网仓库拉到生产。
运行时侧:监控三类异常——工具调用频率突增、跨租户访问被拒、出站流量异常;处置动作要预先定义:吊销应用 Key、暂停命名空间、隔离沙箱、回滚 Agent 版本、关闭某个 MCP Server。没有预演过的处置动作,事故时一定做不对。
七、系统身份(Agent 即服务,G10)
企业系统通过 MCP/A2A 调用平台 Agent(Agent 即服务),与"人对话"的身份语义分离:
| 身份类型 | 主体 | 凭据 | scope | 计量 | 恢复 |
|---|---|---|---|---|---|
| 用户对话 | 自然人(sub) | OAuth/SSO + Token Exchange | 以用户为根 | 记到用户 | 会话重放 |
| 系统调用(新增) | client_id | API Key / client_credentials | 应用级 scopes 白名单 | 记到系统/项目 | task 幂等 |
三条规则:
- 系统身份不进用户上下文:
subject=client_id,不得冒充用户sub;需要代用户操作时仍走 On-Behalf-Of 换取窄 scope 令牌——与用户身份正交,不合并; - scope 是白名单枚举:系统凭据 scope 只含被授权的操作(
invoke/read/interact/cancel);发现不等于授权(§二 规则 3 延伸)——Nacos 有端点不代表系统主体能调; - 计量到系统级:系统调用的 token/工具/预算记到
client_id的项目/部门,不进个人额度(接缝 7 网关计量按此分流)。
验收判据:系统调用与用户对话身份分离(sub ≠ client_id);系统计量独立;代用户操作走 OBO 窄 scope。
原生对齐(§6.5.6/6.5.7 复核):agentscope-service 原生已有 builder_user(user_id/username/password_hash/roles_csv,JPA 源码坐实)与 Application API key(v2 文档:scopes invoke/read/interact/cancel/webhooks:write,按 Agent/Team/Workflow 目标授权,调用权与审批权分离、凭据属于应用、maxConcurrent/tokenBudget 应用级治理)——本节的 client_id + scopes 白名单 + 计量到系统级直落原生模型:系统身份 = Application;scope 枚举与原生一致;计量 = Application tokenBudget。
八、企业 SSO 对接现状(2026-10-25 源码级核实)
"跟企业 SSO 打通"必须分三层回答——不是让所有组件都 SSO 化:
| 层 | 谁 | 现状(源码证据) | 打通方式 |
|---|---|---|---|
| 员工访问层(人) | 员工登录平台/使用 Agent | ✅ Higress 原生 oidc 插件(plugins/wasm-go/extensions/oidc):完整 OIDC 授权码流、issuer discovery、refresh token、logout endpoint、CSRF、cookie 会话;provider 可指企业 IdP(Keycloak/Entra ID/企业微信等) | 网关挂 OIDC 插件指到企业 IdP → 登录一次,sub 贯穿全平台 |
| 组件管理面(管理员) | Nacos console、RocketMQ dashboard | ◐ 各自内置登录,认证插件化可扩展:Nacos AuthPluginTypeResolver 按 nacos.core.auth.plugin.auth.type 装载自定义 AuthPlugin;RocketMQ 5.x auth 模块 AuthenticationProvider/AuthenticationStrategy(Stateful/Stateless) 可插拔 | 按需实现插件对接 SSO;通常不需要全员打通,管理面保留独立管理员 |
| 系统调用层(机器) | B 端系统调 Agent/组件 | ❌ 不应打通 SSO | 走 G10 client_id + scope 白名单(系统凭据,不冒充人) |
架构判断:SSO 是"人"这一层的统一认证,落点在网关(Higress OIDC → sub 透传);数据面 agentscope-runtime 无内置认证层(源码未见 SecurityConfig/Filter),天然依赖网关前置认证,身份经请求头透传,这反而是好事——统一认证点只有一个(控制面 agentscope-service 的自有登录是另一层,见 §九 两段论);组件管理面与系统调用走各自凭据,不与员工 SSO 混。目标不是"全组件 SSO 化",而是"一个认证点 + 身份贯穿 + 机器凭据分离"。
九、身份转换适配层:入口转换,用户无感
SSO 打通只是认证统一;真正支撑"操作过程用户穿透"的是入口后的身份转换适配层——用户只登录一次,内部各层拿到自己需要的身份形式,全部在入口组件转换,用户无感知:
| 场景 | 用户侧看到 | 内部身份形式 | 转换机制 | 用户感知 |
|---|---|---|---|---|
| 用户操作(对话/工具) | 登录一次 | sub + OBO 窄 scope 令牌 / Vault 凭据注入 | 网关 OIDC 认证 → 代用户换下游令牌(Token Exchange / OBO,§二)→ 凭据注入工具执行(§四) | 无感 |
| 控制面 agentscope-service | 管理/调度(托管 Agent、Workspace、Workflow、Vault、Team) | 自有登录体系:POST /api/auth/login → Bearer token + X-AgentScope-Tenant/Namespace + inspect/edit/publish 权限(源码 + 文档坐实);应用接入另发 API key(scopes: invoke/read/interact/cancel/webhooks:write,按 Agent/Team/Workflow 目标授权) | 企业 SSO 对接 = Higress sub → 映射 agentscope 平台用户 token;应用 key 走 G10 client_id 语义(调用权与审批权分离,key 不能替用户审批) | 无感 |
| 数据面 agentscope-runtime | Agent 执行引擎 | 无内置认证,身份经协议 metadata.userId 透传(GraphAgentExecutor 源码坐实);缺省返回 "default_user"(ResponseApiHandler.getUserId() 源码坐实)——入口不注入,所有用户就混成一个 | 控制面代表用户把 sub 注入 userId 进执行上下文;入口组件必须清洗/注入,不得依赖客户端自报 | 无感 |
| 数据系统(画像/记忆/轨迹) | 读写数据 | 当前 ctx.user 是 stub(user_id="default")——平台需做实 | 身份适配层把 sub 映射写入 ctx.user;数据按用户隔离 | 无感(待做实) |
| 后置服务(定时汇总 / 画像蒸馏 / 数据飞轮) | 用户不在线 | 系统身份 client_id(§七 G10) | 事件触发 → 平台以系统身份执行,凭据独立于用户 | 无感 |
| 基础设施(Nacos 注册/配置、RocketMQ 消息、对象存储) | 用户从不接触 | 平台内置服务身份(client_id + 基础设施凭据,按组件隔离存 Vault) | 平台以预置服务账户调用这些组件——不是用户登录它们,是平台代表自己 | 无感 |
| 跨端/跨系统协作 | 一次登录多端 | A2A 消息携带身份声明 | 网关 → 协议层身份透传 | 无感 |
| 管理面 | 管理员独立 | 管理员凭据 | 不与员工 SSO 混 | — |
三条纪律:
- 转换只在入口组件发生一次(Higress 后置适配层),下游不重复认证用户,只校验透传身份——统一认证点不扩散;
- 转换产物是短时、可撤销的窄 scope 令牌(OBO),不长期持有用户身份;
- 用户无感 ≠ 无审计:每次转换落审计(谁 → 以什么身份 → 访问什么),转换链可回放。
身份三态不混:用户身份(sub,SSO 认证的人)/ 委托身份(OBO,平台代用户访问下游业务系统)/ 内置服务身份(client_id + 基础设施凭据,平台代表自己访问 Nacos/RocketMQ/对象存储等内部组件)。Nacos、RocketMQ 对用户是透明的——用户登录一次,平台以内置身份完成注册、配置、消息投递,用户自始至终不接触这些组件的登录;内置身份按组件隔离存 Vault、全量审计(哪个服务以内置身份调了什么)。
执行端与数据端必须显式接身份:控制面 agentscope-service 自带登录(/api/auth/login → Bearer token + X-AgentScope-Tenant/Namespace,权限 inspect/edit/publish;Application API key 带 scopes 且调用权与审批权分离——源码与 v2 文档坐实),它与企业 SSO 的对接 = Higress sub 映射平台用户 token;数据面 agentscope-runtime 无内置认证,身份贯穿靠协议 metadata.userId(GraphAgentExecutor 源码坐实:message.getMetadata().get("userId"))——控制面代表用户注入 sub 进执行上下文;数据面组件的 ctx.user 当前是 stub(user_id="default",集成方案自述)——待做实接缝(Q1:host 真实 user 态接驳 ctx.user),平台身份适配层必须把 sub 映射写入,否则画像/记忆/轨迹数据侧无法按用户隔离。
安全关键点(源码级):数据面 ResponseApiHandler.getUserId() 读请求 metadata.userId,缺省返回 "default_user"(182–185 行)、getSessionId() 缺省 "default_session"——userId 是客户端自报字段,可伪造:若入口组件(Higress 身份转换适配层)不强制清洗/注入 sub,则①所有未带 userId 的请求混成一个 default_user(跨用户会话串扰),②恶意客户端可自报他人 userId 冒充(越权访问他人会话/记忆)。因此身份转换适配层对数据面的职责是写入而非透传:把已认证的 sub 映射为 userId 注入,丢弃客户端自报值;这也是"转换只在入口发生一次"落在数据面的具体含义。
验收判据:用户登录一次,任务全链路可追溯同一 sub;后置服务以系统身份执行不打扰用户;所有身份转换可审计回放。
九.1 SSO 对接方案(2026-10-25 源码实测定稿)
agentscope 认证机制(源码坐实):POST /api/auth/login(bootstrap 密码)→ JWT HS256(Claims:accountVersion/username/roles/sub/jti,TTL 7d,secret=BUILDER_JWT_SECRET);中间件 VerifyAccountToken 除签名外查 users 表 + 校验 claims.accountVersion == users.auth_version + account_login_sessions 会话表——用户必须预存在、JWT 必须带匹配 auth_version(实测:手工签发合法 JWT 但用户不存在 → 401/404)。无 K8s 时 authzMiddleware 静态 token 模式放行;X-AgentScope-Tenant/Namespace 由 header 注入(namespace 成员角色校验见九.2)。
方案对比:
| 方案 | 做法 | 改动面 | 隔离性 | 复杂度 |
|---|---|---|---|---|
| A+ 平台内置身份+DB 预置用户(先做,实测通过) | 入口组件认证企业 SSO(OIDC)→ 企业用户身份记录在接入层;手动/自动往 cp.users 插入企业用户(auth_version=0)→ 入口用 BUILDER_JWT_SECRET 签发 JWT(accountVersion=DB auth_version + jti)→ per-user 身份贯穿 agentscope | 0 改源码 | per-user:每个企业用户有个人 namespace(自动创建) | ★ 最简 |
| B SSO 认证插件(改源码) | login handler 增加企业 SSO 校验分支(调企业 SSO API / OIDC)→ 自动 upsert users + 同步 auth_version → 正常 issueAccountToken;组织映射企业部门/团队 → namespace/teams | 改 control 认证层,维护补丁 | per-user | ★★ |
| C 组织原生(改源码+扩模型) | B + 企业组织导入(启动/定时同步 users+teams+成员) + teams 成员 API 完善 | 改认证层+组织模型 | per-user + 组织原生 | ★★★ |
先执行 A+(0 改源码,串通优先,2026-10-25 运行时全通):
- 用户预置:
INSERT INTO cp.users(user_id,username,password_hash,roles_csv,display_name,disabled,version,auth_version,legacy_sessions_closed,created_at) VALUES('user-xxx','xxx','unused','user','Name',false,1,0,false,extract(epoch from now())::bigint)(created_at是 bigint;password_hash可不真实——入口签发 JWT 不走密码)。 - JWT 签发规则(
_sso_issue.ps1已固化):HS256,Claims={accountVersion:0(=DB auth_version), username, roles, sub:user_id, jti:uuid, iat, exp},key=BUILDER_JWT_SECRET;accountVersion必须等于 DBauth_version、jti必填,否则 401。 - 运行时验证(全套 ✅):插入
user-sso-alice→ 签发 JWT →/api/v1/me/namespaces200,个人 namespacepersonal-1f6a60e5a0e4fe48e17f自动就绪(owner=自己);alice 访问 admin 的 agent → 404 "resource not found in authorized scope"(per-user 隔离生效);对照:手工 JWT 但用户不存在 → 401(坐实"用户须预存在")。 - 多用户落地后:per-user 会话/记忆/资源天然隔离;企业组织→namespace 的映射(部门/团队共享 namespace)待 P2/P5 或切 B/C 时扩展;仅替换入口 JWT 来源,链路不变。
方案 A 身份转换链路(mermaid 版):
方案 A+ 多用户身份转换链路(mermaid 版,2026-10-25 实测):
九.2 智能体开放管控模型(2026-10-25 运行时坐实)
创建的智能体开放给谁用——官方原生有管控:
- 资源归属 = owner(user 或 namespace):personal namespace → 归个人;共享/团队 namespace → durable namespace owner(与创建者解耦,product_access.go L36-38)。
- 访问控制 = namespace 成员角色:
member / developer / operator(对应 inspect / edit / publish 权限面);非成员访问资源 → 404 "resource not found in authorized scope"(隐藏存在性,防探测)。 - publish 为独立动作(product_access.go L118):发布/共享需 publish 权限,不随普通读写授权。
- API key 按 Agent/Team/Workflow 目标授权:应用接入另发 key,scopes=invoke/read/interact/cancel/webhooks:write;调用权与审批权分离(key 不能替用户审批)。
运行时验证:admin(owner)→ 自己的 namespace 读 agent 200 ✅;改用非成员 namespace(fake)→ 404 BLOCKED ✅(_acl.txt)。
接入层增强位:官方无"跨 namespace 广场/visibility"概念(除 marketplace)——"开放给谁用"的企业级发布(白名单部门/团队、审批流、市场可见性)由接入接入层(HiMarket)实现,agentscope 侧以 namespace 成员 + publish 权限承接。这对应 47 清单"发现不等于授权:网关与工具策略仍会独立拒绝"。
九.3 数据面身份注入修复方案(C1 · 2026-10-26 定稿)
缺口定位:控制面 VerifyAccountToken 已从 JWT sub 提取 userId 并通过 per-user namespace 隔离(§九.1 方案 A+ 已实证)。但控制面 dispatch 到数据面时,metadata.userId 未从 JWT sub 注入——数据面 ResponseApiHandler.getUserId() 缺省返回 "default_user",导致所有用户共享同一画像/记忆/轨迹。此为生产阻塞项,修复前禁止画像/记忆/轨迹功能上线。
注入点分析:数据面读 metadata.userId 的来源是 A2A 协议消息体(message.getMetadata().get("userId")),不是 HTTP header。因此修复必须在构造 A2A 消息的环节注入,而非在 HTTP 网关层。
按部署形态分两条路径:
路径 1:agentscope-service 控制面 → agentscope-runtime 数据面
控制面在 dispatch 到数据面时构造 A2A 消息。修复点 = 控制面 dispatch 逻辑在构造 AgentRequest / A2A Message 时,将当前请求的 JWT sub 写入 metadata.userId。
text
修复前: dispatch → A2A message.metadata = {} → 数据面 getUserId() = "default_user"
修复后: dispatch → A2A message.metadata = {userId: <JWT sub>} → 数据面 getUserId() = <真实用户>实施选项:
- 选项 A(推荐):补丁控制面 dispatch 方法,从
SecurityContext取userId注入 metadata。改动量 ≈ 1 个方法,需 fork agentscope-service - 选项 B:在控制面与数据面之间加 sidecar,拦截 A2A 消息并注入 metadata.userId。零 fork,但增加一跳延迟
路径 2:渠道聚合器/网关 → 数字分身实例
渠道聚合器向 数字分身实例投递 POST /api/console/chat 时,body 中已包含 channel/user_id/session_id。修复点 = 渠道聚合器从企业 SSO JWT 提取 sub,映射为 数字分身实例的 user_id 写入请求 body。
text
修复前: 聚合器 → body = {user_id: null, ...} → 实例 getUserId() = "default_user"
修复后: 聚合器 → body = {user_id: <SSO sub 映射>, ...} → 实例 getUserId() = <真实用户>此路径的 sub → user_id 映射规则:
- 企业 SSO
sub(如alice@corp)→ 平台内部userId(如user-sso-alice) - 映射表存 PostgreSQL
cp.users(方案 A+ 已预置,§九.1) - 渠道聚合器查映射表或缓存,miss 时自动预置(与方案 A+ 的 auto-provision 逻辑一致)
验收用例
| # | 场景 | 预期 |
|---|---|---|
| V1 | 用户 A 与用户 B 分别发起 chat | 数据面 getUserId() 返回各自 userId,不出现 default_user |
| V2 | 用户 A 的画像/记忆写入 | 数据按 userId 隔离,用户 B 不可见 |
| V3 | 请求不带 JWT 或 JWT 无 sub | 网关 401 拒绝,不到数据面 |
| V4 | 恶意请求伪造 metadata.userId = "admin" | 接入层覆盖为 JWT sub 映射值,伪造值被丢弃 |
| V5 | 渠道聚合器投递到 数字分身实例 | body 中 user_id = SSO sub 映射值,非 null |
上线门禁
- V1–V5 全部通过前,画像/记忆/轨迹功能不得启用
- 修复上线后,扫描已有
default_user数据,评估是否需要迁移或清理 - 监控指标:
data_plane_user_id_default_total(出现即告警)
最小上手
先只做“三层拒绝 + 一条审计”:
text
1. 网关开启认证与消费者配额,拒绝无凭据与超配额请求;
2. 应用 Key 只给 invoke + read,不给管理权限;
3. 工具分三组:只读自动放行、写操作询问、高危拒绝;
4. 沙箱默认断网,按任务开白名单;
5. 每个拒绝都记录:主体、动作、对象、原因、trace_id;
6. 用一条伪造 tenant 的请求验证:网关拒绝、运行时也拒绝。验收判据:改请求头不能换租户;越权工具调用被策略拦住;沙箱内的进程访问不到内网;审计能还原“谁在什么时候被哪条策略拒绝”。
生产动作
- 默认拒绝:新工具、新 MCP、新渠道默认不可用,按需开通,而不是默认全开再收窄。
- 策略即代码:工具策略、出网白名单、命名空间角色进版本库,变更走评审与灰度。
- 最小权限凭据:一工具一凭据、短有效期、可吊销;禁止共享长期 Token。
- 数据分级:按敏感级别决定能否进模型上下文、能否跨租户检索、保留多久。
- 红队常态化:把注入、越权、SSRF、路径穿越做成固定用例,随版本回归。
- 事故演练:每季度演练一次“吊销 Key + 隔离沙箱 + 回滚版本”的完整链路。
边界
- 沙箱不是安全边界的一切:容器共享内核仍有逃逸风险;强隔离要 VM 或独立节点。
- 提示词不是安全控制:模型可以被说服,权限与网络策略不能。
- 逻辑隔离不是物理隔离:共用数据库与集群时,运维误操作仍可能跨租户;强合规要独立实例。
- 审计不是日志:日志可采样、可删除;审计要求完整、不可改、可追责。
- 开源组件默认值不是安全默认值:预览版 External 注册可能不校验身份,Helm 默认单副本也不是高可用;上线前逐项核对。
讲清楚
安全要按层拼:入口验身份与配额,模型层做内容安全与上下文裁剪,工具层做白名单与参数校验,执行层做沙箱与出网限制,数据层做前缀、加密与作用域,供应链做版本与签名。每层都假设上一层已被绕过。
权限分三层:平台访问、应用调用、工具执行;租户只能来自网关认证结果,调用权与审批权必须分离,发现不等于授权。凭据进 Vault、按工具收窄、短时注入、全程脱敏。
判断隔离是否成立,看四条:改请求头换不了租户、越权工具被拦、沙箱访问不到内网、审计能还原每一次拒绝。
适用:Higress / AgentScope Java 2.x / AgentScope Service 2.1.0-BETA1 | 初稿 2026-10