Ofir Yahav
Ofir Yahav

Reputation: 121

K8S Ingress controller redirect to the wrong path

I have an Nginx ingress controller running on one k8s namespace, and on another k8s namespace, I defined a pod, a service, and an ingress resource. this is the ingress resource definition:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: general-internal
  rules:
  - host: example.com
    http:
      paths:
      - path: "/my-app(/|$)(.*)"
        backend:
          serviceName: my-app-svc
          servicePort: 443

now, when I access this link:

http://example.com/my-app/some-path/

then everything is ok because the "my-app-svc" knows the path "/some-path/" and returns a 200 response (the forwarding is to http://my-app-svc/some-path and that's great because my-app-svc doesn't and shouldn't know or care for the /my-app prefix that exists only for the nginx ingress controller so it will know to forward that request to "my-app-svc" internally).

but when I access this link (notice no "/" in the end):

http://example.com/my-app/some-path

I get a redirection response from the "my-app-svc" service, and the "Location" header contains "/some-path/", so the redirection is to:

http://example.com/some-path/

which does not lead to the "my-app-svc" service because it doesn't have the "/my-app" prefix.

If the Location header was "/my-app/some-path/" instead of "/some-path/" then everything was ok because the redirection would be to:

http://example.com/my-app/some-path/

which would give me the 200 response.

the question is, how can I do that the ingress controller will add a "my-app" prefix to the Location header when it returns the redirection response to the client?

Thanks

Upvotes: 1

Views: 3730

Answers (2)

Villtord
Villtord

Reputation: 56

For anyone landing here and finding the above solution not working (like myself), you might be using nginx-based ingress https://www.nginx.com/blog/guide-to-choosing-ingress-controller-part-4-nginx-ingress-controller-options/ which needs different annotation to your ingress resource:

nginx.org/rewrites: "serviceName=service1 rewrite=rewrite1[;serviceName=service2 rewrite=rewrite2;...]"

which worked for me.

A complete declaration from https://github.com/nginxinc/kubernetes-ingress/tree/v2.3.0/examples/rewrites copied here:

apiVersion: networking.k8s.io/v1 
kind: Ingress
metadata:
  name: cafe-ingress
  annotations:
    nginx.org/rewrites: "serviceName=tea-svc rewrite=/;serviceName=coffee-svc rewrite=/beans/"
spec:
  rules:
  - host: cafe.example.com
    http:
      paths:
      - path: /tea/
        pathType: Prefix
        backend:
          service:
            name: tea-svc
            port:
              number: 80
      - path: /coffee/
        pathType: Prefix
        backend:
          service:
            name: coffee-svc
            port:
              number: 80

Upvotes: 0

Ofir Yahav
Ofir Yahav

Reputation: 121

Thanks to my co-worker, we found a solution for the problem:

The solution is to add these annotations to the ingess resource:

nginx.ingress.kubernetes.io/proxy-redirect-from: /
nginx.ingress.kubernetes.io/proxy-redirect-to: /my-app/

meaning:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/proxy-redirect-from: /
    nginx.ingress.kubernetes.io/proxy-redirect-to: /my-app/
spec:
  ingressClassName: general-internal
  rules:
  - host: example.com
    http:
      paths:
      - path: "/my-app(/|$)(.*)"
        backend:
          serviceName: my-app-svc
          servicePort: 443

It seems that the annotations above check the "Location" header in the redirection response to the client, and replace the first / with /my-app/ and only after this change - the redirection response is sent to the client.

Upvotes: 1

Related Questions