Kubernetes集群中微服务之间如何进行JWT认证

Posted

技术标签:

【中文标题】Kubernetes集群中微服务之间如何进行JWT认证【英文标题】:How to have JWT authentication between micro services in kubernetes cluster 【发布时间】:2020-03-20 10:53:33 【问题描述】:

我们有 8 个 java 微服务在 kubeneters 集群中相互通信。每个微服务都与 auth 库捆绑在一起,该库拦截并验证/更新对控制器的每个 REST 请求的 JWT 令牌。

场景: 从前端,我们第一次获得访问令牌,身份验证成功。让我们说

    前端使用访问令牌命中“微服务 A” - 成功 “微服务 A”在内部通过 restTemplate 命中“微服务 B”。 我的“微服务 B”还需要登录用户详细信息。

问题:我必须将相同的访问令牌从“A”传递到“B”,但我无法在控制器/服务逻辑中获取访问令牌,但只能在验证令牌的过滤器中获取。我可以通过在控制器的所有休息方法中添加以下参数来在休息控制器中获取令牌:

@RequestHeader (name="Authorization") String token

但我不想采用这种方法,因为我必须将此令牌传递到任何地方直到结束,并且必须在所有 APIS 中声明此参数。

我想通过传递身份验证对象从 TokenStore 获取令牌。我们使用的是 Oauth2,我检查了库中的代码,有很多 tokenStore 提供程序。

在 DefaultTokenServices.java 类中,我正在调用

Authentication auth = SecurityContextHolder.getContext().getAuthentication() // Passed this auth to tokenStore
String token = tokenStore.getAccessToken(auth).getValue(); // NullPointerException

我的代码正在通过返回 null 的 JWTTokenStore 提供程序。我检查了,有一个名为 InMemoryTokenStore.class 的提供程序实际上从存储中提取了令牌。但是我的流程并没有进入内存实现。

有什么方法可以让我事后不通过参数在控制器中获取令牌?或者如何启用/使用 inMemoryTokenStore?

也推荐一些更好的kubernetes互通认证?

TIA

【问题讨论】:

你应该看看OAuth2RestTemplate 本质上,您需要一个 SPIFFE 实现来在您的集群中分发令牌,spiffe.io @Jonas,如果有错误请纠正我,但我的印象是 SPIFFE 仅对服务级别 authN/Z 有用,例如设置 mTLS 会话。另一方面,JWT 可用于用户和/或资源级别的 authN/Z。两者都很有用,但如果 OP 热衷于使用解决方案来验证用户而不仅仅是服务,那么 SPIFFE 可能不是 Q 中提到的 JWT 的实际替代品。 @RoobalJindal 您在 Java 应用程序中使用什么 Web 框架? @GrahamLea Spring 安全框架 - Srpingboot 【参考方案1】:

看起来您正在使用 Spring(和 Spring Security),所以我相信文档的相关部分是 Bearer Token Propagation 上的部分。

它的建议是使用 WebClient(从 Spring 5 开始推荐替换 RestTemplate),它使用提供的 ServletBearerExchangeFilterFunction 自动将 JWT 令牌从传入请求传播到传出请求:

@Bean
public WebClient rest() 
    return WebClient.builder()
            .filter(new ServletBearerExchangeFilterFunction())
            .build();

RestTemplate,文档说:

"目前还没有对 RestTemplate 的专门支持,但是您可以使用自己的拦截器非常简单地实现传播"

并提供以下示例:

@Bean
RestTemplate rest() 
    RestTemplate rest = new RestTemplate();
    rest.getInterceptors().add((request, body, execution) -> 
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) 
            return execution.execute(request, body);
        

        if (!(authentication.getCredentials() instanceof AbstractOAuth2Token)) 
            return execution.execute(request, body);
        

        AbstractOAuth2Token token = (AbstractOAuth2Token) authentication.getCredentials();
        request.getHeaders().setBearerAuth(token.getTokenValue());
        return execution.execute(request, body);
    );
    return rest;

如果您只想传播令牌,我认为您不需要查看TokenStores。请记住,与 JWT 相关的所有内容都应该在令牌本身内。 (这就是为什么the doc for the JwtTokenStore 解释说它实际上并不存储任何东西,而只是从令牌中提取信息,并且会为某些方法返回 null,包括您正在调用的 getAccessToken() 方法。)

【讨论】:

以上是关于Kubernetes集群中微服务之间如何进行JWT认证的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes:我应该使用 HTTPS 在服务之间进行通信吗

Consul集群中微服务重复注册问题填坑

如何验证 Kubernetes 服务帐户令牌 (JWT)

Kubernetes 上微服务之间集群间通信的最佳方式?

Kubernetes如何管理暴露服务

Kubernetes如何管理暴露服务