先区分平台中的 Principal 与责任
Principal 是能够被认证并承担权限或审计责任的主体。最终用户、审批者和租户管理员是人类主体;前端/Host 应用、Agent 服务与 Runtime Worker 是工作负载主体;Tool、MCP Server、远程 Agent 和业务 API 是资源服务器或对等工作负载;平台运维与 Break-glass 身份拥有受控的管理能力。
| 主体 | 可信证明 | 不能由它证明 |
|---|---|---|
| 最终用户 / 审批者 | 企业 IdP 会话、认证强度、用户与租户关系 | Runtime 实例未被替换 |
| Host 应用 | OAuth Client、重定向与会话绑定 | 用户拥有目标资源 |
| Agent / Runtime 工作负载 | 工作负载身份、部署与信任域 | 用户已同意具体业务动作 |
| Tool / 资源服务器 | 服务身份、Endpoint 与证书/签名 | 调用参数来自可信事实 |
| 模型 | 只有生成内容与 Provider 回执 | 任何主体身份、权限或同意 |
SPIFFE为动态异构环境定义短期工作负载身份 SVID,可用于工作负载相互认证。它解决“哪个服务实例在通信”,不自动携带最终用户授权。用户身份与工作负载身份必须在审计中同时保留,不能用一个共享服务账号覆盖所有用户。
Break-glass 是独立主体和流程:强认证、明确理由、短期限、双人或事后复核、全量审计和使用告警。它不能复用日常管理员会话,也不能让运维人员通过“排障”绕过租户数据边界而不留证据。
每次行动都保留完整委托链
入口从可信会话解析用户、租户、Host 应用、认证强度和用途。Runtime 用自身工作负载身份访问平台基础设施;需要访问用户业务资源时,向授权服务交换一个面向目标资源、范围收窄、时效短的委托 Token。Subagent 或远程 Agent 再委派时,只能获得子任务所需的衰减权限,不能复制父级 Token。
RFC 8693 OAuth 2.0 Token Exchange区分 impersonation 与 delegation,并定义 actor 语义。工程上应优先保留 delegation:资源能看见 subject 用户与当前 actor 服务,而不是让 Agent 看起来就是用户本人。审计事件至少关联 initiator、subject、actor、approver、tenant、purpose、run、resource 和 policy decision。
凭据生命周期与 Agent Run 生命周期分离
Run 可能持续数小时或等待数天,访问 Token 不应因此变成长效凭据。短期 Token 绑定 issuer、audience/resource、scope、subject、actor 和租户;跨服务通过 Token Exchange 或独立服务身份取得面向目标资源的 Token,不透明透传入口 Token。
RFC 9700 OAuth 2.0 Security Best Current Practice建议访问 Token 做受众限制,并在可行时使用 sender-constrained token 以降低泄露重放风险。具体采用 mTLS 或 DPoP 取决于客户端与基础设施,但 Bearer Token 仍必须视为敏感秘密,不能进入 Prompt、普通日志、Artifact 或队列消息。
| 边界 | 正确动作 | 失败处理 |
|---|---|---|
| 首次敏感动作 | 按风险触发 step-up 或重新授权 | 保存待办,不保存可重放凭据 |
| 等待审批 | Token 到期;审批绑定动作与参数摘要 | 审批完成后重新取得当下授权 |
| 长任务恢复 | 重新认证工作负载、授权主体并读取外部状态 | 权限撤销则停止或降级 |
| 主体离职 / 租户停用 | 撤销后续交换与刷新能力 | 在途不可逆动作进入人工处置 |
| 密钥轮换 | 短期凭据自动更新,验证方支持信任重叠窗 | 过期凭据拒绝且不无限重试 |
恢复点保存授权决定引用、所需 scope、目标资源与参数版本,不保存完整 Token。恢复时重新计算权限,防止“审批时有权、提交时已撤销”或“Run 创建时属于租户,恢复时租户已删除”的时间差越权。
租户上下文必须端到端不可丢
tenant、user、app 和 purpose 只能从验证后的身份与服务端映射产生,禁止从 Prompt、模型输出或未验证 Header 获取。入口建立不可变安全上下文,Run、Task、Trace、队列消息、存储主键、Artifact、RAG 查询、模型调用和 Tool 请求都携带它;跨边界时验证存在性与一致性,缺失则拒绝。
// 示例:安全上下文是服务端产物,不接受模型自由填写
interface SecurityContext {
tenantId: string;
subjectId: string;
actorId: string;
applicationId: string;
purpose: string;
authnLevel: string;
policyDecisionId: string;
}
function requireTenantContext(ctx: Partial<SecurityContext>): SecurityContext {
if (!ctx.tenantId || !ctx.subjectId || !ctx.actorId) {
throw new Error('TENANT_CONTEXT_MISSING');
}
return Object.freeze(ctx as SecurityContext);
}
队列消费者不能依赖进程本地上下文,因为异步切换会丢失它。消息只携带签名或防篡改的最小上下文与授权引用,不携带可直接调用业务资源的长效凭据。Consumer 将 tenant 写入数据库会话、缓存命名空间和 Trace Resource,再执行任何查询。
AWS SaaS 架构文档强调,用户已认证和获得应用功能授权并不自动实现租户隔离;每次资源访问还必须用租户上下文限制可达资源。这正是 tenant 不能只作为日志标签的原因。
RBAC、ABAC 与 Capability 组合
企业 Agent 很少能靠一种授权模型闭环。RBAC 表达稳定组织职责,ABAC 处理资源、环境和风险条件,Capability/Scope 把某次委托缩到具体动作与资源。最终决定是三者与平台底线的交集,不是并集。
RBAC
Role-Based Access Control 用角色表达“租户财务审核员可以查看并批准一定范围的费用”。它适合稳定职责和管理界面,但把每个客户、数据级别、时间和动作参数编码为角色会产生角色爆炸。角色必须带租户作用域,不能用同名角色跨租户复用权限。
ABAC
Attribute-Based Access Control 结合主体、资源、动作和环境属性,例如资源敏感度、地域、设备风险、时间和用途。策略输入必须来自可信属性源,并记录版本与新鲜度;模型抽取的“看起来低风险”只能作为待验证信号,不能直接进入允许条件。
Capability / Scope
Capability 或 Scope 约束具体 Tool、动作、资源集合和委托期限。它应短期、可撤销、受众受限,并绑定 subject 与 actor。对高风险 Tool,还要绑定参数摘要或资源版本,防止“批准查看订单 A”被替换成“退款订单 B”。
决策与执行分离
NIST SP 800-207区分 Policy Decision Point(PDP)与 Policy Enforcement Point(PEP)。PDP 读取可信属性和策略,返回 allow/deny、理由、策略版本与义务;PEP 位于每个 Tool、数据和模型入口,校验决定与实际资源/参数一致并执行脱敏、审批或审计义务。
| 层 | 回答 | 缺失时 |
|---|---|---|
| RBAC | 主体承担什么组织职责 | 无基础授权 |
| ABAC | 当前资源、环境、用途是否满足条件 | 敏感动作拒绝 |
| Capability / Scope | 本次委托允许哪些具体动作 | 不得从角色推导无限动作 |
| PEP | 实际参数和资源是否与决定一致 | 拒绝执行并记录证据 |
每个数据层都要选择隔离策略
隔离不是一次数据库选型,而是逐层决定 pool、silo 或 bridge。高监管或大客户可以独立资源,长尾租户共享资源并做强制策略,常见平台采用混合模型。选择变量包括敏感度、爆炸半径、合规地域、性能噪声、运维复杂度与单位成本。
独立库、Schema 与行级隔离的权衡
独立库提供清晰故障域与密钥边界,但迁移、连接和运营成本高;独立 Schema 降低部分混淆,仍共享数据库实例;共享表加 tenant_id 最经济,却最依赖查询与数据库策略。PostgreSQL Row-Level Security在启用后可对普通查询实施策略并在无适用策略时默认拒绝,但表 Owner 和 BYPASSRLS 角色存在旁路,应用连接角色与管理路径必须专门测试。
向量索引分区与权限过滤不可后置
向量检索先按租户、用户 ACL、数据分类和时间过滤,再做相似度排序。若存储不支持可靠的前置过滤,使用租户/安全域独立索引或检索后对更大的安全候选集过滤,并验证召回与隔离。先全局 Top-K 再删越权结果,既可能泄露侧信道,也会让合法结果被越权候选挤掉。
缓存 Key、连接池和本地缓存携带租户
缓存 Key 至少包含 tenant、subject/权限视图、资源版本和政策版本;敏感租户使用独立命名空间或实例。数据库连接从池中取出时设置租户会话并在归还前清理,错误时也必须执行;进程本地缓存同样不能只按资源 ID。缓存命中后重新验证当前授权,不能缓存一个永久 allow。
日志、Trace、评测样本和导出的访问控制
Telemetry 与评测集常聚合多个租户,必须按 tenant、用途和保留期授权。错误栈、Prompt、Tool 参数与 Artifact 可能包含原始数据,默认采用元数据与哈希;需要内容排障时走受控采样、脱敏和限时访问。导出文件是新的数据副本,带独立 ACL、过期和删除传播。
运行资源防止邻居干扰
数据不泄露仍不等于租户隔离成功。一个租户可以用长流、递归 Agent、昂贵模型、Tool 风暴或大 Artifact 耗尽共享资源。平台按租户和 workload class 管队列、并发席位、Token/费用、Tool 调用、存储和 Telemetry 基数,并在 Scheduler 中实施公平排队与有界优先级。
| 资源 | 控制 | 验证信号 |
|---|---|---|
| Run / Worker | 租户队列、并发、Deadline、最大深度 | 队列等待、公平份额、取消延迟 |
| 模型 | Token、费用、长流席位、关键预留 | 429、Provider TPM、单位任务成本 |
| Tool / Sandbox | 调用速率、网络、CPU/内存、凭据按 Run 隔离 | 超限阻断、逃逸测试、凭据残留 |
| 存储 / Telemetry | 容量、吞吐、基数和保留配额 | 写入拒绝、降级、删除完成率 |
Kubernetes API Priority and Fairness展示了分级、有限队列与公平调度如何避免异常消费者饿死同级请求。Agent 平台可借用机制而非照搬配置:高优先级任务可获得预留,但优先级必须受租户配额约束,不能让关键租户无限挤压普通租户。
容量与安全共享同一过载测试。让一个租户制造取消风暴、超长流和高基数 Trace,确认其他租户 SLO、计费、队列与审计仍正确;只验证 CPU 限额无法覆盖 Provider 与下游 SaaS 配额。
授权决定要贯穿异步、审批和恢复边界
授权决定绑定稳定动作、目标资源 ID、参数摘要、策略版本、主体链和有效期。队列、重试和回调携带最小安全上下文与 decision reference,不携带入口完整 Token。PEP 执行时确认消息未篡改、目标仍一致,并根据风险选择复用短期决定或重新询问 PDP。
| 边界 | 攻击/失败 | 控制 |
|---|---|---|
| 审批等待 | 批准后替换参数或资源版本 | 审批绑定摘要,提交前比较并重新授权 |
| 异步重试 | 权限已撤销仍用旧 Token 重放 | 只存引用,重试时换取短期 Token |
| Run 恢复 | 租户、用户或外部状态已变化 | 恢复前重验身份、授权与业务状态 |
| 回调 | 伪造来源或跨租户关联 Run | 验证回调服务身份、tenant 与一次性关联 |
| Break-glass | 例外权限变成长期旁路 | 短期、理由、告警、审计与强制复核 |
拒绝是可恢复业务状态,不应被 Runtime 当网络错误无限重试。Trace 要区分权限不足、属性过期、需 step-up、需审批和主体撤销,向用户提供可行动路径,但不泄露其他租户资源是否存在。
租户管理员需要可配置但受底线约束
租户管理员可以在平台安全包络内配置模型/Tool/Agent 准入、数据保留与地域、预算、审批人、自动化范围和用户角色。平台定义不可关闭的底线,例如身份验证、跨租户拒绝、关键审计、凭据保护和高风险动作最小审批;租户可以选择更严格,不能降低底线。
| 层级 | 示例 | 冲突处理 |
|---|---|---|
| 平台底线 | 禁止跨租户、关键审计、敏感凭据不入 Prompt | 不可覆盖 |
| 行业/区域政策 | 数据驻留、保留上限、模型准入 | 取更严格约束 |
| 租户政策 | 预算、审批、允许 Tool、自动化上限 | 不得放宽上层 |
| 应用政策 | 业务用途、低风险默认模型、队列优先级 | 在租户范围内生效 |
配置发布走双人复核或风险分级审批,生成不可变版本并支持回滚。管理员 UI 需要预览受影响的用户、Agent 和 Run;紧急收紧立即生效,放宽则先进入评审和灰度。平台团队与租户团队通过 RACI 约定谁定义数据分类、谁维护审批人、谁响应隔离事故。
系统化测试跨租户泄露
隔离测试建立两个最小权限租户和一个受控管理员,覆盖 API、异步、存储、检索、缓存、Telemetry、导出、删除和资源竞争。测试不只断言 403,还要确认响应时间、错误、日志和指标不泄露目标资源是否存在,且失败不会污染另一个租户状态。
| 攻击 | 注入方式 | 必须观察 |
|---|---|---|
| ID 枚举 / 参数替换 | 把 tenant A 的资源 ID 放入 tenant B 请求 | PEP 拒绝、无存在性泄露、审计关联 |
| 缓存混淆 | 相同资源 ID、不同 tenant/角色重复请求 | Key 分区、命中后重授权、内容不串租户 |
| 检索过滤缺失 | 构造与另一租户文档高度相似的查询 | 候选前过滤、无片段/计数泄露 |
| 异步上下文丢失 | 重试、延迟回调、旧版本消息 | 缺上下文 fail closed,旧权限不重放 |
| Trace / 导出泄露 | 低权限用户查询错误、评测与账单导出 | 字段脱敏、ACL、保留与下载审计 |
| 噪声邻居 | 长流、Tool 风暴、大 Artifact、高基数 | 其他租户 SLO、公平份额和计费正确 |
| 租户删除 | 删除后访问 Run、缓存、向量、备份派生物 | 删除清单、墓碑、重建后仍不可恢复 |
验证还要做凭据扫描和混沌测试:终止 Worker 后检查本地凭据是否残留;轮换密钥和撤销用户后恢复 Run;让 PDP、IdP 或租户目录短暂不可用,确认高风险动作 fail closed、低风险降级符合已批准策略。残余风险包括第三方 Provider 的内部隔离、备份删除延迟和 Telemetry 下游副本,必须在数据处理协议与运行控制中单独管理。
可交付的隔离证据不是一张权限矩阵,而是自动化攻击用例、策略版本、PEP 决策日志、租户数据流、配额压测、删除证明和 Break-glass 演练记录。只有这些证据能说明控制在异步、恢复和故障下仍然成立。
主动提取:为什么工作负载身份不能替代用户委托?
迁移判断:审批已经通过,三小时后 Worker 可以直接提交吗?
隔离判断:共享表启用了 RLS,为什么仍需应用层与测试防线?
资料与事实边界
以下以官方文档、标准、论文和原始工程资料为主。厂商 API、价格、限额与模型能力会变化,落地时仍需按目标版本做能力探测和回归。
- RFC 8693:OAuth 2.0 Token Exchange — subject、actor、delegation、impersonation 与跨服务 Token Exchange
- RFC 9700:OAuth 2.0 Security Best Current Practice — 最小权限、受众限制、sender-constrained token 与重放防护
- NIST SP 800-207:Zero Trust Architecture — PDP、PEP、持续评估与资源中心的授权模型
- SPIFFE:Overview — 动态环境中的短期工作负载身份与相互认证
- AWS:SaaS tenant isolation — 认证授权与租户隔离的区别、pool/silo 资源边界
- PostgreSQL:Row Security Policies — 行级策略、默认拒绝与 Owner/BYPASSRLS 边界
- Kubernetes:API Priority and Fairness — 过载下的请求分类、有限排队与公平调度