SPIFFE 是 CNCF 用于向工作负载颁发身份的标准。SPIRE 是其开源参考实现,此外还有多款商业产品也能颁发符合 SPIFFE 规范的身份。Anthropic 可与任何发出兼容 OIDC 的 JWT-SVID 的 SPIFFE 实现进行联合身份验证。联合身份验证可通过位于公共 HTTPS URL 的 OIDC 发现文档(discovery 模式;请参阅 URL 约束)实现,也可通过直接注册 JWKS(inline 模式)实现。JWT-SVID 规范将 sub 定义为工作负载的 SPIFFE ID,而 SPIFFE Workload API 要求调用方在获取时提供 aud,因此这些声明在各实现中是一致的。Anthropic 还额外要求 iss 和 iat,而 JWT-SVID 规范并未强制要求这两项,因此请配置您的实现以填充这两个声明(在 SPIRE 中,iss 对应 jwt_issuer 服务器设置,iat 会自动设置)。完成上述配置后,本指南中的配置 Anthropic、获取并使用令牌和限定规则范围部分适用于任何 SPIFFE 实现。有关当前列表,请参阅 SPIFFE 项目网站上的实现 SPIFFE 的商业软件。
SPIFFE 为每个工作负载分配一个稳定的身份 URI,格式为 spiffe://<trust-domain>/<path>,SPIRE 通过 Workload API 按需将该身份作为 JWT-SVID 颁发。JWT-SVID 是一个普通的签名 JWT,其 sub 声明是工作负载的 SPIFFE ID,其 aud 声明由工作负载在获取时提供。
从 SPIRE 信任域到标准 OIDC 的桥梁是 SPIRE OIDC Discovery Provider,这是一个独立的辅助程序,用于发布信任域 JWT 签名密钥的 /.well-known/openid-configuration 和 JWKS 端点。当发现提供程序运行时,JWT-SVID 的验证方式与任何其他 OIDC 令牌相同:将发现 URL 注册为联合颁发者,编写一条匹配工作负载 SPIFFE ID 的联合规则,并让工作负载将其 JWT-SVID 提交给 Anthropic 的令牌交换端点。
本页面的示例使用 SPIRE,适用于 SPIRE Agent 运行的任何环境:Kubernetes Pod、虚拟机和裸机主机。
如果您的 Kubernetes 集群未运行 SPIRE,并且您希望改用集群原生的投影服务账户令牌进行身份验证,请参阅将 WIF 与 Kubernetes 结合使用。
inline 注册。iss 声明设置为您将注册为联合颁发者 issuer_url 的值。对于 discovery 模式,这是发现端点的公共 URL(在 SPIRE 中为 jwt_issuer 服务器设置)。获取 JWT-SVID 时请求的受众值始终为 https://api.anthropic.com。请在 spiffe-helper 的 jwt_audience、Workload API 的 FetchJWTSVID 调用以及联合规则的 audience 匹配器中使用此值。
本节中的说明特定于 SPIRE。如果您使用其他 SPIFFE 颁发者,请根据其自身文档配置 OIDC 发现端点和 JWT-SVID 获取方式,然后继续阅读配置 Anthropic。
如果您已经在运行带有 OIDC Discovery Provider 的 SPIRE,与 Anthropic 进行联合身份验证需要在 SPIRE 端完成三件事:一个与发现 URL 匹配的 jwt_issuer、一个用于将调用 Claude API 的工作负载的注册条目,以及一种让该工作负载获取带有 Anthropic 受众的 JWT-SVID 的方法。以下小节将逐一介绍。配置片段仅显示与 Anthropic 联合身份验证相关的设置;它们不是完整的 SPIRE 部署配置。
首次设置 SPIRE?请按照 SPIRE 快速入门部署 SPIRE Server 和 Agent,然后将 OIDC Discovery Provider 作为独立服务与 SPIRE Server 一起添加。发现模式的联合身份验证依赖于该提供程序已部署且可公开访问;它不是默认 SPIRE 安装的一部分。
Anthropic 通过将 JWT-SVID 的 iss 声明与已注册的联合颁发者进行匹配,并从该颁发者的发现文档中获取 JWKS 来验证 JWT-SVID。两个 SPIRE 设置必须使用相同的 URL:SPIRE Server 的 jwt_issuer(它会成为每个生成的 JWT-SVID 中的 iss 声明)和 OIDC Discovery Provider 的 domains 列表(它决定了提供发现文档和 JWKS 的主机)。这个共享的 URL 就是您向 Anthropic 注册的内容。
信任域和颁发者 URL 是相互独立的。信任域(spiffe://prod.example.com)限定 sub 声明的范围;颁发者 URL(https://oidc-discovery.prod.example.com)是 Anthropic 获取签名密钥的位置。它们不需要共享主机名。
确认 SPIRE Server 的配置中已设置 jwt_issuer,并指向发现提供程序的公共 URL。以下示例还显示了默认的 JWT-SVID 生命周期;SPIRE 的内置默认值为 5 分钟,这足够短,因此需要持续轮换(请参阅运行 spiffe-helper)。Anthropic 的令牌交换端点会拒绝任何生命周期超过联合颁发者配置的最大值(默认为 1 小时;请参阅验证规则)的身份令牌。此检查适用于所有 SPIFFE 实现,而不仅仅是 SPIRE,因此请将 default_jwt_svid_ttl(或任何按条目的覆盖值)保持在该最大值或以下。
server {
trust_domain = "prod.example.com"
jwt_issuer = "https://oidc-discovery.prod.example.com"
default_jwt_svid_ttl = "5m"
# ...
}在 OIDC Discovery Provider 的配置中,相同的主机名必须出现在 domains 下,并且提供程序必须能够访问 SPIRE Server 的 API 套接字。提供程序通过 HTTPS 提供发现文档和 JWKS;可使用其内置的 ACME 支持终止 TLS,或在其前面放置一个负责此操作的负载均衡器。
domains = ["oidc-discovery.prod.example.com"]
server_api {
address = "unix:///run/spire/sockets/private/api.sock"
}
acme {
email = "[email protected]"
tos_accepted = true
}该示例使用 server_api,它将发现提供程序连接到 SPIRE Server 的特权 API 套接字。提供程序也接受 workload_api 块(包含 socket_path 和 trust_domain),该块通过 SPIRE Agent 的 Workload API 获取 bundle;当发现提供程序不应访问 Server API 或运行在无法访问 Server 的节点上时,请使用此方式。在 Windows 上,address 字段仅适用于 Unix;请改用 server_api { experimental { named_pipe_name = "\\spire-server\\private\\api" } } 来提供 Server API 管道名称。
每个调用 Claude API 的工作负载都需要一个 SPIRE 注册条目,将其运行时选择器映射到 SPIFFE ID。如果工作负载已注册,请记下其 SPIFFE ID;您将在联合规则的 subject_prefix 中使用它。如果尚未注册,请进行注册。对于 Kubernetes Pod,选择器通常是命名空间和 Kubernetes 服务账户:
spire-server entry create \
-spiffeID spiffe://prod.example.com/ns/inference/sa/worker \
-parentID spiffe://prod.example.com/spire/agent/k8s_psat/prod-cluster/NODE_UID \
-selector k8s:ns:inference \
-selector k8s:sa:worker所示的 parentID 是单个节点自动生成的代理 ID。对于集群范围的注册,请将条目的父级设置为节点别名,以便它匹配每个节点上的工作负载,正如 SPIRE Kubernetes 快速入门所做的那样。
Kubernetes 之外的工作负载使用主机级选择器,例如 unix:uid:1000(unix:path 也可用,但需要在代理的 unix 工作负载证明器配置中设置 discover_workload_path = true)。运行 spire-controller-manager 的集群可以使用 ClusterSPIFFEID 自定义资源声明条目,而不是直接调用 spire-server entry create。
spiffe-helper 是一个边车实用程序,它连接到 SPIRE Agent 套接字,为给定受众获取 JWT-SVID,将其写入文件,并在过期前重新获取。该辅助程序默认以守护进程模式运行;下面的示例显式设置了 daemon_mode = true。
agent_address = "/run/spire/sockets/agent.sock"
cert_dir = "/var/run/secrets/anthropic.com"
daemon_mode = true
jwt_svids = [{
jwt_audience = "https://api.anthropic.com"
jwt_svid_file_name = "token"
}]在 Kubernetes 中,将 spiffe-helper 作为边车容器运行,与您的应用程序容器共享一个内存支持的 emptyDir 卷(medium: Memory),这样持有者 SVID 就永远不会落到节点的磁盘上。将主机上的 SPIRE Agent 套接字挂载到边车中,在两个容器中都将共享卷挂载到 /var/run/secrets/anthropic.com,并在应用程序容器上设置 ANTHROPIC_IDENTITY_TOKEN_FILE=/var/run/secrets/anthropic.com/token。在虚拟机和裸机上,将 spiffe-helper 作为系统服务与工作负载一起运行,并将两者指向一个共享目录。
按照设置演练在 Claude Console 中注册联合颁发者、创建 Anthropic 服务账户并创建联合规则。使用以下特定于 SPIFFE 的值。
联合颁发者: 以 discovery 模式注册 OIDC Discovery Provider 的公共 URL。Anthropic 从此 URL 获取 /.well-known/openid-configuration,并跟随返回的 jwks_uri 检索信任域的签名密钥。
{
"name": "spire-prod",
"issuer_url": "https://oidc-discovery.prod.example.com",
"jwks": { "type": "discovery" }
}如果发现提供程序无法从公共互联网访问,请自行获取 JWKS(curl https://oidc-discovery.prod.example.com/keys),并使用返回的 keys 数组的内容以 "jwks": {"type": "inline", "keys": [...]} 注册颁发者。在 inline 模式下,issuer_url 仅与 JWT-SVID 的 iss 声明进行比较;Anthropic 从不尝试访问它。
SPIRE 会频繁轮换 JWT 签名密钥,默认与 CA 的轮换周期相同(ca_ttl,24 小时)。如果您使用内联 JWKS 而不是发现 URL 注册颁发者,则每次 SPIRE 轮换时都必须更新 JWKS:在工作负载开始使用新密钥之前添加新密钥,并在使用旧密钥签名的令牌过期后删除已被取代的密钥。留在内联 JWKS 中的过时密钥将无限期地保持受信任状态。
要在不暴露公共发现端点的情况下自动更新 JWKS,请配置一个 SPIRE Server BundlePublisher 插件(aws_s3、gcp_cloudstorage 或 k8s_configmap),设置 format = "jwks",以便在每次轮换时将 JWT 签名密钥推送到外部存储,然后将其同步到颁发者的内联密钥中。
联合规则: 匹配 JWT-SVID 的 sub(即 SPIFFE ID)和您配置 spiffe-helper 请求的 aud。SPIFFE ID 是 URI 字符串,subject_prefix 将它们作为不透明文本进行匹配,因此精确值或尾部带 * 的前缀匹配都适用。对于更复杂的模式,请使用 CEL condition。
{
"name": "spire-inference-worker",
"issuer_id": "fdis_...",
"match": {
"subject_prefix": "spiffe://prod.example.com/ns/inference/sa/worker",
"audience": "https://api.anthropic.com"
},
"target": {
"type": "service_account",
"service_account_id": "svac_..."
},
"workspace_id": "wrkspc_...",
"oauth_scope": "workspace:developer",
"token_lifetime_seconds": 600
}尽可能根据工作负载的情况进行精确匹配。仅当在该路径下注册的每个工作负载都应映射到同一个 Anthropic 服务账户时,才将 subject_prefix 放宽为 spiffe://prod.example.com/ns/inference/*。将规则的 fdrl_... ID 添加到工作负载的 ANTHROPIC_FEDERATION_RULE_ID 环境变量中。
Anthropic SDK 可以从 spiffe-helper 维护的文件中读取 JWT-SVID,也可以通过令牌提供程序可调用对象直接调用 SPIFFE Workload API。文件路径是最简单的集成方式,适用于所有 SDK 语言;可调用对象方式无需边车,但需要在您的应用程序语言中有 SPIFFE Workload API 客户端。
在接入 SDK 之前,直接从 SPIRE Agent 获取 JWT-SVID,并确认声明与您的联合规则所期望的内容匹配。如果您使用其他 SPIFFE 实现,请使用其 CLI 或 Workload API 客户端获取 JWT-SVID,并以相同方式解码负载。
Workload API 会对调用进程进行证明。对于 Kubernetes 注册条目,请在满足该条目选择器且已挂载代理套接字的 Pod 内运行此命令(例如,使用 kubectl exec)。在虚拟机和裸机上,请以匹配条目 unix: 选择器的用户或进程身份运行。从未经证明的主机 shell 运行会返回 no identity issued,这是验证步骤中最常见的失败原因。
spire-agent api fetch jwt \
-audience https://api.anthropic.com \
-socketPath /run/spire/sockets/agent.sock \
-output json \
| jq -r '.[0].svids[0].svid' \
| jq -rR 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson'-output json 标志将 SVID 响应和 bundle 响应作为一个包含两个元素的 JSON 数组返回,因此 jq -r '.[0].svids[0].svid' 可提取裸令牌。在没有 -output 的旧版 SPIRE 上,该命令会打印一个带标签的文本块;在这种情况下,将默认输出通过管道传递给 awk '/^[[:space:]]*eyJ/{print $1; exit}' 以提取令牌行。检查 iss 是否为您注册的 OIDC Discovery Provider URL,sub 是否为工作负载的 SPIFFE ID,以及 aud 是否包含 https://api.anthropic.com。然后运行获取并使用令牌中的 cURL 示例;成功的交换会返回一个以 sk-ant-oat01- 开头的 access_token。如果出现 400 invalid_grant,请参阅排查交换失败问题;SPIRE 端最常见的原因是 SPIRE Server 的 jwt_issuer 与注册为联合颁发者的 URL 不匹配。
SPIFFE ID 路径约定由操作员定义,因此联合规则的 subject_prefix 匹配器应反映您的注册条目所使用的路径方案。常见方案包括 spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>(spire-controller-manager 中 ClusterSPIFFEID 资源发出的默认值)以及用于虚拟机和裸机工作负载的 spiffe://<trust-domain>/host/<hostname>/<service>。
subject_prefix 为 spiffe://prod.example.com/* 会匹配信任域中的每个工作负载。如果没有 audience 匹配器,该规则还会接受为任何受众生成的 JWT-SVID,包括工作负载为不相关的依赖方请求的那些。
将规则的 match 块锁定到适合您用例的最窄范围:
subject_prefix 设置为完整的 SPIFFE ID,不带尾部 *。audience,并使用相同的值配置 spiffe-helper(或 Workload API 调用),以便拒绝为其他依赖方生成的 SVID。spiffe://prod.example.com/ns/inference/* 授权在某个命名空间下注册的每个工作负载,并为每个命名空间创建单独的规则和 Anthropic 服务账户,而不是扩大单个规则的范围。Was this page helpful?