场景:微服务认证的困境

假设你有一个典型的微服务架构:

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)提供:

  1. 统一的身份标识:每个工作负载有唯一的 SPIFFE ID
  2. 自动化的凭证管理:短期 SVID 自动轮换
  3. 跨环境互操作:通过 Trust Bundle 和联邦实现信任传递
  4. 标准化 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:统一身份标识

格式规范

1
spiffe://<trust-domain>/<path>

示例

1
2
3
spiffe://acme.com/ns/default/sa/frontend
spiffe://staging.example.com/service/database
spiffe://prod.example.com/department/engineering/team/backend

设计原则

原则说明
全局唯一同一 Trust Domain 内不能重复
层次化路径/ 分隔,支持任意深度
Trust Domain 隔离不同 Trust Domain 的 ID 相互独立
非敏感信息ID 本身不含密钥,可安全传递

路径语义

路径部分由实现者定义,常见模式:

1
2
3
4
5
6
7
8
# Kubernetes 风格
spiffe://cluster.example.com/ns/<namespace>/sa/<service-account>

# 服务分组
spiffe://prod.example.com/team/backend/service/payment

# 多租户
spiffe://saas.example.com/tenant/<tenant-id>/service/<service-name>

⚠️ 重要:路径是标识符,不是授权策略。授权决策由策略引擎(如 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

命名建议

  • 使用有意义的名称(如 productionstagingaws-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 格式(推荐):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "keys": [
    {
      "kty": "RSA",
      "kid": "production-root-1",
      "use": "x509-svid",
      "x5c": ["MIIB..."],
      "n": "...",
      "e": "AQAB"
    }
  ]
}

PEM 格式

1
2
3
4
5
6
-----BEGIN CERTIFICATE-----
MIIB...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIC...
-----END CERTIFICATE-----

SVID:可验证身份凭证

SVID(SPIFFE Verifiable Identity Document)是绑定了 SPIFFE ID 的凭证

两种类型对比

维度X.509-SVIDJWT-SVID
用途TLS/mTLS、服务间认证HTTP 头、应用层
有效期通常 1-24 小时通常 5-15 分钟
验证方式证书链验证签名验证
撤销CRL/OCSP(不推荐)短期自然过期
性能需要证书解析JWT 直接解析
适用场景服务网格、数据库Web API、浏览器

X.509-SVID

结构

1
2
3
4
5
6
7
Certificate:
    Subject: CN=spiffe://production/ns/default/sa/frontend
   Issuer: CN=Production Intermediate CA
   Validity: 1 hour
Extensions:
    Subject Alternative Name (SAN):
        URI: spiffe://production/ns/default/sa/frontend

关键点

  1. SPIFFE ID 在 SAN 扩展中(URI 类型)
  2. 短期有效:通常 1-24 小时,自动轮换
  3. 包含完整证书链:终端证书 + 中间证书 + 根证书

使用示例(mTLS):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import ssl

context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_cert_chain(
    certfile="/tmp/svid.crt",    # X.509-SVID
    keyfile="/tmp/svid.key"      # 私钥
)
context.load_verify_locations("/tmp/bundle.crt")  # Trust Bundle

# 验证对端证书中的 SPIFFE ID
context.verify_mode = ssl.CERT_REQUIRED

JWT-SVID

结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "header": {
    "alg": "ES256",
    "kid": "production-key-1",
    "typ": "JWT"
  },
  "payload": {
    "sub": "spiffe://production/ns/default/sa/frontend",
    "aud": ["spiffe://production/ns/api/sa/backend"],
    "exp": 1710000000,
    "iat": 1709999900
  },
  "signature": "..."
}

关键声明(Claims)

Claim必需说明
subSPIFFE ID(主题)
aud受众(目标服务 ID)
exp过期时间
iat签发时间

使用示例

1
2
3
GET /api/data HTTP/1.1
Host: backend.example.com
Authorization: Bearer eyJhbGciOiJFUzI1NiIs...

验证逻辑

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import jwt

def verify_jwt_svid(token, expected_audience, bundle):
    # 解码并验证签名
    payload = jwt.decode(
        token,
        key=bundle.public_key,
        algorithms=["ES256"],
        audience=expected_audience
    )
    
    # 验证 SPIFFE ID 格式
    spiffe_id = payload["sub"]
    assert spiffe_id.startswith("spiffe://")
    
    return spiffe_id

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(推荐):

1
export SPIFFE_ENDPOINT_SOCKET=unix:///run/spire/sockets/agent.sock

TCP(受限场景):

1
export SPIFFE_ENDPOINT_SOCKET=tcp://127.0.0.1:8000

安全机制

机制说明
零认证工作负载无需提供密钥即可调用 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。

请求

1
2
3
GET /.well-known/spiffe/bundle HTTP/1.1
Host: prod.example.com
Accept: application/json

响应

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "keys": [
    {
      "kty": "RSA",
      "kid": "prod-root-1",
      "use": "x509-svid",
      "x5c": ["MIIB..."]
    }
  ]
}

Web PKI 集成

Bundle Endpoint 必须使用 Web PKI 证书(Let’s Encrypt 等),因为:

  1. 联邦的初始信任需要从某个根开始
  2. Web PKI 是广泛信任的公共根
  3. 避免手动分发根证书

联邦流程

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 的映射:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "entryId": "entry-123",
  "spiffeId": {
    "trustDomain": "production.example.com",
    "path": "/ns/default/sa/frontend"
  },
  "parentId": "spiffe://production.example.com/nodepool/aws",
  "selectors": [
    {"type": "k8s", "value": "ns:default"},
    {"type": "k8s", "value": "sa:frontend"}
  ],
  "ttl": 3600
}

Selectors 定义了匹配规则:

选择器类型示例说明
k8sns:default,sa:frontendKubernetes ServiceAccount
unixuid:1000Unix UID
dockerlabel:app=frontendDocker 标签
aws_iidaccount:123456789AWS 实例身份

与 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):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from spiffe import WorkloadAPIClient

client = WorkloadAPIClient()
svid = client.fetch_x509_svid()

# 使用 SVID 建立到工具服务的 mTLS 连接
response = requests.post(
    "https://tool-service/api",
    cert=(svid.cert_chain, svid.private_key),
    verify=svid.bundle
)

2. Agent 调用 LLM API(JWT Bearer):

1
2
3
4
5
6
7
8
jwt_svid = client.fetch_jwt_svid(
    audience=["https://api.openai.com"]
)

response = requests.post(
    "https://api.openai.com/v1/chat/completions",
    headers={"Authorization": f"Bearer {jwt_svid.token}"}
)

3. Agent 联邦访问(跨信任域):

1
2
3
4
5
6
7
8
9
# 获取联邦 Bundle
bundles = client.fetch_x509_bundles()

# 使用目标信任域的 Bundle 验证对端
response = requests.get(
    "https://other-domain.example.com/api",
    cert=(svid.cert_chain, svid.private_key),
    verify=bundles["other-domain.example.com"]
)

总结: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

关键限制

  1. 信任根保护:SPIRE Server 私钥泄露影响整个信任域
  2. 网络依赖:Agent 需要与 Server 通信
  3. 引导问题:初始信任建立需要外部机制(Web PKI 或手动分发)
  4. 撤销延迟:X.509 撤销列表传播有延迟(推荐用短期证书规避)

参考资源