前面的文章全部聚焦于”人的身份”——OIDC、SAML、MFA、Passkey
解决的都是”坐在键盘前的人是谁”。但在一个数百微服务的 K8s
集群中,每个服务之间的调用也需要身份。当
order-service 调用 payment-service
时,后者怎么知道”这个请求的确来自
order-service,而不是某个攻入集群内部的进程在伪造”?
这就是 Workload Identity(工作负载身份)——对软件工作负载(不是人)的身份管理。在零信任架构中(参见本站零信任架构篇),Workload Identity 和 User Identity 同等重要。本文从三个技术层面讨论:传输层(mTLS)、平台层(SPIFFE/SPIRE)、应用层(OAuth 2.0 JWT Profile)。
一、mTLS:传输层的服务身份
1.1 基本原理
普通 TLS(单向 TLS)只验证服务端:客户端确认”我连接的是真的 payment-service”。mTLS(双向 TLS)同时也验证客户端:服务端确认”连接我的是真的 order-service”。
sequenceDiagram
participant Client as order-service
participant Server as payment-service
Client->>Server: 1. ClientHello
Server->>Client: 2. ServerHello + Server Certificate (cert.payment)
Client->>Client: 3. 验证 Server Cert (CA 链 + DNS SAN)
Client->>Server: 4. Client Certificate (cert.order)
Server->>Server: 5. 验证 Client Cert (CA 链 + SPIFFE ID)
Server->>Client: 6. TLS 握手完成
Client->>Server: 7. 加密的应用数据
1.2 证书管理与 X.509 扩展
mTLS 的部署难点在证书生命周期管理——不是”怎么签”(OpenSSL 一行命令),而是:
- 签发:谁为新部署的服务签发证书?
- 轮换:证书过期前怎么自动换新?
- 吊销:服务被下线后,它的旧证书怎么被标记为无效?
- 信任域:dev 环境的证书在 prod 环境能用吗?
K8s 生态的 cert-manager(基于 ACME 协议,与 Let’s Encrypt
集成的证书自动管理工具)解决了第 1-2 个问题。对于 mTLS
中的内部证书,cert-manager 可以维护一个内部 CA,为每个 Pod
自动签发短期证书(如 24 小时有效期),并通过
cert-manager-csi-driver 将证书挂载到 Pod
的文件系统或 tmpfs。
X.509 证书的 SAN(Subject Alternative Name)扩展中的 URI
类型是编排系统中最常用的服务身份表达方式。例如:URI:spiffe://cluster.local/ns/payment/sa/payment-sa。
1.3 mTLS 的局限性
mTLS 解决的问题:传输层的身份——确认对方有合法证书。
mTLS 不解决的问题: - 证书管发本身:谁是 CA?CA
信任什么? -
身份模型:证书中的身份怎么映射到”这个服务有权访问这个 API”?
- 应用层授权:mTLS 通过后,order-service 能不能 POST 到
payment-service 的 /refund 端点?
这就是 SPIFFE 和 OAuth 2.0 Token Exchange 进入讨论的原因。
二、SPIFFE/SPIRE:平台层的身份框架
2.1 SPIFFE ID
SPIFFE(Secure Production Identity Framework for Everyone,CNCF Graduated)定义了一种通用的工作负载身份标识格式——SPIFFE ID:
spiffe://trust-domain/ns/namespace/sa/service-account
spiffe://cluster.prod.example.com/ns/payments/sa/payment-processor
URI 结构: - spiffe:// 固定 scheme -
trust-domain:信任域——通常对应一个 K8s
集群或一个组织边界 -
/ns/{namespace}/sa/{service-account}:K8s
工作负载的典型路径。也可以是 /node/{hostname}
或自定义路径
2.2 SPIRE:SPIFFE 的参考实现
SPIRE(SPIFFE Runtime Environment)是 SPIFFE 的 CNCF 参考实现,负责 SPIFFE ID 的发放和验证。
SPIRE 的核心组件:
flowchart TD
SPIRE-Server["SPIRE Server<br/>(集群级别)"]
SPIRE-Agent1["SPIRE Agent<br/>(Node 1)"]
SPIRE-Agent2["SPIRE Agent<br/>(Node 2)"]
Workload1["Pod: payment-service<br/>SA: payment-sa"]
Workload2["Pod: order-service<br/>SA: order-sa"]
SPIRE-Agent1 --> SPIRE-Server
SPIRE-Agent2 --> SPIRE-Server
Workload1 -->|"Workload API (Unix socket)"| SPIRE-Agent1
Workload2 -->|"Workload API (Unix socket)"| SPIRE-Agent2
SPIRE-Agent1 -->|"Node Attestation"| SPIRE-Server
SPIRE-Agent2 -->|"Node Attestation"| SPIRE-Server
Workload1 -.->|"mTLS with SVID"| Workload2
关键概念:
- SVID(SPIFFE Verifiable Identity Document):一个可验证的身份文件——通常是 X.509 证书(含 SPIFFE ID 在 SAN URI 中)或 JWT。
- Node Attestation:SPIRE Agent
在加入集群时向 SPIRE Server
证明”我是一个合法的节点”——通过云平台元数据(AWS
instance-identity-document)、TPM 或手动 token。 - Workload Attestation:SPIRE Agent 在发放 SVID 前验证调用方是真的 workload——通过检查进程的 UID/GID、K8s 的 ServiceAccount token review 或 Unix socket 调用者。
- Workload API:每个 Node 上的 SPIRE Agent 通过 Unix Domain Socket 提供 gRPC API,Pod 通过 Volume 挂载该 socket 来获取 SVID。
2.3 SPIRE 与 Istio/Service Mesh 的关系
SPIRE 和 Istio 不是竞品,是互补的:
- Istio:做流量层(mTLS 加密、负载均衡、路由、可观测)。
- SPIRE:做身份层(身份证明、证书管发、多集群多云的统一信任域)。
Istio 可以配置为使用 SPIRE 作为其 CA,而不是使用 Istio 自带的内置 CA。这样 SPIRE 负责”这个 workload 是谁”,Istio 负责”用这个身份的证书做 mTLS 和鉴权”。
三、OAuth 2.0:应用层的服务身份
mTLS + SPIFFE 解决了传输层和平台层的身份。但很多场景中,服务需要”应用层”的身份令牌——不带 TLS 层的 OAuth 2.0 Access Token,用于调用 REST API 时的 Bearer 认证。
3.1 Client Credentials Grant
最简单的服务间 OAuth 模式:服务作为 OAuth 客户端,用
client_id + client_secret 请求
Access Token。
POST /token
Authorization: Basic base64(client_id:client_secret)
grant_type=client_credentials&scope=payment:write
→ { "access_token": "eyJhbG...", "token_type": "Bearer", "expires_in": 3600 }
Client Credentials Grant 的问题:
- secret 分发:每个服务需要拿到
client_secret——K8s Secret 或 Vault 注入。 - 身份不是 SPIFFE ID:Access Token 中的
sub是 OAuth client 的 ID(如payment-service),不是 SPIFFE ID(spiffe://cluster.local/ns/payment/sa/payment-sa)。如果要让两者对齐,需要在 IdP 层面建立映射。 - 无平台亲和性:同一个
client_secret可以在集群内外、跨云使用——这不是安全漏洞,但在零信任模型中这是”信任面太宽”。
3.2 JWT Profile for OAuth 2.0(RFC 7523)
更好的方案是:服务用它已有的 SVID(SPIFFE 证书或 JWT)来向 OP 换取 OAuth Access Token。这称为 JWT Profile for OAuth 2.0(RFC 7523)。SPIRE 可以生成 JWT-SVID,这个 JWT 本身就是 RFC 7523 格式的 assertion:
POST /token
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion=eyJhbG...jwt_svid...
OP 验证 JWT-SVID:
- 签名(用 SPIRE 信任域的 JWKS)
- issuer (spiffe://cluster.local)
- subject (spiffe://cluster.local/ns/order/sa/order-sa)
- audience (OP 的 token endpoint)
- 有效期
→ { "access_token": "eyJhbG...", "token_type": "Bearer" }
这种方式把平台身份(SPIFFE ID)和 OAuth 令牌链在了一起——Access Token 中可以编码对应的 SPIFFE ID,使得资源服务器能追溯到”调用方到底是哪个 K8s workload”。
四、三种层次的选型
| 层次 | 技术 | 粒度 | 部署复杂度 | 身份信任根 |
|---|---|---|---|---|
| 传输层 | mTLS | 连接 | 高(需要 CA 和证书管发) | TLS 证书的 CA 链 |
| 平台层 | SPIFFE/SPIRE | 工作负载(Pod/进程) | 中-高(需要部署 SPIRE) | 节点证明(云平台/TPM) |
| 应用层 | OAuth 2.0 Client Credentials / JWT Profile | 应用逻辑身份 | 低-中 | OP 的客户端 secret 或 SPIFFE SVID |
工程选择不是一个”选哪个”的问题——三者在零信任架构中是同时需要的:
- mTLS 保证传输加密和连接级别的相互认证。
- SPIFFE/SPIRE 提供平台级别的、可审计的、自动化的身份发行。
- OAuth 2.0 Token Exchange 将平台身份转化为应用可用的 Bearer Token,方便在 HTTP API 中传递。
对于没有 K8s 或 Service Mesh 的小规模部署,Client Credentials Grant + HashiCorp Vault 管理 secret 是务实的起点。
上一篇:风险感知认证:设备信任、异常登录与挑战升级 下一篇:RBAC、ABAC、ReBAC:权限模型怎么选
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【零信任安全架构】mTLS 大规模部署的工程现实:联邦、故障排查与根 CA 轮换
mTLS 是零信任服务间通信的基石,但从'单集群内启用 mTLS'到'全公司多集群、混合云的 mTLS',中间隔着 SPIRE 联邦、跨信任域证书验证、mTLS 握手并发瓶颈、连接池协议兼容性和故障排查等工程问题。本文不重复 SPIFFE/SPIRE 基础,而是聚焦大规模部署中才暴露的问题。
零信任安全架构深度系列
零信任是 IAM 的自然延伸——当身份变成新边界,VPN 的'拨入即信任'模型必须被'永不信任、始终验证'取代。本系列从 NIST SP 800-207 规范、Google BeyondCorp 六篇论文、SPIFFE/SPIRE 联邦到微分段、持续验证、ZTNA 和零信任迁移的工程策略,系统拆解零信任的每一种组件和每一步实施。
【身份与访问控制工程】IAM 全景:为什么这是高价值赛道
从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。
【零信任安全架构】零信任的新兴前沿:AI Agent 身份、边缘计算和量子后的证书
零信任的现状主要服务于'人访问应用'和'服务调用服务'两种模式。但三个新兴场景正在挑战零信任的基本假设:AI Agent 的自主操作、边缘计算的间歇性连接、以及 PQC 对 X.509 证书和 mTLS 握手的冲击。本文展示工程挑战和当前最优实践,不假装有成熟的标准答案。