本文为 SPIFFE 官方规范 The JWT SPIFFE Verifiable Identity Document 的中文译本,仅供学习参考;若与英文原文有出入,以英文版为准。
JWT SPIFFE 可验证身份文档
稳定性:Stable(稳定) - 参见 STABILITY.md。
本备忘录的状态 (Status of this Memo)
本文档为互联网社区规定了一项身份文档标准,并征求各方对其改进的讨论与建议。本文档的分发不受限制。
1. 引言
JWT-SVID 是 SPIFFE 规范集中的第一种基于令牌(token)的 SVID。它旨在为解决跨第 7 层(Layer 7)边界断言身份所带来的难题提供即时价值,因此与现有应用程序和库的兼容性是一项核心要求。
JWT-SVID 就是应用了少量限制的标准 JWT 令牌。JOSE 在历史上一直难以安全地实现,在安全社区中赢得了这样一种名声:它是一项很可能在其部署与实现中引入漏洞的技术。JWT-SVID 采取了一些措施,在不破坏与现有应用程序和库兼容性的前提下,尽可能合理地缓解这些问题。
JWT-SVID 是采用 JWS Compact Serialization(紧凑序列化)的 JSON Web 签名(JSON Web Signature,JWS)数据结构,在所有情况下均是如此。禁止(MUST NOT)使用 JWS JSON Serialization。
2. JOSE 头 (JOSE Header)
历史上,JOSE 头的加密敏捷性(cryptographic agility)所引入的复杂性,导致了流行 JWT 实现中的一系列漏洞。为避免此类陷阱,本规范限制了最初给予的一些许可。本节描述所允许的已注册头(registered header)及其取值。此处未描述的任何头,无论是已注册的还是私有的,都禁止(MUST NOT)被包含在 JWT-SVID 的 JOSE 头中。
仅支持 JWS。
2.1. 算法 (Algorithm)
alg 头必须(MUST)被设置为 RFC 7518 第 3.3、3.4 或 3.5 节中所定义的取值之一。收到 alg 参数被设置为其他取值的令牌时,验证方(validator)必须(MUST)拒绝该令牌。
所支持的 alg 取值为:
alg 参数值 | 数字签名算法 |
|---|---|
| RS256 | RSASSA-PKCS1-v1_5 using SHA-256 |
| RS384 | RSASSA-PKCS1-v1_5 using SHA-384 |
| RS512 | RSASSA-PKCS1-v1_5 using SHA-512 |
| ES256 | ECDSA using P-256 and SHA-256 |
| ES384 | ECDSA using P-384 and SHA-384 |
| ES512 | ECDSA using P-521 and SHA-512 |
| PS256 | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 |
| PS384 | RSASSA-PSS using SHA-384 and MGF1 with SHA-384 |
| PS512 | RSASSA-PSS using SHA-512 and MGF1 with SHA-512 |
2.2. 密钥 ID (Key ID)
kid 头是可选的。
2.3. 类型 (Type)
typ 头是可选的。若设置,其值必须(MUST)为 JWT 或 JOSE。
3. JWT 声明 (JWT Claims)
JWT-SVID 规范并未引入任何新的声明(claim),但它确实对 RFC 7519 所定义的已注册声明(registered claim)施加了一些限制。本文档未描述的已注册声明,以及私有声明(private claim),可以(MAY)由实现者自行酌情使用。但应当注意,依赖此处未定义的声明可能会影响互操作性,因为生产方与消费方应用程序必须各自独立地就此达成一致。实现者在引入额外声明时应保持谨慎,并仔细考量其对 SVID 互操作性的影响,尤其是在实现者无法同时控制生产方与消费方的环境中。如果确有必要使用额外声明,则应按照 RFC 7519 的建议使其具备抗碰撞性(collision-resistant)。
本节概述 JWT-SVID 规范对现有已注册声明所施加的要求与限制。
3.1. 主体 (Subject)
sub 声明必须(MUST)被设置为该令牌所签发给的工作负载(workload)的 SPIFFE ID。这是断言工作负载身份所依据的主要声明。
3.2. 受众(audience)
aud 声明必须(MUST)存在,并包含一个或多个值。验证方必须(MUST)拒绝未设置 aud 声明的令牌,或者验证方所认定的取值未作为某个 aud 元素出现的令牌。强烈建议在正常情况下将取值的数量限制为一个。更多信息请参见"安全考量"一节。
所选取的值是站点特定的(site-specific),并且应当(SHOULD)被限定于其预期呈现给的服务范围内。例如,对于呈现给 reports 服务的令牌,reports 或 spiffe://example.org/reports 都是合适的取值。而 production 或 spiffe://example.org/ 之类的取值则不予提倡,因为其范围过于宽泛,一旦 production 中仅仅一个服务被攻陷,便会带来被冒充(impersonation)的可能性。
3.3. 过期时间 (Expiration Time)
exp 声明必须(MUST)被设置,并且验证方必须(MUST)拒绝未包含此声明的令牌。鼓励实现者在合理范围内将有效期(validity period)保持得尽可能短,不过本规范并未对其取值设定任何硬性上限。
4. 令牌签名与验证 (Token Signing and Validation)
JWT-SVID 的签名与验证语义与常规的 JWT/JWS 相同。在处理之前,验证方必须(MUST)确保 alg 头被设置为受支持的取值。
JWT-SVID 签名按照 RFC 7519 section 7 所列的步骤进行计算和验证。aud 与 exp 声明必须(MUST)存在,并按照 RFC 7519 第 4.1.3 与 4.1.4 节进行处理。验证方收到未设置 aud 与 exp 声明的令牌时,必须(MUST)拒绝该令牌。
5. 令牌传输 (Token Transmission)
本节描述 JWT-SVID 从一个工作负载(workload)传输到另一个工作负载的方式。
5.1. 序列化 (Serialization)
JWT-SVID 必须(MUST)使用 RFC 7515 Section 3.1 中所描述的 Compact Serialization(紧凑序列化)方法进行序列化,一如 RFC 7519 Section 1 所要求。请注意,正如 JOSE 头一节所强制规定的,这排除了使用 JWS Unprotected Header(未受保护头)的可能性。
5.2. HTTP
通过 HTTP 传输的 JWT-SVID 应当(SHOULD)使用 RFC 6750 section 2.1 中所定义的 “Bearer” 认证方案,在 “Authorization” 头(HTTP/2 中为 “authorization”)中传输。例如,在 HTTP/1.1 中为 Authorization: Bearer <serialized_token>,在 HTTP/2 中为 authorization: Bearer <serialized_token>。
5.3. gRPC
gRPC 协议使用 HTTP/2。因此,HTTP 一节中的传输指南同样适用。具体而言,gRPC 实现应当(SHOULD)设置一个元数据(metadata)键 authorization,其值为 Bearer <serialized_token>。
6. 在 SPIFFE Bundle 中的表示 (Representation in the SPIFFE Bundle)
本节描述如何将 JWT-SVID 签名密钥发布到 SPIFFE bundle,以及如何从中消费。有关 SPIFFE bundle 的更多信息,请参阅 SPIFFE Trust Domain and Bundle 规范。
6.1. 发布 SPIFFE Bundle 元素 (Publishing SPIFFE Bundle Elements)
对于给定的信任域(trust domain),JWT-SVID 签名密钥在 SPIFFE bundle 中被表示为符合 RFC 7517 的 JWK 条目,每个签名密钥对应一个条目。
每个 JWK 条目的 use 参数必须(MUST)被设置为 jwt-svid。此外,每个 JWK 条目的 kid 参数必须(MUST)被设置。
6.2. 消费 SPIFFE Bundle (Consuming a SPIFFE Bundle)
SPIFFE bundle 可能包含许多不同 SVID 类型的 JWK 条目。实现必须(MUST)在将这些密钥用于验证目的之前,先提取出 JWT-SVID 专用的密钥。表示 JWT-SVID 签名密钥的条目可通过其 use 参数的值来识别,该值必须为 jwt-svid。如果不存在 use 值为 jwt-svid 的条目,则该 bundle 所表示的信任域不支持 JWT-SVID。
一旦提取出这些 JWK 条目,便可按照 RFC 7517 所述,直接将它们用于 JWT-SVID 验证。
7. 安全考量 (Security Considerations)
本节概述实现者与用户在使用 JWT-SVID 时应考虑的安全事项。
7.1. 重放保护 (Replay Protection)
作为一种承载令牌(bearer token),JWT-SVID 易受重放攻击(replay attack)的影响。通过要求设置 aud 与 exp 声明,本规范已采取措施改善这一状况,但在保持与 RFC 7515 验证兼容性的同时,无法将其彻底解决。理解这一风险非常重要。建议为 exp 声明采用一个激进(即较短)的取值。某些用户可能希望利用 jti 声明,尽管这会带来额外的开销。虽然本规范允许使用 jti 声明,但应当注意,JWT-SVID 验证方并不被要求跟踪 jti 的唯一性。
7.2. 受众(audience)
对 JWT-SVID 的接收方存在一种隐含的信任。若存在多个受众,发送给一个受众的令牌可能被重放给另一个受众。例如,如果 Alice 持有一个受众为 Bob 和 Chuck 的令牌,并将该令牌传输给 Chuck,那么 Chuck 便可以通过将同一令牌发送给 Bob 来冒充 Alice。因此,在铸造(mint)带有多个受众的 JWT-SVID 时应格外小心。强烈建议使用单一受众的 JWT-SVID 令牌,以限制可重放的范围。
7.3. 传输安全 (Transport Security)
JWT-SVID 与其他承载令牌(bearer token)方案面临相同的风险,即由于其固有的可重放性,一旦承载令牌被拦截,攻击者便获得了 JWT-SVID 所赋予的全部权限。存在一些用于限制影响的缓解措施,例如通过 exp 声明强制过期,但始终会存在一个易受攻击的时间窗口。因此,传输 JWT-SVID 所经过的通信通道上的所有跳转/链路都应提供机密性(confidentiality)(例如从工作负载到负载均衡器、从负载均衡器到另一个工作负载)。值得注意的例外是那些对暴露风险具有合理安全假设的非网络链路,例如同一主机内两个进程之间的 Unix 域套接字(Unix domain socket)。
附录 A. 验证参考 (Appendix A. Validation Reference)
下表为任何实现 JWT-SVID 验证方的人员提供了一份快速参考。如果使用现成的库,实现者有责任确保采取了以下验证步骤。
此外,请参阅 JWT-SVID Schema 以获取更正式的参考。
| 字段 | 类型 | 要求 |
|---|---|---|
alg | Header | 设置为第 2.1 节表格中的取值之一。否则拒绝。 |
aud | Claim | 至少存在一个值。用户应提前配置至少一个可接受的值。否则拒绝。 |
exp | Claim | 必须被设置。禁止为过去的时间(允许少量宽限)。否则拒绝。 |