Skip to content

Question: why the case insensitive regular expression location modifier will be enforced on ALL paths If the use-regex is set #11397

Open
@simonellefsen

Description

@simonellefsen

From the ingress-nginx doc https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/#warning

IMPORTANT NOTES:

If the use-regex OR rewrite-target annotation is used on any Ingress for a given host, then the case insensitive regular expression location modifier will be enforced on ALL paths for a given host regardless of what Ingress they are defined on.

My question is why? why does it have to be this way? why can't it just be the ingress that has "use-regex=true" or "rewrite-target" defined that uses case insensitive regular expression locations match.

We have a very old website with some not so well designed paths like

/[a-z0-9_.-]{3,40}(\/)?([\?\#]|$)

And when we add that as an ingress and sets the annotation use-regex=true then all the Exact and Prefix ingress are all converted into case insensitive regular expression location modifiers and we loose that ability to have a simple prioritisation.

Like having a Prefix ingress for path /foo that will have a higher priority than the regex above.

And we cannot for the life in us understand why anyone would want this default behaviour, that if one ingress is using regex then all is converted into regex location matches.

We have to patch the nginx.tmpl to get around this

This is our patch and it works fine for us but maybe we are missing something (most likely we are, hence why I'm asking this question)

With this patch an Exact ingress type will not be changed into case insensitive regular expression location modifiers but remain "=" location modifier.

Simon Ellefsen

--- nginx.tmpl	2024-05-17 13:54:19
+++ nginx.tmpl	2024-05-17 13:56:09
@@ -1056,8 +1056,26 @@
 
         {{ buildMirrorLocations $server.Locations }}
 
-        {{ $enforceRegex := enforceRegexModifier $server.Locations }}
+        ## {{ $enforceRegex := enforceRegexModifier $server.Locations }}
         {{ range $location := $server.Locations }}
+
+        # These two lines are the custom change. The rest of the file is the same as the original file.
+        # The goal of this change is to change the default behaviour of the ingress-nginx controller that
+        # makes all location blocks for a host to be regex based if at least one of ingresses has `use-regex` annotation set to true.
+        # The way we're changing this behaviour is by limiting $enforceRegex to be true only if the location has `use-regex` in it's Ingress resource set to true not in the whole host.
+        # Also we're preventing "Exact" paths to be regex based EVEN IF the `use-regex` is set to true on it's Ingress by checking the return value of buildLocation with second argument set to false
+        # as it's only going to have "=" if it's an exact path.
+        # The default behaviour while being expected and documented is strange and doesn't fit us as it causes problems with `profile-page` and might cause problems going down the road.
+        # Also see this issue in the ingress-nginx repository: https://github.com/kubernetes/ingress-nginx/issues/10618
+        #
+        # It still leaves us with a problem when using Prefix pathType with `use-regex` as a prefix path like `/foo` will match `/foobar`
+        # as there's no way to figure out if it's a Prefix or a Regex in the template ($location.PathType is a reference to a string which we can't deref here to know for sure).
+        # This can be mitigated by using `/foo/` as a path in the Ingress resource as it will end up into being a regex like `^/foo/` in the final config.
+        # So when using `use-regex` with Prefix pathType we should make sure to add a trailing slash to the path in the Ingress resource.
+        # So if someone wants to match `/foo` and `/foo/bar` they should add both `Exact:/foo` and `Prefix:/foo/` paths in the Ingress resource.
+        {{ $plainPath := buildLocation $location false }}
+        {{ $enforceRegex := and (eq $location.Rewrite.UseRegex true) (not (contains $plainPath "=")) }}
+
         {{ $path := buildLocation $location $enforceRegex }}
         {{ $proxySetHeader := proxySetHeader $location }}
         {{ $authPath := buildAuthLocation $location $all.Cfg.GlobalExternalAuth.URL }}

Metadata

Metadata

Assignees

Labels

lifecycle/frozenIndicates that an issue or PR should not be auto-closed due to staleness.needs-kindIndicates a PR lacks a `kind/foo` label and requires one.needs-priorityneeds-triageIndicates an issue or PR lacks a `triage/foo` label and requires one.

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions