# 第二十二章:WIMSE — 多系统环境中的工作负载身份 > "当工作负载跨越多个系统边界时,身份不应该在途中丢失。" ```{mermaid} mindmap root((WIMSE)) 背景 IETF 工作组 跨系统身份 与 SPIFFE 互补 核心概念 WIT Txn-Token Token Exchange 应用场景 多云 SaaS-to-SaaS 混合云 与现有标准 OAuth 2.0 SPIFFE OIDC ``` ## 22.1 WIMSE 是什么 WIMSE(Workload Identity in Multi-System Environments)是 IETF 正在制定的标准,解决**跨系统环境中工作负载身份传递**的问题。 ### 为什么需要 WIMSE SPIFFE 解决了"工作负载如何获得身份"的问题,但在复杂的多系统调用链中,还有未解决的问题: ``` 问题场景:跨系统调用链 用户 → Service A → Service B → Service C → Database (AWS) (GCP) (Azure) 1. Service A 有 AWS 的身份(IAM Role) 2. Service B 有 GCP 的身份(Service Account) 3. Service C 有 Azure 的身份(Managed Identity) 问题: - Service C 如何知道这个请求最初来自哪个用户? - Service B 如何向 Service C 证明"我是代表 Service A 调用的"? - 如何防止 Confused Deputy 攻击? ``` ## 22.2 核心概念 ### Workload Identity Token(WIT) WIT 是基于 JWT 的工作负载身份令牌,标识工作负载自身的身份: ```json { "iss": "https://issuer.example.com", "sub": "spiffe://example.com/service-a", "aud": "spiffe://example.com/service-b", "exp": 1709510400, "iat": 1709506800, "jti": "unique-token-id", "cnf": { "kid": "key-binding-id" } } ``` ### Transaction Token(Txn-Token) Txn-Token 在调用链中传递,记录完整的调用上下文: ```json { "iss": "https://txn-token-service.example.com", "iat": 1709506800, "aud": "https://api.example.com", "txn": "txn-abc-123", "sub": { "format": "oidc_id_token", "iss": "https://idp.example.com", "sub": "user-alice" }, "rctx": { "req_ip": "192.168.1.100", "req_method": "POST", "req_path": "/api/transfer" }, "purp": "transfer_funds" } ``` ``` Txn-Token 在调用链中的传递: 用户 ──▶ Service A ──▶ Service B ──▶ Service C │ │ │ │ 创建 │ 传递 │ 验证 │ Txn-Token │ Txn-Token │ Txn-Token │ │ │ ▼ ▼ ▼ 包含用户身份 包含调用链上下文 知道请求来源 和请求目的 和中间服务身份 可以做授权决策 ``` ### Token Exchange(RFC 8693) Token Exchange 允许工作负载将一种 Token 交换为另一种: ``` ┌──────────┐ ┌──────────────┐ ┌──────────┐ │ Service A │───▶│ Token Exchange│───▶│ Service B │ │ (AWS) │ │ Service │ │ (GCP) │ │ │ │ │ │ │ │ 持有: │ │ AWS Token │ │ 需要: │ │ AWS IAM │───▶│ → GCP Token │───▶│ GCP SA │ │ Token │ │ │ │ Token │ └──────────┘ └──────────────┘ └──────────┘ ``` ```python import httpx async def exchange_token( subject_token: str, subject_token_type: str, target_audience: str, ) -> str: """OAuth 2.0 Token Exchange (RFC 8693)""" async with httpx.AsyncClient() as client: response = await client.post( "https://token-exchange.example.com/token", data={ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token": subject_token, "subject_token_type": subject_token_type, "requested_token_type": "urn:ietf:params:oauth:token-type:access_token", "audience": target_audience, } ) return response.json()["access_token"] # 将 SPIFFE JWT-SVID 交换为目标系统的 Token new_token = await exchange_token( subject_token=spiffe_jwt_svid, subject_token_type="urn:ietf:params:oauth:token-type:jwt", target_audience="spiffe://gcp.example.com/service-b", ) ``` ## 22.3 Confused Deputy 攻击 ``` 正常流程: 用户 Alice ──▶ Service A ──▶ Service B (有权限) (执行操作) Confused Deputy 攻击: 攻击者 Eve ──▶ Service A ──▶ Service B (被欺骗) (用 A 的权限执行) Service A 被"迷惑"了,用自己的身份帮攻击者执行了操作。 Txn-Token 的防御: 攻击者 Eve ──▶ Service A ──▶ Service B 创建 Txn-Token 检查 Txn-Token 记录 Eve 的身份 发现请求者是 Eve 拒绝!❌ ``` ## 22.4 WIMSE 与现有标准的关系 | 标准 | 解决的问题 | WIMSE 的关系 | |------|-----------|-------------| | SPIFFE | 工作负载如何获得身份 | 互补:WIMSE 传递 SPIFFE 身份 | | OAuth 2.0 | 委托授权 | 扩展:Token Exchange | | OIDC | 用户身份认证 | 集成:Txn-Token 携带用户身份 | | mTLS | 传输层身份验证 | 补充:应用层身份传递 | ## 22.5 应用场景 ### 多云环境 ``` AWS 服务 ──(WIT)──▶ Token Exchange ──(WIT)──▶ GCP 服务 spiffe://aws.../a AWS→GCP Token转换 spiffe://gcp.../b ``` ### SaaS-to-SaaS ``` SaaS A ──(Txn-Token)──▶ SaaS B 用户在 A 中触发操作 B 知道请求来自 A 的用户 可以做细粒度授权 ``` ## 22.6 小结 - **WIMSE** 解决跨系统环境中的工作负载身份传递问题 - **WIT** 标识工作负载自身身份,**Txn-Token** 传递调用链上下文 - **Token Exchange** 实现跨系统的 Token 转换 - WIMSE 与 SPIFFE **互补**:SPIFFE 提供身份,WIMSE 传递身份 - **Confused Deputy** 攻击是 WIMSE 要解决的核心安全问题 - WIMSE 标准仍在 IETF 制定中,但核心概念已经清晰