Welcome!
What did you do?
Used kubernetesIngressNGINX provider with an Ingress containing an NGINX server-snippet using the standard ^~ (best prefix match) location modifier to block internal paths:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
location ^~ /internal {
return 404;
}
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-service
port:
number: 80
Sent an HTTP request to GET /internal.
What did you see instead?
The request to /internal was not blocked and fell through to the catch-all path: / backend. No error or warning was produced during Ingress parsing or at runtime.
Root Cause in Source Code:
In pkg/middlewares/ingressnginx/snippet/collector.go:
-
createLocationCollectable() handles 2 parameters when a modifier is present:
pathPattern := params[0].String()
if len(params) == 2 {
pathPattern += params[1].String()
}
For location ^~ /internal, params[0] is "^~" and params[1] is "/internal", making pathPattern = "^~/internal".
-
buildLocationMatcher(pathPattern) checks for ~*, ~, and =, but omits ^~:
func buildLocationMatcher(pathPattern string) (locationMatcher, error) {
if pattern, ok := strings.CutPrefix(pathPattern, "~*"); ok { ... }
if pattern, ok := strings.CutPrefix(pathPattern, "~"); ok { ... }
if exact, ok := strings.CutPrefix(pathPattern, "="); ok { ... }
// Fallback: Prefix match
return func(req *http.Request) bool {
return strings.HasPrefix(req.URL.Path, pathPattern)
}, nil
}
-
Because "^~/internal" does not start with ~ or =, it falls into the prefix match fallback:
strings.HasPrefix(req.URL.Path, "^~/internal").
-
Since request paths never start with "^~", matcher(req) silently evaluates to false for every request, causing the block to never execute.
What version of Traefik are you using?
v3.7.5
What is your environment & configuration?
- Kubernetes with
kubernetesIngressNGINX provider enabled (--providers.kubernetesingressnginx=true, --providers.kubernetesingressnginx.allowSnippetAnnotations=true).
- Standard
networking.k8s.io/v1 Ingress with nginx.ingress.kubernetes.io/server-snippet.
Welcome!
What did you do?
Used
kubernetesIngressNGINXprovider with an Ingress containing an NGINXserver-snippetusing the standard^~(best prefix match) location modifier to block internal paths:Sent an HTTP request to
GET /internal.What did you see instead?
The request to
/internalwas not blocked and fell through to the catch-allpath: /backend. No error or warning was produced during Ingress parsing or at runtime.Root Cause in Source Code:
In
pkg/middlewares/ingressnginx/snippet/collector.go:createLocationCollectable()handles 2 parameters when a modifier is present:For
location ^~ /internal,params[0]is"^~"andparams[1]is"/internal", makingpathPattern = "^~/internal".buildLocationMatcher(pathPattern)checks for~*,~, and=, but omits^~:Because
"^~/internal"does not start with~or=, it falls into the prefix match fallback:strings.HasPrefix(req.URL.Path, "^~/internal").Since request paths never start with
"^~",matcher(req)silently evaluates tofalsefor every request, causing the block to never execute.What version of Traefik are you using?
v3.7.5
What is your environment & configuration?
kubernetesIngressNGINXprovider enabled (--providers.kubernetesingressnginx=true,--providers.kubernetesingressnginx.allowSnippetAnnotations=true).networking.k8s.io/v1Ingress withnginx.ingress.kubernetes.io/server-snippet.