<p>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. </p>

<p>Followed this tutorial - <a href="https://cloud.google.com/community/tutorials/nginx-ingress-gke" rel="nofollow noreferrer">https://cloud.google.com/community/tutorials/nginx-ingress-gke</a>. </p>

<p>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?</p>

<pre><code>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
</code></pre>

<p>POST /jwt/login</p>

<p>GET /jwt/api/cars/listings</p>

<p>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.  </p>

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

<pre><code>@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);


  }
}
</code></pre>
