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

Generalize Rewrite Block Creation and Deprecate AddBaseUrl (not backwards compatible) #3174

Merged
merged 1 commit into from
Jan 2, 2019

Conversation

zrdaley
Copy link
Contributor

@zrdaley zrdaley commented Oct 3, 2018

What this PR does / why we need it:

When the rewrite-target annotation is used and the written path uses regex and does not end in / (ex. foo/bar/.+), rewrite does not work as expected. This provides a regex check in BuildProxyPass and uses a custom rewrite block if the use-regex annotation is true for a location.

UPDATE
In addition to the above, this PR deprecates the AddBaseUrl annotation.

Problem

An ingress is created with use-regex="true" and rewrite-target="/new" and the path /foo/bar/.+.

This results in the following rewrite blocks for that location:

rewrite (?i)/foo/bar/.+/(.*) /new/$1 break;
rewrite (?i)/foo/bar/.+$ /new break;
...

Therefore a request to /foo/bar/bar will go to /new instead of /new/bar as a user may expect.

Solution

Check if a use-regex is true for a location when building the proxy pass.

An ingress is created with use-regex="true" and rewrite-target="/new/$1" and the path /foo/bar/(.+).

This results in the following rewrite blocks for that location:

rewrite (?i)/foo/bar/(.+) /new/$1 break;
...

Now a request to /foo/bar/bar will go to /new/bar.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Oct 3, 2018
@k8s-ci-robot k8s-ci-robot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Oct 3, 2018
@aledbf
Copy link
Member

aledbf commented Oct 4, 2018

/lgtm
/hold

@k8s-ci-robot k8s-ci-robot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. lgtm "Looks good to me", indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Oct 4, 2018
@ElvinEfendi
Copy link
Member

The way I understand this is it enforces using regexp group references explicitly in rewrite-target annotation when use-regex is true.

So given an ingress with regexp path enabled and rewrite-target is "/new/$1". And there are two paths
foo/bar/(.+)
and
foo/baz

rewrite (?i)/foo/bar/(.+) /new/$1 break;
and
rewrite (?i)/foo/baz /new/$1 break;

will be generated accordingly. This means foo/baz/anything will be rewritten to /new/, which means breaking existing expectations.

I don't know what's the best solution here, maybe we should stop trying to make the controller smart about generating the correct rewrite syntax and let the user take are of that. Because to me it seems like impossible to find a common ground. Therefore it would make sense to let user do whatever they want. That would also simplify controller logic. Nginx rewrite directive has two required arguments:

rewrite regex replacement [flag];

So given that whenever rewrite target is used we enforce regepx path matching, I'd delete all the existing logic where we try to come up with correct arguments to rewrite and let the user take care of it the way she wants.

For example the simplest case when you want to rewrite foo/bar to /new you would need to set rewrite-target to /new/$1 and configure the path as (?i)/foo/bar/(.*). Then the controller would take the path and target as is and generate

rewrite (?i)/foo/bar/(.*) /new/$1 break;

this is obviously not backward compatible, but I really dislike the complexity around the current solution, and this solution will make it simpler to reason about.

@zrdaley
Copy link
Contributor Author

zrdaley commented Oct 4, 2018

@ElvinEfendi I completely agree.

Giving the user control of whether or not to append parameters to rewritten paths in all cases makes way more sense. Defaulting to enforcing this policy, especially now that regex is enabled, seems counterintuitive.

@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed lgtm "Looks good to me", indicates that a PR is ready to be merged. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Oct 4, 2018
@aledbf
Copy link
Member

aledbf commented Oct 8, 2018

@zrdaley please squash the commits

@@ -139,14 +138,13 @@ proxy_pass http://upstream-name;
false,
false,
false,
true},
false},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this false, when there's rewrite enforceRegex is always true, no?

@ElvinEfendi
Copy link
Member

/hold

@zrdaley please update PR title and description accordingly now that we pivoted.

--

