JWT authentication not working when spring boot app deployed to kubernetes cluster with nginix controller

10/15/2019

I have a Spring boot app with end point POST /login which validates the credentials and returns the JWT in the response header. There is another endpoint /api/cars/listing which requires Authorization header with valid JWT. This app is deployed to a Kubernetes cluster with 3 nodes. After that I have installed ngnix ingress controller for L7 routing within the cluster and added the ingress resource.

Followed this tutorial - https://cloud.google.com/community/tutorials/nginx-ingress-gke.

When I use the JWT generated from POST /login and use it for GET /api/cars/listings I am getting 403 error in the response. Is there anything that I need to configure in the Nginx ingress controller for routing the request to the same node based on the request IP?

kind: Ingress
metadata:
  name: ingress-resource
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
 rules:
 - http:
    paths:
     - path: /jwt(/|$)(.*)
       backend:
        serviceName: jwt-app-service
        servicePort: 80

POST /jwt/login

GET /jwt/api/cars/listings

-- anusha rampally
jwt
kubernetes
kubernetes-ingress
nginx-ingress
spring-boot

1 Answer

10/15/2019

After looking at the kubectl logs, found the issue was related to JWT secret key generation. Everytime the spring boot app restarted the secret key got dynamically generated.

I was using Keys.secretKeyFor(SignatureAlgorithm.HS512); in the Spring config file as below. This could be configured as deployment env variable or in some other secured way.

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  private final JwtTokenService jwtTokenService;

  private AppUserDetailsService appUserDetailsService;

  @Autowired
  public SecurityConfig(AppUserDetailsService appUserDetailsService) {
    this.jwtTokenService = jwtTokenService();
    this.appUserDetailsService = appUserDetailsService;
  }

  public SecurityConfig() {
    this.jwtTokenService = jwtTokenService();
  }

  private Key base64EncodedSecretKey() {
    return Keys.secretKeyFor(SignatureAlgorithm.HS512);
  }


  private JwtTokenService jwtTokenService() {
    return new JwtTokenService(base64EncodedSecretKey());
  }


  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(this.appUserDetailsService)
        .passwordEncoder(NoOpPasswordEncoder.getInstance());
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    http.csrf().disable()
        .authorizeRequests()
        .antMatchers(HttpMethod.GET,"/greetings").permitAll()
        .antMatchers("/login").permitAll()
        .anyRequest()
        .authenticated()
        .and()
        .addFilterBefore(new LoginFilter("/login", this.jwtTokenService, authenticationManager()),
            UsernamePasswordAuthenticationFilter.class)
        .addFilterBefore(new JwtAuthenticationFilter(this.jwtTokenService, "/api/**"), UsernamePasswordAuthenticationFilter.class);


  }
}
-- anusha rampally
Source: StackOverflow