场景:微服务认证的困境
假设你有一个典型的微服务架构:
flowchart LR
A[Service A] --> B[Service B]
B --> C[Service C]
A --> D[Database / Cache]
B --> D
C --> D
style A fill:#1565C0,color:#fff
style B fill:#1565C0,color:#fff
style C fill:#1565C0,color:#fff
style D fill:#228B22,color:#fff
问题:Service B 如何验证请求确实来自 Service A,而非攻击者?
传统方案的局限
| 方案 | 问题 |
|---|---|
| API Key | 静态、长期有效、难以轮换、泄露影响大 |
| 密码 | 需要安全存储、分发困难 |
| IP 白名单 | 动态环境中 IP 不固定、伪造风险 |
| 服务网格 TLS | 依赖基础设施,不跨环境 |
核心矛盾:我们需要一种动态的、短期的、自动轮换的、跨环境的身份机制。
SPIFFE 的答案
SPIFFE(Secure Production Identity Framework for Everyone)提供:
- 统一的身份标识:每个工作负载有唯一的 SPIFFE ID
- 自动化的凭证管理:短期 SVID 自动轮换
- 跨环境互操作:通过 Trust Bundle 和联邦实现信任传递
- 标准化 API:Workload API 提供语言无关的身份服务
核心概念速览
flowchart TB
subgraph 信任域["Trust Domain (信任域)"]
TD["trust-domain: production"]
end
subgraph 工作负载["Workload (工作负载)"]
W1["Service A
ns: default"]
W2["Service B
ns: api"]
end
subgraph 身份标识["SPIFFE ID (身份标识)"]
ID1["spiffe://production/ns/default/sa/service-a"]
ID2["spiffe://production/ns/api/sa/service-b"]
end
subgraph 凭证["SVID (身份凭证)"]
S1["X.509-SVID
短期证书"]
S2["JWT-SVID
身份令牌"]
end
TD --> ID1
TD --> ID2
W1 --> ID1
W2 --> ID2
ID1 --> S1
ID1 --> S2
style TD fill:#1565C0,color:#fff
style ID1 fill:#228B22,color:#fff
style ID2 fill:#228B22,color:#fff
style S1 fill:#5E35B1,color:#fff
style S2 fill:#5E35B1,color:#fff
| 概念 | 类比 | 说明 |
|---|---|---|
| SPIFFE ID | 身份证号 | 全局唯一的工作负载标识符 |
| Trust Domain | 发行国 | 定义信任边界,所有 ID 属于某个信任域 |
| SVID | 身份证 | 可验证的身份凭证(X.509 证书或 JWT) |
| Workload API | 办证大厅 | 工作负载获取身份的标准化接口 |
SPIFFE ID:统一身份标识
格式规范
| |
示例:
| |
设计原则
| 原则 | 说明 |
|---|---|
| 全局唯一 | 同一 Trust Domain 内不能重复 |
| 层次化路径 | / 分隔,支持任意深度 |
| Trust Domain 隔离 | 不同 Trust Domain 的 ID 相互独立 |
| 非敏感信息 | ID 本身不含密钥,可安全传递 |
路径语义
路径部分由实现者定义,常见模式:
| |
⚠️ 重要:路径是标识符,不是授权策略。授权决策由策略引擎(如 OPA)基于 ID 做出。
Trust Domain 与 Trust Bundle
Trust Domain
定义:信任域是一个管理边界,代表一组共享信任根的工作负载。
flowchart TB
subgraph TD1["Trust Domain: production
spiffe://production/..."]
A1[Service A]
A2[Service B]
A3[Service C]
end
subgraph TD2["Trust Domain: staging
spiffe://staging/..."]
B1[Service D]
B2[Service E]
end
style TD1 fill:#1565C0,color:#fff
style TD2 fill:#5E35B1,color:#fff
style A1 fill:#228B22,color:#fff
style A2 fill:#228B22,color:#fff
style A3 fill:#228B22,color:#fff
style B1 fill:#228B22,color:#fff
style B2 fill:#228B22,color:#fff
命名建议:
- 使用有意义的名称(如
production、staging、aws-us-east-1) - 避免使用 IP 地址或易变信息
- 推荐使用反向域名(如
prod.example.com)
Trust Bundle
定义:Trust Bundle 是一组公钥证书(X.509),用于验证某 Trust Domain 内 SVID 的真实性。
flowchart TB
subgraph Bundle["Trust Bundle (production)"]
C1["Root CA Certificate #1
Subject: CN=Production Root CA
Valid: 10 years"]
C2["Root CA Certificate #2 (轮换中)
Subject: CN=Production Root CA 2
Valid: 10 years"]
end
style Bundle fill:#1565C0,color:#fff
style C1 fill:#228B22,color:#fff
style C2 fill:#228B22,color:#fff
关键特性:
| 特性 | 说明 |
|---|---|
| 只包含公钥 | 不含私钥,可安全分发 |
| 支持轮换 | 可包含多个根证书,支持平滑过渡 |
| 可分发 | 通过 Bundle Endpoint 或联邦协议分发 |
Bundle 格式
JWK Set 格式(推荐):
| |
PEM 格式:
| |
SVID:可验证身份凭证
SVID(SPIFFE Verifiable Identity Document)是绑定了 SPIFFE ID 的凭证。
两种类型对比
| 维度 | X.509-SVID | JWT-SVID |
|---|---|---|
| 用途 | TLS/mTLS、服务间认证 | HTTP 头、应用层 |
| 有效期 | 通常 1-24 小时 | 通常 5-15 分钟 |
| 验证方式 | 证书链验证 | 签名验证 |
| 撤销 | CRL/OCSP(不推荐) | 短期自然过期 |
| 性能 | 需要证书解析 | JWT 直接解析 |
| 适用场景 | 服务网格、数据库 | Web API、浏览器 |
X.509-SVID
结构:
| |
关键点:
- SPIFFE ID 在 SAN 扩展中(URI 类型)
- 短期有效:通常 1-24 小时,自动轮换
- 包含完整证书链:终端证书 + 中间证书 + 根证书
使用示例(mTLS):
| |
JWT-SVID
结构:
| |
关键声明(Claims):
| Claim | 必需 | 说明 |
|---|---|---|
sub | ✅ | SPIFFE ID(主题) |
aud | ✅ | 受众(目标服务 ID) |
exp | ✅ | 过期时间 |
iat | ❌ | 签发时间 |
使用示例:
| |
验证逻辑:
| |
Workload API:身份服务的标准化接口
设计理念
核心问题:工作负载如何获取 SVID?
传统方式的问题:
- 需要提前分发证书文件
- 证书过期需要手动更新
- 不同环境实现方式不同
SPIFFE 的解决方案:Workload API
sequenceDiagram
participant Workload as 工作负载
participant Agent as SPIFFE Agent
(Workload API)
participant Server as SPIFFE Server
Workload->>Agent: 1. FetchX509SVID()
Note over Agent: 验证工作负载身份
(内核 introspection/编排器)
Agent->>Server: 2. 申请 SVID
Server->>Agent: 3. 签发 X.509-SVID
Agent->>Workload: 4. 返回 SVID + 私钥 + Trust Bundle
Note over Workload: 使用 SVID 进行 mTLS
API 方法
| 方法 | 作用 | 返回内容 |
|---|---|---|
FetchX509SVID | 获取 X.509 凭证 | 证书 + 私钥 + Trust Bundle |
FetchX509Bundles | 获取 Trust Bundle | 所有可信根证书 |
FetchJWTSVID | 获取 JWT 凭证 | JWT Token |
FetchJWTBundles | 获取 JWT 验证密钥 | JWK Set |
ValidateJWTSVID | 验证 JWT | 验证结果 |
访问方式
Unix Domain Socket(推荐):
| |
TCP(受限场景):
| |
安全机制
| 机制 | 说明 |
|---|---|
| 零认证 | 工作负载无需提供密钥即可调用 API |
| 带外验证 | Agent 通过内核/编排器识别调用者身份 |
| 本地绑定 | 仅监听 Unix Socket 或 localhost |
| SSRF 防护 | 必须携带 workload.spiffe.io: true 元数据 |
认证流程:
flowchart LR
A[工作负载调用 API] --> B{Agent 识别调用者}
B -->|Unix Socket| C[内核查找
PID/UID]
B -->|Kubernetes| D[查询 Pod
ServiceAccount]
B -->|TCP| E[IP 地址映射]
C --> F[匹配注册条目]
D --> F
E --> F
F --> G[返回对应 SVID]
SPIFFE 联邦:跨信任域通信
场景
flowchart LR
subgraph TD1["Trust Domain: prod"]
A1["spiffe://prod/..."]
end
subgraph TD2["Trust Domain: aws"]
A2["spiffe://aws/..."]
end
TD1 -->|"联邦 mTLS"| TD2
style TD1 fill:#1565C0,color:#fff
style TD2 fill:#5E35B1,color:#fff
核心问题:如何建立信任?
核心思路:信任域之间交换 Trust Bundle。
flowchart LR
subgraph TD1["Trust Domain: prod"]
B1["Trust Bundle A"]
S1["Server A"]
end
subgraph TD2["Trust Domain: aws"]
B2["Trust Bundle B"]
S2["Server B"]
end
S1 -->|"Bundle Endpoint"| B2
S2 -->|"Bundle Endpoint"| B1
TD1 -->|"联邦 mTLS"| TD2
Bundle Endpoint
定义:一个 HTTPS 端点,暴露 Trust Bundle。
请求:
| |
响应:
| |
Web PKI 集成
Bundle Endpoint 必须使用 Web PKI 证书(Let’s Encrypt 等),因为:
- 联邦的初始信任需要从某个根开始
- Web PKI 是广泛信任的公共根
- 避免手动分发根证书
联邦流程
sequenceDiagram
participant SvcA as Service A
(prod)
participant AgentA as Agent (prod)
participant BundleEP as Bundle Endpoint
(aws)
participant SvcB as Service B
(aws)
AgentA->>BundleEP: 1. 获取 aws Trust Bundle
BundleEP-->>AgentA: 2. 返回 Bundle
AgentA->>AgentA: 3. 缓存 Bundle
SvcA->>AgentA: 4. FetchX509Bundles()
AgentA-->>SvcA: 5. 返回 prod + aws Bundles
SvcA->>SvcB: 6. mTLS 连接(使用 aws Bundle 验证)
SvcB-->>SvcA: 7. 响应
生产部署架构
SPIRE 架构
SPIRE 是 SPIFFE 的生产级实现:
flowchart TB
subgraph 控制平面["SPIRE Server (控制平面)"]
S1[Server]
D1[(Data Store)]
end
subgraph 节点1["Node 1"]
A1[Agent]
W1[Workload A]
W2[Workload B]
end
subgraph 节点2["Node 2"]
A2[Agent]
W3[Workload C]
end
S1 -->|SVID 签发| A1
S1 -->|SVID 签发| A2
A1 -->|Workload API| W1
A1 -->|Workload API| W2
A2 -->|Workload API| W3
S1 --> D1
style S1 fill:#1565C0,color:#fff
style A1 fill:#228B22,color:#fff
style A2 fill:#228B22,color:#fff
高可用部署
flowchart TB
LB[Load Balancer]
S1[Server 1]
S2[Server 2]
S3[Server 3]
DS[(Data Store
PostgreSQL)]
LB --> S1
LB --> S2
LB --> S3
S1 <--> S2
S2 <--> S3
S1 <--> S3
S1 --> DS
S2 --> DS
S3 --> DS
style LB fill:#B22222,color:#fff
style S1 fill:#1565C0,color:#fff
style S2 fill:#1565C0,color:#fff
style S3 fill:#1565C0,color:#fff
style DS fill:#228B22,color:#fff
注册条目(Registration Entry)
定义工作负载与 SPIFFE ID 的映射:
| |
Selectors 定义了匹配规则:
| 选择器类型 | 示例 | 说明 |
|---|---|---|
k8s | ns:default,sa:frontend | Kubernetes ServiceAccount |
unix | uid:1000 | Unix UID |
docker | label:app=frontend | Docker 标签 |
aws_iid | account:123456789 | AWS 实例身份 |
与 AI Agent 的关系
为什么 AI Agent 需要 SPIFFE?
根据 IETF draft-klrc-aiagent-auth-00,AI Agent 被定义为工作负载:
| 传统应用 | AI Agent |
|---|---|
| 用户身份驱动 | 工作负载身份驱动 |
| 长期会话 | 异步、长时间运行 |
| 单一环境 | 跨多个服务/域 |
SPIFFE 为 Agent 提供的能力
flowchart TB
subgraph Agent运行时["AI Agent Runtime"]
A[Agent 进程]
end
subgraph SPIFFE层["SPIFFE Identity Layer"]
WAPI[Workload API]
SVID[X.509-SVID]
JWT[JWT-SVID]
end
subgraph 外部服务["External Services"]
LLM[LLM API]
Tools[Tool Services]
DB[Databases]
end
A -->|获取身份| WAPI
WAPI --> SVID
WAPI --> JWT
A -->|mTLS| Tools
A -->|JWT Bearer| LLM
A -->|mTLS| DB
style A fill:#1565C0,color:#fff
style WAPI fill:#228B22,color:#fff
集成模式
1. Agent 访问工具服务(mTLS):
| |
2. Agent 调用 LLM API(JWT Bearer):
| |
3. Agent 联邦访问(跨信任域):
| |
总结:SPIFFE 设计哲学
核心原则
| 原则 | 体现 |
|---|---|
| 零信任 | 不依赖网络边界,每个工作负载独立身份 |
| 自动化 | SVID 自动轮换,无需人工干预 |
| 可移植 | 标准化 API,跨环境一致体验 |
| 最小权限 | 短期凭证,自然过期 |
技术栈
| 组件 | 标准化程度 | 实现选择 |
|---|---|---|
| SPIFFE ID | ✅ 规范 | 统一格式 |
| Trust Domain | ✅ 规范 | 命名约定 |
| Trust Bundle | ✅ 规范 | JWK Set / PEM |
| X.509-SVID | ✅ 规范 | 标准 X.509 |
| JWT-SVID | ✅ 规范 | 标准 JWT |
| Workload API | ✅ 规范 | gRPC |
| Server 实现 | ⚠️ 未规范 | SPIRE、Istio、AWS App Mesh |
关键限制
- 信任根保护:SPIRE Server 私钥泄露影响整个信任域
- 网络依赖:Agent 需要与 Server 通信
- 引导问题:初始信任建立需要外部机制(Web PKI 或手动分发)
- 撤销延迟:X.509 撤销列表传播有延迟(推荐用短期证书规避)