This change is not backward compatible and it is going to break every single rewrite configuration.
We should find some way to at least not fail silently (this is what's going to happen the PR as is).

The logic at https://github.com/kubernetes/ingress-nginx/pull/3174/files#diff-652deabba49a2a87d4c5a79700dfa1e3R331 does not make much sense with regexp path support and specially after this PR. With this PR users will have to have something like (.*) in their path to do rewrite with $1, which is going to render (?<baseuri>.*) useless. IMO we should completely drop support for AddBaseURL, the app has every knowledge to make that decision.

This test https://github.com/kubernetes/ingress-nginx/pull/3174/files#diff-780db26d3e78669defcf119bfb8a9b64R43 now is not so useful. We should make sure it tests that path suffix (/something/i-am-suffix) gets added to the target path prefix (/) when proxying.

@aledbf
Copy link
Member

aledbf commented Oct 11, 2018

@zrdaley friendly ping

@zrdaley zrdaley changed the title Use custom rewrite block when regex is used Generalize Rewrite Block Creation (not backwards compatible) Oct 16, 2018
@zrdaley
Copy link
Contributor Author

zrdaley commented Oct 16, 2018

@ElvinEfendi I agree with the deprecation of AddBaseURL however, I think that maybe this should be addressed in a separate PR, following this one.

Also, is there an official way to notify users of backwards compatibility issues or will the change of name above be sufficient?

I am just going to remove this test https://github.com/kubernetes/ingress-nginx/pull/3174/files#diff-780db26d3e78669defcf119bfb8a9b64R43. This test https://github.com/kubernetes/ingress-nginx/pull/3174/files?utf8=%E2%9C%93&diff=unified#diff-780db26d3e78669defcf119bfb8a9b64R257 cover's suffix appending for both the index and all other path cases since there is no longer a special case for the index path.

@zrdaley zrdaley force-pushed the rewrite-regex branch 2 times, most recently from 47f6cb1 to 4a6a6f5 Compare October 16, 2018 18:16
@zrdaley zrdaley changed the title Generalize Rewrite Block Creation (not backwards compatible) [WIP] Generalize Rewrite Block Creation (not backwards compatible) Oct 16, 2018
@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 16, 2018
@zrdaley zrdaley changed the title [WIP] Generalize Rewrite Block Creation (not backwards compatible) Generalize Rewrite Block Creation (not backwards compatible) Oct 16, 2018
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 16, 2018
@RAbraham
Copy link

@dshakey could you share your code change. That would be much appreciated.

@spacecat
Copy link

How can I configure nginx.ingress.kubernetes.io/rewrite-target and spec.rules.http.paths.path to satisfy the following URI patterns?

/aa/bb-aa/coolapp
/aa/bb-aa/coolapp/cc

Legend:

  • a = Any letter between a-z. Lowercase. Exactly 2 letters - no more, no less.
  • b = Any letter between a-z. Lowercase. Exactly 2 letters - no more, no less.
  • c = any valid URI character. Lowercase. Of variable length - think slug.

Example URI:s that should match the above pattern:

/us/en-us/coolapp
/us/en-us/coolapp/faq
/us/en-us/coolapp/privacy-policy

@Gilgames000
Copy link

@spacecat does this answer your question?

@spacecat
Copy link

@Gilgames000 Thanks. I've updated the SO post.

@anhthang
Copy link

I'm using the latest nginx-ingress with a below yml file

kind: Ingress
metadata:
  annotations:
    ingress.kubernetes.io/rewrite-target: /$1
    kubernetes.io/ingress.allow-http: "false"
    kubernetes.io/ingress.class: nginx
  labels:
    app: app_name
  name: app_name-staging
  namespace: app_name
spec:
  rules:
  - host: my_url
    http:
      paths:
      - backend:
          serviceName: app_name-staging
          servicePort: http
        path: /dev/?(.*)
  tls:
  - hosts:
    - my_url
    secretName: app_name-staging-tls
status:
  loadBalancer:
    ingress:
    - ip: 34.87.60.27

When I go to my_url/dev/path it's showing default backend - 404 and when I go to my_url/path it show success response.

I'm expecting success response when I go to my_url/dev/path. Can anyone help me check this?

@spacecat
Copy link

@buianhthang try this:
nginx.ingress.kubernetes.io/rewrite-target: /$2
path: /dev(/|$)(.*)

@anhthang
Copy link

@spacecat thank you. i haven’t try yet, but my snippet working now. I’m guessing it’s ingress-nginx-default-backend issue. But I will try your suggestions

Sent with GitHawk

@davidchua davidchua mentioned this pull request Sep 12, 2019
@scniro
Copy link

scniro commented Nov 26, 2019

Not happy about having my app break and needing to sift through these comments, reaching the bottom and not finding a reasonable workaround.

For clarity, what is now the canonical solution? This is a bit of a head scratcher.

@scniro
Copy link

scniro commented Nov 26, 2019

I am quite confused about the implications of this PR. Do I even have to worry about anything if I do not specify use-regex=true anywhere? I also have no regex constructs in my rewrite-targets. Should I be worried?

We use Azure AKS, and have nginx.ingress.kubernetes.io/rewrite-target: in our helm charts. We don't have use-regex=true in our chart anywhere, but this change broke our rewrite targets.

@avik-so Have you found a reasonable solution? Facing the same - dead in the water

@aledbf
Copy link
Member

aledbf commented Nov 26, 2019

@scniro this is a change introduced more than a year ago. The example https://kubernetes.github.io/ingress-nginx/examples/rewrite/#rewrite-target is up to date.
If you have an issue using the annotation please open a new one. Thanks

@avik-so
Copy link

avik-so commented Nov 26, 2019

@scniro Only options are to use the new syntax or use version 0.21.0

@zuzzas
Copy link

zuzzas commented Nov 26, 2019

One day I'll write a blog post about migrating 80+ Kubernetes clusters:

  1. From old annotation format to new one;
  2. From old rewrite format to new one

via a mutating admission webhook that creates almost identical copy of an Ingress resource, but with a different ingress.class, and with proper annotations and rewrite the new rewrite. Once such a webhook is in place and all Ingress resources have a working copy, we've switched Nginx Ingress Controller to use previously create Ingresses via a new ingress.class cmdline option.

That was quite a journey. :)

@elafontaine
Copy link

elafontaine commented Feb 3, 2020

For folks ending up here and wondering what they could do, we solved the backward incompatible by having the anntoation be the following;

nginx.ingress.kubernetes.io/rewrite-target: /$2
and the path
path: /paas-demo(/|$)(.*$) (Notice the dollar sign in the capture group)

This made sure that the baseuri regex is not taken into consideration for the match and allowed us to move forward.

@blurpy
Copy link

blurpy commented Feb 19, 2020

Are there any solutions at all that will work both before and after this change? We don't have the option of upgrading and having requests fail until all the teams redeploy all their apps with a fixed ingress.

Most of our rewrites are simple:

nginx.ingress.kubernetes.io/rewrite-target: /
path: /something/

I've tried different combinations of the new syntax, like:

nginx.ingress.kubernetes.io/rewrite-target: /$2
path: /something(/|$)(.*$)

And:

nginx.ingress.kubernetes.io/rewrite-target: /$1
path: /something/(.*)

But the rewrite rule ends up weird in the old version of the nginx.conf:

rewrite /something/(.*)/(.*) /$1/$1 break;

@kevin-pro
Copy link

This is a bad breaking change and not backward compatible. For a frontend web app with multiple backend services, the configuration of the ingress became very weird after the upgrades. Is it possible to add a switch for a user to decide if turn on the change or not?

@avik-so
Copy link

avik-so commented May 3, 2020

Are there any solutions at all that will work both before and after this change? We don't have the option of upgrading and having requests fail until all the teams redeploy all their apps with a fixed ingress.

Most of our rewrites are simple:

nginx.ingress.kubernetes.io/rewrite-target: /
path: /something/

I've tried different combinations of the new syntax, like:

nginx.ingress.kubernetes.io/rewrite-target: /$2
path: /something(/|$)(.*$)

And:

nginx.ingress.kubernetes.io/rewrite-target: /$1
path: /something/(.*)

But the rewrite rule ends up weird in the old version of the nginx.conf:

rewrite /something/(.*)/(.*) /$1/$1 break;

As far as we have been able to figure out, this change requires downtime to redeploy.
An alternative is to create two services, with two different ingress configurations, and do a slow migration that way.

@ghost
Copy link

ghost commented Jun 10, 2020

@buianhthang试试这个:
nginx.ingress.kubernetes.io/rewrite-target: /$2
path: /dev(/|$)(.*)

It solved my problem! Thank You!

@maxisam
Copy link

maxisam commented Aug 8, 2020

how do you solve this case #3770 ?

@liakouras
Copy link

I have IC version 0.20.0 and the following configuration works, but NOT with 0.30.0:

======================
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
name: test-ingress
namespace: test
labels:
Name: test
name: test-ingress
namespace: test
spec:
rules:

  • host: www.test.com
    http:
    paths:
    • backend:
      serviceName: test-application-1
      servicePort: 80
      path: /test/api1
    • backend:
      serviceName: test-application-2
      servicePort: 80
      path: /test/api2

======================

I replaced the nginx.ingress.kubernetes.io/rewrite-target: / with the following but still doesn't work:

======================
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite "(?i)/test/api1/(.)" /$1 break;
rewrite "(?i)/test/api1$" / break;
rewrite "(?i)/test/ap21/(.
)" /$1 break;
rewrite "(?i)/test/ap21$" / break;
======================

can you please help?

Gacko added a commit to giantswarm/docs that referenced this pull request Nov 23, 2023
Gacko added a commit to giantswarm/docs that referenced this pull request Nov 23, 2023
Gacko added a commit to giantswarm/docs that referenced this pull request Nov 27, 2023
Gacko added a commit to giantswarm/docs that referenced this pull request Nov 28, 2023
Gacko added a commit to giantswarm/docs that referenced this pull request Nov 28, 2023
* Configuration: Prepend `nginx` to annotations.

* Configuration: Remove `nginx.ingress.kubernetes.io/add-base-url`.

Deprecated: kubernetes/ingress-nginx#3174

* Configuration: Remove `nginx.ingress.kubernetes.io/session-cookie-hash`.

Deprecated: kubernetes/ingress-nginx#3743

* Configuration: Bump `last_review_date`.

* Multiple Ingress NGINX Controllers: Remove deprecated `controller.ingressClass`.

* Multiple Ingress NGINX Controllers: Remove wildcard from `controller.service.subdomain`.

* Multiple Ingress NGINX Controllers: Migrate `configmap` to `controller.config`.

* Multiple Ingress NGINX Controllers: Bump `last_review_date`.

* Service Type LoadBalancer: Make `service.beta.kubernetes.io/aws-load-balancer-internal` a boolean.

* Service Type LoadBalancer: Make `service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval` a string.

* Service Type LoadBalancer: Move `Other AWS ELB configuration options`.

* Service Type LoadBalancer: Document Martian Packets when using internal AWS Network Load Balancers.

* Service Type LoadBalancer: Document Health Checks failing when using PROXY protocol and `externalTrafficPolicy: Local`.

* Service Type LoadBalancer: Document Security Group configuration on internal AWS Network Load Balancers.

* Service Type LoadBalancer: Bump `last_review_date`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.