主题
账号、租户与命名空间
一句话:平台的身份不是一个登录账号,而是“人、应用、Agent 实例”三类主体在“企业—租户—用户—工作区—会话”五级作用域上的投影;投影没对齐,配额、隔离和审计就会各说各话。
机制层面的多租户原则见 企业平台与推理部署,平台侧的责任划分见 定义态、运行态与支撑服务;本篇只讲开源组件怎么承载身份与作用域。
拼装位置:上游是渠道与网关的认证结果 → 本篇把外部身份翻译成平台四元组 → 下游是 Service 命名空间、Vault 与所有存储前缀;交界字段
tenant / namespace / subject / session。
为什么需要
组件各自都有一套“账号”:网关有消费者和 API Key,市场有开发者账号和应用,运行时命名空间有租户请求头,Vault 有凭据路径,消息队列有 Topic。它们默认互不认识。拼在一起后最常见的四个问题:
- 计费串租户:网关按 Key 计量,但 Key 是某个开发者个人申请的,账单无法落到业务租户。
- 隔离靠自觉:检索和缓存没有带租户维度,A 租户的文档被 B 租户的会话召回。
- 权限两套:市场里审批通过的“可调用”,运行时却没人校验;或者反过来,运行时放行但市场里根本没订阅。
- 离职即孤儿:人走了,个人 Key、个人工作区、个人 Agent 还在跑,没人知道该停哪一个。
根因是把“认证”(你是谁)、“授权”(你能做什么)、“归属”(资源算谁的)混成一个账号字段。三者必须分开建模。
核心机制
一、五级作用域:每一级只回答一个问题
| 作用域 | 回答的问题 | 典型资源 | 谁管理 |
|---|---|---|---|
| 企业 Enterprise | 平台允许什么 | 模型目录、市场目录、安全基线、保留期 | 平台运营 |
| 租户 Tenant | 这个业务单元能用什么、花多少 | 命名空间、配额、Vault、知识库、Agent 目录 | 租户管理员 |
| 用户 User | 这个人是谁、能看什么 | SSO 身份、角色、个人工作区、个人凭据 | 企业目录 |
| 工作区 Workspace | 这类任务怎么做 | 指令、技能、工具白名单、子 Agent 定义 | 项目负责人 |
| 会话 / 任务 Session | 这一次执行到哪 | 事件日志、上下文、产物、任务通道 | 运行时 |
上一级只能收紧下一级,不能替下一级做决定:企业可以规定“所有租户禁止外网工具”,租户不能放开;租户可以给项目配额,项目不能向企业透支。反过来,下级可以比上级更严格,这叫“只增不减”的继承规则。
二、三类主体:人、应用、Agent 实例
| 主体 | 标识 | 用来做什么 | 常见错误 |
|---|---|---|---|
| 人 Subject | OIDC sub | 登录、审批、审计归属 | 用 API Key 代替人,离职无法回收 |
| 应用 Client | client_id + 凭据 | 代表一个系统调用平台 | 把应用凭据当成人凭据,权限过大 |
| Agent 实例 | agent_id + instance_id | 归属某次运行、绑定版本与租户 | 只记录 Agent 名称,重名后无法定位 |
一次请求至少要带四个标识:tenant、namespace、subject、session。AgentScope Service 用 X-AgentScope-Tenant 与 X-AgentScope-Namespace 两个请求头确定资源与权限范围;网关负责把外部身份翻译成内部标识,运行时不再相信客户端自报的租户。
三、请求的身份链
这条链的关键是每次跳转都重新校验,而不是透传信任:网关验完签名,不代表 Dataplane 可以忽略命名空间;Dataplane 拿到凭据,不代表工具可以跨租户读取。每一跳都问“这个主体在这个作用域下有没有这个权限”,而不是“上游说它有”。
四、统一在入口,不统一在组件
这套生态里没有一张“所有组件共用的用户表”,也不应该有。统一的是规范主体 ID 和签名身份信封,不是每个组件的账号库。 入口负责认证、规范化与签发,下游只做验签、授权和投影。
| 组件 | 它原生认识的“身份” | 平台怎么投影 | 不要做什么 |
|---|---|---|---|
| 企业 IdP | (issuer, sub) | 映射成内部 subject_id(UUID),email 只展示 | 用 email 或用户名当主键 |
| Higress | 消费者(Key/JWT)、路由 | 认证人,剥离客户端身份头,注入签名信封;消费者只代表应用 | 把消费者当成用户 |
| HiMarket | 开发者账号、应用 | 发布者用开发者账号;订阅绑定 client_id + tenant;终端用户只在运行时校验 | 把市场登录态当运行时授权 |
| Nacos | 用户名/Token、命名空间 | 运行时用只读服务账号;用户永不登录 Nacos;租户靠命名空间与前缀 | 给终端用户发 Nacos 凭据 |
| AgentScope Service | X-AgentScope-Tenant / Namespace、会话 user_id | 网关签名后透传;Service 只做范围校验,不认证人 | 把请求头当认证结果 |
| AgentScope Java | RuntimeContext 的 userId/sessionId/agentId | 由 Dataplane 从信封构造,模型与工具不可写 | 让模型或工具决定 userId |
| Vault | Role、路径、策略 | 路径按 tenant/subject/tool,按会话签发短时令牌 | 一个服务账号读所有路径 |
| RocketMQ | Topic、ACL | Topic 按 tenant/session,信封里带 subject 与幂等键 | 用消息内容当授权依据 |
| 对象存储 | Bucket/前缀、服务角色 | 前缀 tenant/subject/...,用户侧只走下载网关 | 把预签名 URL 直接发给用户 |
| 沙箱 | 容器/命名空间 | 执行绑定 session,数据绑定 user,凭据按会话注入 | 热池镜像里预置用户凭据 |
| OTel / 审计 | 属性、事件 | 统一带 tenant/subject/session/agent_version,审计另加 actor | 把高基数 ID 放进指标标签 |
信封至少包含这些字段,缺一不签:
text
sub 规范主体 UUID
tenant 租户
namespace 资源与授权范围
client_id 调用方应用
agent_id 运行时的 Agent(如有)
session_id 本次执行
scopes 授权范围
ts / nonce 时效与防重放
sig HMAC 或 mTLS 之上的签名四条硬规则:
- 入口剥离:客户端带来的
X-User-Id、X-Tenant、X-AgentScope-*一律删除,只保留网关注入的版本; - 每跳验签:下游校验签名、时间窗与 nonce,再校验资源 owner 与 tenant 是否匹配,不接受“上游说它有”;
- 身份不转嫁:用户令牌不直接转发给模型与 MCP;要么做令牌交换(
sub+act),要么用服务身份加on_behalf_of,模型永远看不到用户凭据; - 生命周期单点:IdP 的入职、转岗、离职事件只改平台主体状态,再由它级联吊销会话、Key、ticket、定时任务与沙箱,组件不各自维护一份用户状态。
一句话:组件各记各的资源,但只认同一个 subject_id 和同一个签名信封。
五、账号能力清单:不止登录
| 能力 | 开源落点 | 必须补的部分 |
|---|---|---|
| 认证 | Higress 的 OIDC / JWT / Key Auth;市场接企业 OIDC | 多 IdP 映射、会话登出、MFA 策略 |
| 授权 | 市场可见性 + 命名空间权限 + 工具策略 | 角色模型、审批流、职责分离 |
| 配额 | 网关 Token 限额、调度器并发、存储配额 | 预留与透支规则、跨层预算 |
| 计费 | 网关按 Token/调用计量 | 价格版本、结算、退款、对账 |
| 审计 | 网关访问日志、会话事件日志、Trace | 保留期、脱敏、不可篡改 |
| 生命周期 | 目录账号同步 | 入职、转岗、离职的资源和凭据回收 |
最后一行最容易被忽略:账号系统的终点不是登录成功,而是离职后所有派生资源都能被找到并停掉。所以每个资源都要有 owner 和 tenant,凭据要有签发者与有效期。
六、个人账号与租户账号的边界
个人空间和租户空间不是大小关系,而是信任等级不同:
- 个人工作区允许快速试验、接个人订阅、跑本地 Harness;默认不进入租户目录,也不被租户管理员读取。
- 要变成团队能力,必须走“提交 → 评审 → 发布”的晋升路径,发布后由租户目录托管版本,个人改动不影响已发布版本。
- 个人凭据不能直接给租户级 Agent 使用;租户级执行只能用 Vault 中登记、可轮换、可审计的凭据。
这条边界保护两边:个人试验不被组织流程拖慢,组织能力不被个人密钥绑架。
七、隔离矩阵:别只靠命名空间
| 维度 | 隔离手段 | 容易漏的地方 |
|---|---|---|
| 身份 | OIDC + 命名空间校验 | 服务间调用跳过校验 |
| 数据 | 行级过滤 / 独立库 / 前缀 | 缓存键、向量索引没带租户 |
| 计算 | 独立命名空间 / 节点池 | 共享 Pod 池残留工作目录 |
| 网络 | NetworkPolicy / 出站白名单 | 工具直连内网绕过网关 |
| 模型 | 租户级端点与配额 | 共享 Key 的用量无法拆分 |
| 工具 | 工具集启用 + 调用策略 | MCP Server 内部再访问别的租户 |
| 证据 | Trace 与日志带租户标签 | 排障时跨租户检索 |
命名空间只是“资源分组”,不是安全边界。真正的隔离要在数据、网络、凭据三个层面各有一道,并且默认拒绝。
最小上手
先不接市场,只做三件事:
text
1. 网关注册一个 OIDC 客户端,登录后把 sub / tenant / roles 写入请求头;
2. Service 侧固定读取 X-AgentScope-Tenant 与 X-AgentScope-Namespace,拒绝缺失;
3. 所有存储键统一为 {tenant}/{namespace}/{resource},缓存与检索强制带前缀。再加一张策略表,至少覆盖四行:租户管理员能做什么、普通用户能做什么、应用能做什么、Agent 实例能做什么。跑通判据:换一个租户的 Token 请求同一接口返回 403;同一问题在两个租户下召回不同文档;删除一个用户后,其个人 Key 与工作区在 24 小时内失效。
生产动作
- 身份四元组强制:
tenant / namespace / subject / session缺一即拒绝,不接受“默认租户”。 - 凭据不落业务库:统一进 Vault,按租户路径隔离,支持轮换与吊销;日志只留元数据。
- 配额三层对齐:企业上限、租户配额、项目/用户配额,扣减顺序固定,超额行为(拒绝/排队/降级)显式配置。
- 缓存键带作用域:模型语义缓存、检索缓存、工具结果缓存都必须包含租户与密级,否则宁可不用缓存。
- 离职回收演练:每季度挑一个账号,验证其凭据、工作区、定时任务、Hosted Runtime 能否全部停掉。
边界
- 层级不是越多越好:五级是上限,不是模板;小团队可以合并企业与租户,但不要合并“人”和“应用”。
- 命名空间不等于安全:同一集群共享内核与网络,强隔离要独立节点池或独立集群。
- 个人空间不适合放生产凭据:本地 Harness 方便,但它的密钥、代码和产物默认不受平台管控。
- 配额不能只在一层做:只在网关限 Token,工具仍可能被刷;只在调度器限并发,模型仍可能被刷。
- 不要用 Agent 名称当身份:名称会重、会改;身份要用不可变 ID 加版本。
讲清楚
平台身份要同时回答三个问题:谁在调用、资源算谁的、这次执行属于哪个会话。做法是把人、应用、Agent 实例三类主体,投影到企业、租户、用户、工作区、会话五级作用域上,上一级只能收紧下一级。
组件各有一套账号,接缝处必须重新校验,不能透传信任。请求带齐四元组,凭据进 Vault,缓存和检索带租户前缀,配额在网关、调度、存储三层对齐,离职时能回收全部派生资源。
判断账号模型是否成立,看四个反例:换租户 Token 是否被拒、跨租户是否召回别人的文档、个人 Key 能否驱动租户级 Agent、离职后是否还有孤儿任务在跑。
适用:2026 年开源 Agent 平台账号体系 | 初稿 2026-10