Featured image of post Agent 的身份联邦:SPIFFE 那套工作负载身份正在搬进 Agent 世界,但最后一道关不是身份,是意图

Agent 的身份联邦:SPIFFE 那套工作负载身份正在搬进 Agent 世界,但最后一道关不是身份,是意图

你的 Agent 要读 Jira、调内部结算 API、再把结果交给另一个 Agent 去发通知。这一路上它得回答同一个问题好几遍:你是谁,谁允许你这么干。

过去两年的默认答案很难看:给它一个 API key,或者更糟,给它一个大家共用的 service account。这个答案正在被换掉,换成的方案本身没什么新意,是从云原生搬过来的一个词,工作负载身份(workload identity)。

我把这条线上的几份一手文档读了一遍,包括 Google Cloud 的 Agent Identity、Anthropic 的 SPIFFE 联邦文档、IETF 那份专门讲 Agent 认证的草案、MCP 七月那版授权规范,还有 ServiceNow 十月中刚发的 AI Passport。读完的结论分两半:身份这件事,搬迁基本完成了;但搬完你会发现问题换了个地方,卡在意图上。

Service account 为什么不够用

先说清楚为什么不能继续凑合。

service account 的设计前提是:一个稳定的程序,跑在一台稳定的机器上,代表一个固定的角色。Agent 把这三个前提全打破了。

它可能是被临时创建出来的,跑完一个任务就销毁。数量可能几百上千,而且会长出来。它常常是在替某个具体的人办事,很少只代表自己。它会跨出你的信任域,去调别人的服务。它还做不了多因素认证,因为没人坐在它前面按指纹。

在这些前提下,service account 的每个特性都变成了缺点。它是共享的,所以出事之后你查不清是谁干的。它的密钥是长期的,一旦泄露,有效窗口就是它的整个生命周期。它可以被别的程序拿去冒充,因为它本质上就是一把静态钥匙。最关键的一点,它没法表达「代谁办事」——一个共享账号的凭证里,读不出委托链。

SPIFFE 到底给了什么

不熟这套东西的话,一句话能说清:SPIFFE 把「你是谁」从「你手里有一把密钥」改成了「平台能证明你是谁」,而且这个证明是短期的、可自动轮换的。

它有几个原语。身份是一个 URI,长这样 spiffe://trust-domain/path,前半段是信任域,后半段是工作负载的路径。凭证叫 SVID,可以是 X.509 证书,也可以是一个 JWT,里面的 sub 就是那个 SPIFFE ID。工作负载不用自己去申请密钥,它调一个本地的 Workload API 就能拿到,签发和轮换都是自动的。能拿到什么身份,由 attestation 决定,也就是平台去验证这个进程实际跑在哪、以什么身份在跑。SPIRE 是这套标准的开源参考实现,挂在 CNCF 下面。

两种 SVID 的分工值得单独说,因为它对应 Agent 的两种通信形态。X.509-SVID 用来做双向 TLS,适合 Agent 之间、Agent 和服务之间建连的时候互相验明身份,连接一旦建立,身份就绑在通道上了。JWT-SVID 是个可传递的 bearer 令牌,适合放进 HTTP 头去调 API,也适合拿去做跨域联邦,因为它就是一个标准 JWT,任何 OIDC 验证方都验得了。一个 Agent 通常两个都要:用 X.509 跟同伴建连,用 JWT 去调外部服务。

这里有个设计上的关键取舍:SPIFFE 不解决「你怎么信任另一个信任域」这件事,它把这部分交给联邦。两个信任域要互认,交换的是信任包(trust bundle),也就是对方的签发者公钥集合,而不是互相把对方的每一个工作负载登记一遍。所以身份联邦天然是「我信任你的签发者」,扩展性好得多。

适配已经发生,而且是多家同时发生

我原本以为「SPIFFE 用在 Agent 上」还停在提案阶段。查完发现不是,已经落到产品文档里了。

Google Cloud 的 Agent Identity 页面,第一句话就是:为每个 Agent 提供强证明的密码学身份,基于 SPIFFE 标准。它专门列了和 service account 的差别:Agent 身份默认不跨工作负载共享,不可被冒充,不允许开发者生成长期密钥,为 Google Cloud 签发的访问令牌会和这个 Agent 唯一的 X.509 证书做密码学绑定,用来防令牌窃取。它配套还有 Agent Registry(登记工具和目标)和 Agent Gateway(执行策略、检查流量)。有个细节我觉得挺关键:配合 Agent Gateway 和 Gemini Enterprise 时,终端用户的凭据由 auth manager 加密、在网关上解密,Agent 全程接触不到明文凭据。

Anthropic 那边是从联邦那一侧切的。它的工作负载身份联邦支持任何能签发 OIDC 兼容 JWT-SVID 的 SPIFFE 实现,两种接入方式:公网 HTTPS 上的 OIDC discovery 文档,或者直接把 JWKS 注册进去。文档里还写了几个具体约束:JWT-SVID 的 sub 是 SPIFFE ID,aud 由工作负载在取令牌时提供,而 Anthropic 额外要求 iss 和 iat 两个声明,因为 JWT-SVID 规范没强制它们。它举的例子是 SPIRE 的 OIDC Discovery Provider,负责发布 /.well-known/openid-configuration 和签名密钥。这个桥一搭起来,JWT-SVID 就跟任何一个 OIDC 令牌一样能被验证。

标准组织这边的态度更有意思。IETF 有一份草案叫 AI Agent Authentication and Authorization,作者来自 Defakto、AWS、Zscaler、Ping Identity、OpenAI 和 Okta。它的摘要第一句就是:这份文档不定义新协议,而是说明现成的、已经广泛部署的标准(WIMSE 架构加 OAuth 2.0 家族)该怎么用到 Agent 的认证授权上。它引用的 WIMSE,是 IETF 里专门做「多系统环境下的工作负载身份」的工作组,这份 Agent 认证草案就是它的一条输出线。想跟这条线,盯这个工作组比盯单个厂商的产品文档有用。

厂商侧的落点也在收。ServiceNow 十月十五号发的 AI Passport,定位是「一个新的授权层」,让企业能在多 Agent 工作流的每一个点上,实时控制 Agent 和 MCP 服务器被允许做什么。它强调基于开放规范,任何治理产品、身份提供方或执行点都能为自己的和第三方的 Agent 签发、验证凭证。

而 MCP 七月那版授权规范,已经把该硬的地方硬了:客户端必须带 resource 参数(RFC 8707 的资源指示器),服务端必须验证令牌是不是专门发给自己的、必须拒绝 audience 里没有自己的令牌;授权服务器如果不声明支持 PKCE,客户端必须直接拒绝继续。

规范里还有一条容易被忽略、工程上却最容易出事的要求:禁止令牌透传。意思是 MCP 服务器不能把客户端递给它的令牌原样转发给下游的第三方 API。这个做法看着省事,实际是经典的权限放大:下游只看到「有个合法令牌」,看不到这个令牌本来发给谁、用来干什么。规范要求服务端必须确认自己是令牌的预期接收方,堵的就是这条路。

把这些摆在一起看,一个判断就出来了:身份这一层已经形成共识,云厂商、模型厂商、平台厂商、标准组织在同一套原语上收敛。收敛的对象,就是从 Kubernetes 那套工作负载身份直接搬过来的。

「联邦」这一步真正解决的是什么

我一开始觉得联邦是个锦上添花的词,读完文档发现它是这套东西能规模化的前提。

如果没有联邦,跨组织调用 Agent 就得做点对点的凭证登记:你的每个 Agent 在我这边登记一遍,我的每个 Agent 在你那边登记一遍。Agent 数量一涨,这个矩阵就爆炸了,而且登记本身又成了新的信任负担。

联邦把这个矩阵压扁了。我只需要信任你的签发者,剩下的验证走标准流程:你签发的 JWT-SVID,我用你发布的 discovery 文档找到你的公钥,验签,看 sub 是不是我要放行的那个 SPIFFE ID,再看 aud 是不是发给我的。信任关系维护在信任域这个层级上,不在单个 Agent 上。

这才是「身份联邦」这四个字的分量。它让「跨信任域的 Agent 互认」变成一个可运维的工程问题,而不是一个每接一家就要重新谈一次的商务问题。

最后一道关:意图

到这里,一切看起来都挺顺。但我在读一份安全分析的时候停住了。

SC Media 五月初有一篇文章,标题直接写着:身份问题修好之后,MCP 的混淆代理问题还在。它的论点是,即使身份层完全正确,Agent 依然可以当混淆代理,因为工具校验的是凭证,不是那个人的意图。

它给了一张分层的表,我照着整理了一下,加上了每层实际住在哪:

控制层 它在验什么 住在哪
认证 Agent 是谁 身份提供方
授权 Agent 能访问什么 令牌 scope
委托 行使的是谁的权利 委托令牌链
持续上下文 登录之后发生了什么变化 策略引擎
意图 用户到底有没有要求过这个动作 工具边界(这里是空的)

前四层现在都有人在做了,而且做得不错。第五层是个洞。

机制其实不新。混淆代理是三十八年前就被描述过的问题:一个有权限的程序,被一个权限更低的调用方骗着去滥用它的权限。只是今天这个「有权限的程序」变成了一个拿着你生产数据库、邮箱和支付网关访问权的语言模型。而它的输入是自然语言,可以被它读到的任何一段内容改写。

prompt injection 在这里的表现很特别:它不偷你的凭证,它借用你的凭证。你的 Agent 身份是真的,令牌是合法的,audience 是对的,委托链是完整的。它只是被一份恶意文档说服,去做了一件用户从来没要求过的事。所有身份层的检查都会通过。

这不是理论。微软给 Copilot Studio 里一个间接 prompt injection 分配了 CVE-2026-21520,我在 NVD 上查了,官方描述是「Copilot Studio 中的敏感信息向未授权方暴露,未认证攻击者可通过网络向量查看敏感信息」,Microsoft 作为 CNA 给了 7.5 的 CVSS 3.1 分。安全圈当时讨论的重点是:给一个 agentic 平台里的 prompt injection 分配 CVE,这件事本身很不寻常。OWASP 在去年十二月的 Agentic 应用 Top 10 里,把这一类列为 ASI01,Agent 目标劫持。

今年冒出来的三份框架,其实都在往这个方向补。CoSAI 的 MCP 安全白皮书列了十二类、接近四十个威胁。IETF 有一份草案专门讲跨域授权信息共享,给跨信任边界运行的 Agent 定义了威胁模型。还有 CoSAI 四月十七号发的 Agentic 身份与访问管理框架,提了三样东西:签名的 Agent 清单、持续授权、以及保持委托链可审计的 on-behalf-of 令牌。

所以我的判断是这个:身份层做对之后,攻击面并没有缩小,它被推到了下一层。你从「证明你是谁」走到了「证明你要干的事是有人要你干的」。后面这半句,凭证答不了,因为凭证里没有意图。

要落地的话,按这个顺序

如果你现在要给一批 Agent 上身份,我建议的顺序是这样的。

第一,别用共享的 service account。每个 Agent 一个独立身份,这一条不商量,因为它决定了出事之后你能不能查清是谁干的。

第二,凭证要短期、要绑定。短期是自动轮换的前提,绑定是防窃取的前提,Google 那边把令牌和 X.509 证书做密码学绑定就是干这个的。

第三,把委托链做成可审计的。on-behalf-of 令牌链的意义不只是权限收窄,还有事后能还原出「这一串动作是谁委托的」。

第四,audience 绑定别偷懒。MCP 规范已经把这条写成强制项了,服务端必须拒绝不是发给自己的令牌,这是防令牌转发滥用的基本盘。

第五,高危写操作单独加一道意图校验。这是前面那个洞的位置。SC Media 那篇给的具体做法是给写操作加签名意图摘要,从风险最大的那几类开始(改邮箱、发起支付、授予权限、重置凭据),再把高影响动作拆成「先起草、再提交」两段。CoSAI 的框架也是同一个方向。

第五条的难度明显比前四条大。前四条基本是配置和集成的工作,第五条落到最后是改产品流程:你要在用户下单之前多一个确认动作,在系统里多一份能被验证的意图记录,而这两件事都不是运维能自己拍板的。但前四条做完了不做第五条,你得到的是一套很规整、能被绕过的身份体系。

写在最后

身份联邦这件事,我觉得最值得记的一点,是它示范了一种标准扩散的路径:Kubernetes 世界里被验证过的工作负载身份原语,被原样搬进了 Agent 世界,而且搬的过程里没人觉得需要重新发明一遍。IETF 那份草案的摘要说得很明白,不定义新协议。

但搬完之后剩下的那道关,也是真的难。身份解决的是冒充,意图解决的是操纵。前者是一个工程问题,后者更接近一个产品设计问题,因为你要回答的是「怎么把用户真实的意愿,变成一个可验证的工件,而不是 prompt 里的一句话」。

相关阅读:

By AI博士 万戈