作者:Max Luo · 2026年10月11日 · Teloa AI Security
请求里有 user_id,不代表请求已经通过用户认证;进程有一个 Agent 名称,不代表它被平台允许以这个身份访问下游。企业 Agent 的身份设计要回答三个不同的问题:谁发起并承担授权责任,哪一个逻辑 Agent 正在执行,哪一个运行实例持有这次调用的证明。
这篇文章沿“员工从 IM 发起工单摘要任务”的路径,设计身份绑定、执行实例登记、网关认证和停用流程。JSON 与流程都是参考设计,示例字段不是标准协议,也不代表 Teloa 已实现全部控制。规范依据是基线 V1,等级与适用条件按原文核验。
1. 建立三个身份,再关联任务与租户
| 身份 | 例子与可信来源 | 生命周期 | 能证明什么 |
|---|---|---|---|
| 用户主体 | IdP 验证后映射的 user-42 |
入职、转岗、离职及认证会话 | 哪个人发起或委托了任务 |
| 逻辑 Agent | 平台登记的 agent-support |
登记、发布、配置变更、停用 | 使用哪项受控 Agent 配置 |
| 工作负载 | 控制面签发给 run-17 的短期身份 |
单次会话或执行实例 | 哪个实例正在发起访问 |
任务、租户、工作空间、连接器与这三个身份形成平台登记关系。它们不能在每次请求中被自由组合:一个合法的 run-17 凭证,也不能被请求参数重新绑定给管理员或另一个租户。负责人是治理属性,不能代替执行主体。
这里还要区分代表用户行事与自主 Agent。代表用户的 Agent 受该用户权限上限约束;基线中的自主 Agent 使用独立的非人类身份,负责人负责治理,但平台不能偷借负责人的个人账号。自动程度很高的定时任务,也可能仍然属于用户委托任务。V1.3.2、V2.3 对这两种模式分别规定了身份与权限责任。
2. 渠道绑定要证明双方,而不是匹配名字
一个安全的绑定流程必须同时证明“这个渠道账号是谁”和“这个企业用户是谁”。只完成 SSO,然后相信浏览器传回的 IM 用户 ID,仍然可能把攻击者的渠道账号绑定到受害人的企业身份。
一种参考流程是:
- 验证渠道平台签名、时间戳和事件去重标识,从已验证事件得到组织 ID 与稳定的渠道账号 ID。
- 服务端创建短时、单次使用的绑定事务,记录渠道组织、账号、预期企业租户及回调状态;浏览器只拿到随机事务引用。
- 用户进入企业 IdP 完成认证,平台验证登录结果与绑定事务。采用 OIDC 授权码流程时,按协议完成
state、nonce与 PKCE 等检查,不能用未经校验的令牌载荷建立绑定。 - 根据已验证的 IdP 身份查企业目录,确认用户仍启用、租户一致。在已认证的企业用户界面展示服务端固定的渠道组织与账号,要求用户明确确认绑定意图;再核对渠道账号所有权,在原渠道完成确认或采用提供方可验证的账号关联机制。不能只有攻击者能够独立完成的原渠道确认,否则转交绑定链接可诱导受害人登录并关联到攻击者的账号。
- 原子消费事务并建立绑定;换绑、跨租户绑定和账号恢复需要重新验证,旧绑定的解除留审计。
企业用户键可以由可信 issuer 与 subject 映射产生。OpenID Connect Core规定 sub 在签发方内识别用户,并存在 pairwise subject 模式。因此跨客户端不能假定 sub 相同,更不能退回用邮箱字符串自动合并账号。
{
"channel_key": ["im-provider", "org-a", "channel-user-81"],
"enterprise_user": "user-42",
"verified_idp_identity": {
"issuer": "https://idp.corp.example",
"subject": "idp-subject-4281"
},
"tenant": "tenant-a",
"binding_transaction": "bind-902",
"status": "active"
}
这是服务端登记记录,不是接受任意客户端提交的绑定请求。显示名、昵称和邮件 From 地址只能用于展示。DMARC 校验可以帮助核验发件域,却不能单独证明企业员工身份,也不能代替企业授权;邮件渠道还必须满足 V1.2.6 的外部域限制和其他身份控制。
3. 执行实例启动时固定身份关系
在创建 run-17 时,控制面先验证用户状态与 Agent 配置,再登记 tenant-a / user-42 / agent-support / task-17 / run-17 的关系。凭证的持有边界要与模型、可执行代码及普通工具结果分开。
已验证渠道事件 → 查询绑定与用户状态
→ 控制面创建任务、登记 run-17
→ 签发受众受限的短期工作负载证明
→ 受控身份组件认证到出口网关
→ 网关查实例登记,恢复可信调用主体
如果使用 JWT,可以采用下面这种平台内部证明载荷。这里的私有声明只是为了展示绑定关系;它不是 ID Token,也不是可以直接传给第三方 SaaS 的通用 OAuth 令牌。示例时长为 300 秒,是演示选择,不是基线要求的统一时长。
{
"iss": "https://workload-issuer.corp.example",
"sub": "workload:run-17",
"aud": "egress-gateway",
"iat": 1791676800,
"exp": 1791677100,
"jti": "proof-017",
"tenant_id": "tenant-a",
"task_id": "task-17",
"registry_revision": 7
}
网关不能只验签。它还要限制可信签发方、算法和密钥来源,验证受众、有效期与所选令牌类型,并检查实例仍处于活动状态、任务与登记版本一致。kid 只用于选择预先信任的密钥,不允许请求提供任意验签地址。权限与用户启用状态来自当前控制面,不能永远使用签发时的副本。
如果部署采用 OAuth JWT access token profile,应遵循 RFC 9068 的资源服务器校验规则,而不是将上述私有证明伪装成标准访问令牌。JWT 的签名保证完整性,不保证载荷保密;Base64 解码得到的声明不能作为已验证身份。
4. 在网关恢复主体,处理代理与 sidecar 的边界
V1.4.3 要求网关只依据工作负载身份确定用户和 Agent。一个安全的处理顺序是认证工作负载、查可信登记、检查状态,再将恢复的主体交给策略服务。工具参数中的 user_id、agent_id 只能作为待校验业务数据,不能覆盖认证结果。
常见的绕过发生在反向代理里:代理设置了 X-User-ID,但网关也允许客户端直接访问,并接受同名请求头。修复必须包含网络访问限制、可信代理认证,以及移除或覆盖客户端自带的身份头。只修改代码中“优先读取哪个头”不够。
sidecar 可以把密钥与模型上下文分开,但不自动构成安全边界。如果任意沙箱进程都能访问 sidecar 的身份签名接口,失陷进程仍可能以该实例身份提出请求。应限制控制接口和文件权限,阻断跨实例借用;同时假定已认证实例可能是恶意调用者,继续做每次请求的资源级授权。
工作负载认证的意义是“确定谁在调用”,不能证明“它的调用内容是安全的”。这一点也是身份篇与下一篇授权篇的分工。
5. 使用工作负载证明时,区分身份与软件完整性
V1.4.5 将签发前的工作负载证明放在 L3。SPIRE 的概念文档区分节点证明与工作负载证明:前者识别运行节点,后者利用进程属性与登记条件识别工作负载。这提供了签发身份的可信依据。
工程上还要处理实例粒度。若全部容器复用同一个服务级 SPIFFE ID,网关只能识别“这个服务”,不能据此区分具体会话。可以为会话建立独立登记关系,或通过受控 broker 在已证明的服务身份上再绑定一次性执行实例上下文;绑定仍须由控制面生成。
证明也不等于代码从未被攻陷。镜像签名、依赖版本锁定和运行时隔离分别解决供应链与执行问题,不能靠一个有效证书替代。L1、L2 部署也要满足其适用的短期实例身份要求,但不应被本文错误地提升为必须安装 SPIRE。
6. 下游令牌表达用户与执行者,委托链不增加权限
网关访问下游时,需要把内部工作负载身份转换成下游认可的授权形式。RFC 8693中的 sub 与 act 可以分别表达主体和当前执行者。以下仅展示声明关系,实际令牌由可信授权服务器签发,资源范围、有效期和受众按下游协议确定。
{
"sub": "user-42",
"aud": "tickets-api",
"scope": "tickets:read",
"act": { "sub": "agent-support" }
}
嵌套 act 保存先前执行者的历史,不是可以累加的授权集合。RFC 8693 明确历史执行者不能用于资源服务器的访问控制决定。多跳委托的权限收窄应在可信授权与策略服务中完成,将最终范围写入当前有效授权;审计保存完整链路,而不是从链中找到一个管理员就放行。
令牌交换也不会自动防止越权。授权服务器仍需判断谁可以代表谁、允许访问哪个资源,以及本次委托是否有效。自主 Agent 则使用自身的非人类主体,不能在日志里伪装成某位员工。
7. 短期身份仍需要主动撤销与运行状态检查
有效期只给出了过期上限。若用户被禁用,而网关只检查一个剩余五分钟有效期的凭证,调用仍可能继续;若旧 TLS 连接被复用,更新证书也未必中止已建立的连接。
一种可复验的撤销流程是:IdP 禁用事件更新用户状态;绑定失效;任务与实例被标记停止;身份签发与续期停止;网关拒绝新的凭证取用与调用;刷新令牌和仍可用的连接撤销;运行中的任务与重试队列中止。必要时关闭现有连接,或在每个请求上检查运行状态。下游支持何种撤销方式也应单独登记。
CREATED → ACTIVE → STOPPING → REVOKED → DESTROYED
│
└─ 到期 / 用户停用 / Agent 停用 / 会话结束
状态转换必须阻止“停用后续期”和“被停止的任务因重试重新激活”。状态缓存要有上限;事件丢失时有补偿同步;高风险调用无法确定当前状态时应拒绝。V1.4.4 要求会话结束或实例销毁立即吊销对应身份,V10.4.1 则要求用户禁用或降权后的调用在约定窗口内被拒。两个控制不能被混成“等 JWT 自然过期”。
测量撤销时,在禁用前开始对各网关节点与连接器持续探测,记录禁用事件、最后一次成功,以及之后首次持续拒绝的时间。最后成功只给出下界,稀疏探测可能低估延迟;报告观测区间、采样间隔与缓存配置,并以连续拒绝且没有后续成功验证约定上限。没有禁用后的成功样本时,也不能直接宣称零延迟。撤销不会回滚已经送达下游的操作,已提交的外部效果需要独立追踪和处置。
8. 用八个实验验收身份链
| 实验 | 预期结果 | 主要条款 |
|---|---|---|
| 修改渠道显示名或邮箱 | 企业主体与权限不改变 | V1.2.2 |
| 用另一租户的账号完成绑定事务 | 拒绝绑定,不产生关联记录 | V1.2、V1.5.2 |
| 重放事件、已消费事务,或转交有效绑定链接 | 不重复创建;受害人不得在未确认固定目标账号的情况下绑定到攻击者账号 | 参考流程的防重放与绑定意图控制 |
| 修改请求中的用户、Agent、实例字段 | 不能覆盖工作负载认证主体 | V1.4.3 |
| 让实例 B 使用实例 A 的证明 | 凭证持有边界或实例绑定阻止借用 | V1.4.1;结合执行隔离验收 |
| 发送错受众、过期或未可信签发的证明 | 网关认证拒绝,无下游凭证取用 | V1.4、V4.6.3 |
| 停止会话后重放旧证明、复用旧连接 | 调用被拒,停止状态不会被续期覆盖 | V1.4.4 |
| 禁用用户后运行定时任务或旧队列 | 在约定窗口内阻断,留下可关联记录 | V2.3.2、V10.4 |
保留认证事件、绑定版本、实例登记、拒绝原因、停用时间和下游日志。日志中不要保存原始令牌或私钥;令牌标识、证书指纹与受限的主体标识通常足以做关联。对于 JWT bearer 方案,凭证被窃取后可能被重放;若声称实例绑定能抵抗这类攻击,必须提供持有证明、密钥保护或等价机制的验证证据,不能只依赖载荷里的实例名称。
身份链验证完成之后,仍需要判断这个主体是否可以对这份资源做这项操作。继续阅读授权与执行篇,或回看威胁建模与评估篇。完整基线与自评工具由 Teloa AI Security维护,源于 Teloa 的开发实践。
