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

Ingress pathType "Prefix" can override pathType "Exact" #703

Open
phihos opened this issue Mar 5, 2025 · 2 comments · May be fixed by #704
Open

Ingress pathType "Prefix" can override pathType "Exact" #703

phihos opened this issue Mar 5, 2025 · 2 comments · May be fixed by #704

Comments

@phihos
Copy link

phihos commented Mar 5, 2025

Let's assume we have a web service with prefix /foo. There are many sub-paths for /foo/.... Let's also assume we want to have different timeouts for /foo and /foo/.*.

We would expect the following to work:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: subpath-foo
  annotations:
    haproxy.org/standalone-backend: "true"
    haproxy.org/timeout-server: 5s
spec:
  ingressClassName: haproxy
  rules:
  - host: example.tld 
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: foo-service
            port:
              name: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: just-foo
  annotations:
    haproxy.org/standalone-backend: "true"
    haproxy.org/timeout-server: 10s
spec:
  ingressClassName: haproxy
  rules:
  - host: example.tld 
    http:
      paths:
      - path: /foo
        pathType: Exact
        backend:
          service:
            name: foo-service
            port:
              name: http

The annotation haproxy.org/standalone-backendensures two separate backends are created so that the different timeouts do not fight each other.
Now we have the problem that /etc/haproxy/maps/path-exact.map has the following contents:

example.tld/foo          ing_default_subpath-foo_http.dbe4b28f9c4404fc36a7ae76ead9a37d
example.tld/foo          ing_default_just-foo_http.dbe4b28f9c4404fc36a7ae76ead9a37d

That means the actual exact match from ingress just-foo will never match since pathType Prefix patterns are also put into this pattern file.
Here we can find the responsible code:

	path := route.Path.Path
	switch {
	case route.Path.PathTypeMatch == store.PATH_TYPE_EXACT:
		mapFiles.MapAppend(PATH_EXACT, route.Host+path+"\t\t\t"+value)
	case path == "" || path == "/":
		mapFiles.MapAppend(PATH_PREFIX, route.Host+"/"+"\t\t\t"+value)
	case route.Path.PathTypeMatch == store.PATH_TYPE_PREFIX:
		path = strings.TrimSuffix(path, "/")
		mapFiles.MapAppend(PATH_EXACT, route.Host+path+"\t\t\t"+value)
		mapFiles.MapAppend(PATH_PREFIX, route.Host+path+"/"+"\t\t\t"+value)
	case route.Path.PathTypeMatch == store.PATH_TYPE_IMPLEMENTATION_SPECIFIC:
		path = strings.TrimSuffix(path, "/")
		mapFiles.MapAppend(PATH_EXACT, route.Host+path+"\t\t\t"+value)
		mapFiles.MapAppend(PATH_PREFIX, route.Host+path+"\t\t\t"+value)
	default:
		return fmt.Errorf("unknown path type '%s' with backend '%s'", route.Path.PathTypeMatch, route.BackendName)
	}

I do understand why Prefix paths must have an entry in path-exact.map: The definition of ingress resources mandates that /foo must match /foo and /foo/bar but never /foobar. Therefore we add /foo to exact matches and /foo/ to prefix matches (via map_beg).

The only way I see to resolve this issue in a clean and backward-compatible way is to introduce a new map file which will contain all exact matches from pathType Prefix only and it will be matched if there was no match in path-exact.map which will then contain ONLY pathType Exact patterns.

I will follow up with a PR.

@dosmanak
Copy link
Contributor

Just a while ago I wondered the Implementation Specific variant could by also implemented in haproxy with regex matching available.

@phihos
Copy link
Author

phihos commented Mar 10, 2025

Hi @dosmanak, if an ingress controller wants to implement regex-based parsing then pathType ImplementationSpecfic is the way to go. But this is beside the point of this issue. Here I discussed that prefix paths can sometimes override exact paths, which should not happen.
If you would like to discuss regex-based path matching feel free to open another issue for that. I am not a maintainer of this project, but I certainly can contribute some caveats to be aware of.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants