Agent 身份认证与授权如何分层设计
文章介绍用 SPIFFE 标识工作负载、通过 SPIRE 签发短期身份凭证,再由 OPA 执行授权策略,以降低长期静态密钥被复制滥用的风险。它同时强调,身份可信并不代表 Agent 的具体操作安全。
AI 深度解读
长期有效的 API key 很容易接入,也容易在被复制后变成冒用 Agent 的通行证。原文给出的方案是:用 SPIFFE 和 SPIRE 证明调用者是谁,再用 OPA 决定它能做什么。短期身份凭证负责减少密钥暴露风险,默认拒绝的策略负责限制操作范围。
这套分工值得做 AI 工具调用的程序员理解。但它不是防止 Agent 闯祸的完整答案:身份验证通过,依然可能执行提示注入诱导的危险请求。
先分清:谁在调用,和它能做什么
原文用机场解释这套机制:护照回答「你是谁」,登机口回答「你能不能上飞机」。SPIFFE 和 SPIRE 负责前者,OPA 负责后者。
SPIFFE 是标准,SPIRE 是实现,Istio 等服务网格也能签发 SPIFFE 身份。一个 Agent 的名字可以是 spiffe://example.org/agents/billing:example.org 是信任域(trust domain),后面的路径标识具体工作负载。
名字还需要可验证的证明。SVID,即 SPIFFE Verifiable Identity Document,就是带签名的身份证明,有 X.509 证书和 JWT 两种形式。
作者更推荐证书,因为私钥留在 Agent 一侧;JWT-SVID 一旦被盗,在过期前仍可能被重放。这里要区分:私钥没有随请求发送,不等于运行环境失陷后私钥也绝对安全。
原文把有效期在一小时内的「护照」作为替代长期密钥的形象说法,但没有给出统一的有效期配置。真正要抓住的是短期有效、自动轮换,而不是把「一小时」当成协议硬限制。
没有初始密码,SPIRE 怎么认出 Agent
用一个秘密去换另一个秘密,会留下最初那个秘密如何保管的问题,也就是 secret zero。SPIRE 用两步认证建立信任。
第一步是节点证明自己,例如提交云实例文档。SPIRE Server 相当于签发办公室,每个节点上的 SPIRE Agent 是本地窗口。这里的 SPIRE Agent 是基础设施组件,和 AI Agent 是两回事。
第二步是工作负载证明(workload attestation)。AI Agent 向本地窗口申请身份,不必先提交 API key。窗口通过内核确认调用进程,再识别它的容器、ServiceAccount 等属性。
原文列出的选择器包括 k8s:ns:agents、k8s:container-image:…/billing-agent 和 k8s:sa:billing-agent。它们要匹配预先登记的条目,才能拿到 SVID。
下面的命令把命名空间和 ServiceAccount 映射到 billing Agent 的身份:
spire-server entry create \
-parentID spiffe://example.org/spire/agent/k8s_psat/demo-cluster/node-1 \
-spiffeID spiffe://example.org/agents/billing \
-selector k8s:ns:agents -selector k8s:sa:billing-agent
要看清两行 -selector:这条示例实际登记了命名空间和 ServiceAccount,没有登记上文提到的镜像条件。允许哪些进程获得身份,取决于你配置的匹配规则。
SVID 会在到期前自动轮换。随后,Agent 与内部工具通过双向 TLS(mTLS)通信,双方依据各自的信任包验证对方。原文说的「不再需要 API key」限定在这类内部调用,不能直接推到所有第三方 API。
身份完全正确,为什么还会删库
原文构造了一个危险场景:提示注入让 billing Agent 发出 DELETE /customers HTTP/1.1,工具返回 HTTP/1.1 200 OK。
这不是身份验证失败。调用者确实是 billing Agent,只是工具允许它做了不该做的事。
身份验证通过,不能成为放行操作的充分条件。
OPA,即 Open Policy Agent,负责根据 Rego 策略判断请求是否允许。下面的规则只放行指定身份对发票路径的 GET 请求:
default allow := false
allow if {
input.principal == "spiffe://example.org/agents/billing"
input.method == "GET"
startswith(input.path, "/invoices")
}
最关键的是 default allow := false:没有明确放行的请求一律拒绝。OPA 返回判断结果,Envoy 执行拦截,通常返回 403 Forbidden。
不过,startswith(input.path, "/invoices") 只是前缀匹配,示例没有表达租户、资源归属或金额限制。真实业务仍要细化策略。
Agent 还经常代表人办事,所以入口既要识别 Agent,也要检查用户授权。原文提到一份 2026 年 9 月的 IETF AI-agent 草案,采用类似分工:Agent 使用 SPIFFE 风格身份,用户侧使用 OAuth token exchange,策略判断不在该草案讨论范围内。它是草案中的设计方向,不能据此认定已有统一落地标准。
我的判断
我认同原文最有用的拆分:把工作负载身份、用户授权和业务权限分别处理。这样才能解释为什么换掉长期密钥之后,仍然需要限制 Agent 的工具调用。
但文章是一篇 4 分钟动画讲解的文字版,没有提供部署实验、故障记录或对照数据。它说明了机制为何合理,没有证明某个团队采用后成本更低、事故更少。
相较于手工轮换 API key,这套方案增加了身份签发、节点认证和策略执行组件的运维成本。对已有 Kubernetes、服务网格和多服务调用的团队,它更容易接入现有体系;对只调用外部模型 API 的小应用,原文没有说明这些供应商如何接受 SPIFFE 身份。
此外,示例中的全量删除会被拒绝,但获准的读取操作仍可能造成数据泄露。默认拒绝能缩小权限范围,不能独自解决提示注入。
能拿来做什么
- 为 Node 工具服务梳理 Agent 的实际权限,把读取发票与删除客户等操作分开,先明确每个身份允许调用哪些接口。
- 已经使用 Kubernetes 的团队,可以按命名空间和 ServiceAccount 设计身份映射,检查不同 Agent 是否共享了过宽的身份条件。
- 在工具入口落实默认拒绝,并确认 OPA 的拒绝结果确实由 Envoy 等执行层拦截,不能只记录策略判断。
- 对代表用户操作的 Agent,同时保留工作负载身份与用户授权信息,并在业务策略中检查租户和资源归属。