在集群身份验证服务中存储 RSA 密钥

Storing RSA keys in a clustered authentication service

我想构建一个使用 JWT 和使用 RS256 生成的签名的身份验证服务。在单服务器解决方案中,实现相当简单。但是,当谈到使其成为多节点时,有两个相关问题我没有找到明确的答案:

  1. 在集群解决方案中,每个服务器应该使用自己的密钥对还是可以由多个节点使用共享密钥对?在那种情况下如何有效地构建一个不包含太多密钥的 JWK?

  2. 另一方面,如果可以在不引起重大安全问题的情况下共享私钥,那么共享密钥和管理其轮换的最佳方法是什么?

如果可能 (IMO),您应该使用单个私钥来签署访问令牌。

拥有多个只会增加复杂性(例如,后端资源服务器需要逻辑来计算出用于 JWT 验证的 public 键,或者循环使用多个 public 键来验证一个 JWT),我真的看不到任何安全优势。

FWIW 可能出于业务原因需要在后端支持多个,例如如果您的公司有多个具有单独身份验证的产品 tenants/sign-on-domains,您可能需要在共享后端 services/capabilities 中支持多个密钥 - 对于这种情况,您需要使用诸如令牌发行者之类的东西( iss) 声称要确定用于 JWT 验证的 public 密钥。

WRT旋转键;如果您使用的是像 Auth0 这样的 PaaS IDP,它可能已经为您处理好了。如果您使用的是像 Keycloak 这样的 COTS 产品(或者如果您推出了自己的 IDP),则需要在 JWKS 端点中定义多个 public 密钥(尽管是暂时的)。新密钥将被指定为 'active' 并将用于签署所有后续令牌,而旧密钥将被指定为 'passive' 并且只需要验证在轮换之前颁发的访问令牌并且还没有过期。 注意:一旦使用旧密钥签名的所有访问令牌都过期,您可能可以decommission/remove旧密钥。

Here's a link 到 Keycloak 文档,了解可能有用的旋转密钥。

在您进行 JWT 验证的后端服务中,应缓存与 JWT 上的密钥 ID (kid) 声明相对应的 public 密钥。如果使用新私钥对请求进行签名,则 JWT 应该具有不同的密钥 ID。如果后端服务遇到新的密钥 ID,它应该懒惰地返回到 JWKS 端点以获取与新密钥 ID 关联的 public 密钥(然后也应该将其缓存)。

在大多数常见的编程语言中,都有一些库可以为您处理大部分此类问题,例如我已经使用 Microsoft.AspNetCore.Authentication 包在 .NET Core 中完成了 JWT 验证,我需要做的就是配置一个 Open ID matadata 端点(它引用 JWKS 端点)并且诸如密钥轮换和缓存之类的事情都是透明处理的。