Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rewrite-target invalid for kubernetes ingress on root path #5990

Closed
seboudry opened this issue Dec 10, 2019 · 10 comments
Closed

rewrite-target invalid for kubernetes ingress on root path #5990

seboudry opened this issue Dec 10, 2019 · 10 comments
Labels
Milestone

Comments

@seboudry
Copy link

Do you want to request a feature or report a bug?

Bug

What did you do?

Creating an Ingress resource on a subdomain having only one rule on / that point to a backend handling requests on /app.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.ingress.kubernetes.io/rewrite-target: /app
spec:
  rules:
  - host: app.my-domain.fr
    http:
      paths:
      - path: /
        backend:
          serviceName: my-app
          servicePort: http

What did you expect to see?

Traefik to send all requests with URLs on domain with app.my-domain.fr to my backend on path:

  • / -> /app/
  • /foo/ -> /app/foo/

Same as nginx.ingress.kubernetes.io/rewrite-target behavior.

What did you see instead?

curl -s https://app.my-domain.fr/ | grep GET
<pre>Cannot GET /app</pre>

with a 404 status code.

But, request on https://app.my-domain.fr// (notice the additional / at end) give a 200 with expected response.

traefik version

In Kubernetes, installed with Helm chart stable/traefik v1.82.3

traefik-helm: traefik:1.7.19

What is your environment & configuration (arguments, toml, provider, platform, ...)?

Route rule (on dashboard):

PathPrefix:/;ReplacePathRegex: ^/(.*) /app$1
Host:app.my-domain.fr
# traefik.toml
logLevel = "info"
defaultEntryPoints = ["http","https"]
[entryPoints]
  [entryPoints.http]
  address = ":80"
  compress = true
  [entryPoints.https]
  address = ":443"
  compress = true
    [entryPoints.https.tls]
      [[entryPoints.https.tls.certificates]]
      CertFile = "/ssl/tls.crt"
      KeyFile = "/ssl/tls.key"
  [entryPoints.traefik]
  address = ":8080"
[ping]
entryPoint = "http"
[kubernetes]
ingressClass = "traefik"
[traefikLog]
  format = "json"
[accessLog]
  format = "json"
[accessLog.fields]
  defaultMode = "keep"
[accessLog.fields.names]
[accessLog.fields.headers]
  defaultMode = "keep"
[accessLog.fields.headers.names]
[api]
  entryPoint = "traefik"
  dashboard = true
@dtomcej
Copy link
Contributor

dtomcej commented Dec 10, 2019

Hello @seboudry,

You gave an example of what you expected to happen:

/ -> /app/
/foo/ -> /app/foo/

But that is not what you see:

/ -> /app

And what you expect is not how nginx handles it either:
https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/rewrite#rewrite-target

rewrite.bar.com/something/new -> rewrite.bar.com/new

You need to pay close attention to whether your request has a trailing slash.

You have configured the rewrite-target NOT to have a trailing slash:

traefik.ingress.kubernetes.io/rewrite-target: /app

And your application doesn't appear to listen on that path:

curl -s https://app.my-domain.fr/ | grep GET

Cannot GET /app

What happens if you use:
traefik.ingress.kubernetes.io/rewrite-target: /app/? Does it behave as you expect?

@seboudry
Copy link
Author

Hi @dtomcej !

Here's my working Nginx ingress definition:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress-nginx
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /app/
spec:
  rules:
  - host: app.my-domain.fr
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http

So indeed the target have a trailing slash and app listen on /app/, will expose it later for Treafik.
And I don't have to specify path: / on path rules spec as it's the default value (same behaviour with or without it).

Using Traefik, if I add a trailing slash with traefik.ingress.kubernetes.io/rewrite-target: /app/, it doesn't seems to be used.
Indeed, ReplacePathRegex rule doesn't include it.
Route rule (on dashboard):

PathPrefix:/;ReplacePathRegex: ^/(.*) /app$1
Host:app.my-domain.fr

If I remove path: / on path rules spec, nothing is applied (regardless of trailing slash is defined on rewrite-target).
Route rule (on dashboard):

Host:app.my-domain.fr

So it seems the fix is to have the trailing slash on rewrite-target annotation added to ReplacePathRegex rule.

@dtomcej
Copy link
Contributor

dtomcej commented Dec 11, 2019

Hello @seboudry

This behavior was last changed almost a year and a half ago with this PR:

#3699

Can you please confirm that you are expecting different behavior than that?

We manually strip the slash off the right: https://github.com/containous/traefik/blame/a8393faf0ae6714e9d545051011624738a9eb2b7/provider/kubernetes/kubernetes.go#L676

@dtomcej
Copy link
Contributor

dtomcej commented Dec 11, 2019

There might be an edge case when the path matched is /

@dduportal dduportal added kind/bug/possible a possible bug that needs analysis before it is confirmed or fixed. area/provider/k8s/ingress and removed status/0-needs-triage labels Dec 11, 2019
@seboudry
Copy link
Author

Yes, It works fine when path contains something without trailing slash (/testing in the PR example).
But when path is on root / it breaks.

Just giving a hand on Traefik since this week ;)
Like it but this issue will make migration from Nginx difficult.
I'm planning to use Traefik on a couple of services and then migrate whole on v2.

@dtomcej
Copy link
Contributor

dtomcej commented Dec 11, 2019

Ok. So it is the edge case. Will look at making a PR.

Just to confirm, the case that we are wanting to implement is:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress-traefik
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.ingress.kubernetes.io/rewrite-target: /app/
spec:
  rules:
  - host: app.my-domain.fr
    http:
      paths:
      - backend:
          serviceName: my-app
          servicePort: http

or

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.ingress.kubernetes.io/rewrite-target: /app/
spec:
  rules:
  - host: app.my-domain.fr
    http:
      paths:
      - path: /
        backend:
          serviceName: my-app
          servicePort: http

should both result in rules that forward these requests:

app.my-domain.fr/ -> app.my-domain.fr/app/
app.my-domain.fr/foo/ -> app.my-domain.fr/app/foo/

@seboudry
Copy link
Author

Exactly!

And using the test requests from previous PR:

$ curl -v app.my-domain.fr/ -silent 2>&1 | grep GET

> GET / HTTP/1.1
GET /app/ HTTP/1.1

$ curl -v app.my-domain.fr/foo/ -silent 2>&1 | grep GET

> GET /foo/ HTTP/1.1
GET /app/foo/ HTTP/1.1

Thanks for the quick consideration of this! 👍

@dtomcej
Copy link
Contributor

dtomcej commented Dec 11, 2019

@seboudry, feel free to test with this PR to see if it works for you (it should).

@seboudry
Copy link
Author

PR tested OK ;)
#6005 (comment)

@traefiker
Copy link
Contributor

Closed by #6005.

@traefiker traefiker added this to the 1.7 milestone Dec 19, 2019
@traefik traefik locked and limited conversation to collaborators Jan 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants