I'm playing with Minikube to deploy a simple spring-boot application you can find here: https://github.com/shopKubernetesSpringboot
minikube v1.9.2 on Ubuntu 18.04
Kubernetes v1.17.0 on Docker 19.03.5 ...
I'm using cors, session, basic auth. It works outside the Minikube cluster (with the embedded spring-boot netty server), but I can't make it work with nginx-ingress.
It is basically two microservices products and cart. Product & cart list (GET) works. But I can't make cart add (POST) work, it always returns the following in the browser:
XHRPOST http://192.168.39.94/cart/add
[HTTP/1.1 403 Forbidden 37ms]
CSRF Token has been associated to this client
The back-end is receiving the X-XSRF-TOKEN
:
[or-http-epoll-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [e8b45b1f-2] HTTP POST "/cart/add", headers=[Host:"192.168.39.94", X-Request-ID:"dc741d2765b9d0c585b7f73d0e2bab95", X-Real-IP:"192.168.39.1", X-Forwarded-For:"192.168.39.1", X-Forwarded-Host:"192.168.39.94", X-Forwarded-Port:"80", X-Forwarded-Proto:"http", X-Scheme:"http", Content-Length:"120", User-Agent:"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0", Accept:"application/json, text/plain, /", Accept-Language:"en-GB,en;q=0.5", Accept-Encoding:"gzip, deflate", Content-Type:"application/json;charset=utf-8", Authorization:"Basic dXNlcjp1c2Vy", X-XSRF-TOKEN:"17e1b013-98b3-4064-8173-bf3af4ce8bc7", Origin:"http://localhost:3000", Referer:"http://localhost:3000/"]
[or-http-epoll-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [e8b45b1f-2] Completed 403 FORBIDDEN, headers=[Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Access-Control-Allow-Origin:"http://localhost:3000", Access-Control-Allow-Credentials:"true", Content-Type:"text/plain", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Content-Type-Options:"nosniff", X-Frame-Options:"DENY", X-XSS-Protection:"1 ; mode=block", Referrer-Policy:"no-referrer", content-length:"45"]
My ingress looks like that:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: shop-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/affinity: cookie
nginx.ingress.kubernetes.io/session-cookie-name: session
nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:3000"
nginx.ingress.kubernetes.io/cors-allow-headers: X-XSRF-TOKEN,Accept,Accept-Encoding,Accept-Language,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Origin,Connection,Content-Length,Content-Type,Host,Referer,User-Agent
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/session-cookie-path: /cart
spec:
rules:
- http:
paths:
- path: /product
backend:
serviceName: product-svc
servicePort: 80
- path: /cart
backend:
serviceName: cart-svc
servicePort: 80
Cart service & pod
apiVersion: v1
kind: Service
metadata:
name: cart-svc
labels:
app: shop
name: cart
tier: backend
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 120
selector:
app: shop
name: cart
tier: backend
ports:
- protocol: TCP
port: 80
targetPort: rest-api-port
---
apiVersion: v1
kind: Pod
metadata:
name: cart-pod
labels:
app: shop
name: cart
tier: backend
spec:
containers:
- name: cart
image: davidgfolch/shop-cart:latest
ports:
- containerPort: 8080
name: rest-api-port
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
SpringSecurityConfig.java
@Configuration
@Slf4j
public class SecurityConfig {
@Value("${com.dgf.shopCart.cors.origins}")
private String corsOrigins;
@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
return http
.csrf().csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()).and()
.cors(c -> c.configurationSource(cors()))
.authorizeExchange()
.anyExchange().authenticated()
.and()
.httpBasic()
.and()
.build();
}
private UrlBasedCorsConfigurationSource cors() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin(corsOrigins);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
With Kubernetes SESSION cookie is not arriving to the back-end (as shown in the logs):
HTTP POST "/cart/add", headers=[Host:"192.168.39.94", X-Request-ID:"aba957e6cc3c8803c1734a2724a75fbf", X-Real-IP:"192.168.39.1", X-Forwarded-For:"192.168.39.1", X-Forwarded-Host:"192.168.39.94", X-Forwarded-Port:"80", X-Forwarded-Proto:"http", X-Scheme:"http", Content-Length:"120", User-Agent:"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0", Accept:"application/json, text/plain, /", Accept-Language:"en-GB,en;q=0.5", Accept-Encoding:"gzip, deflate", Content-Type:"application/json;charset=utf-8", Authorization:"Basic dXNlcjp1c2Vy", X-XSRF-TOKEN:"17e1b013-98b3-4064-8173-bf3af4ce8bc7", Origin:"http://localhost:3000", Referer:"http://localhost:3000/"]
Without Kubernetes they do:
HTTP POST "/cart/add", headers=[Host:"localhost:8080", User-Agent:"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0", Accept:"application/json, text/plain, /", Accept-Language:"en-GB,en;q=0.5", Accept-Encoding:"gzip, deflate", Content-Type:"application/json;charset=utf-8", Authorization:"Basic dXNlcjp1c2Vy", X-XSRF-TOKEN:"17e1b013-98b3-4064-8173-bf3af4ce8bc7", Content-Length:"120", Origin:"http://localhost:3000", Connection:"keep-alive", Referer:"http://localhost:3000/", Cookie:"Idea-c3de9a37=a5f5270f-e0e1-4807-92e2-79c126b768fc; XSRF-TOKEN=17e1b013-98b3-4064-8173-bf3af4ce8bc7; SESSION=eddb22e9-15f7-4b28-a422-36faa8a7f285"]
Any advice? What I'm missing?
I finally found that sticky sessions don't work if not specified spec.host
for nginx-ingress versions prior to v.0.27.0. See pull request.
So it should be updated nginx-ingress to version 0.27.0 to make the above configuration work or set spec.host
and (i hope) enable DNS addon to make it work. Accesing via de host dns name:
spec:
host: myapp.example.com
rules:
- http:
paths:
- path: /product
backend:
serviceName: product-svc
servicePort: 80
- path: /cart
backend:
serviceName: cart-svc
servicePort: 80
Here you can find some related links:
I will be fine-tunning this answer as soon as I get a working version.
#minikube docker-env
#eval $(minikube -p minikube docker-env)
#docker images | grep ingress
#docker pull quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.27.1
#minikube stop && minikube start
#eval $(minikube -p minikube docker-env)
kubectl delete -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.26.1/deploy/static/mandatory.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.27.1/deploy/static/mandatory.yaml
minikube stop && minikube start