-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Description
What happened:
The Admission Validation logic (checkOverlap) incorrectly skips checking subsequent Rules and Paths if the first Rule/Path in the Ingress definition is valid (no conflict).
This allows an Ingress with conflicting rules to bypass the admission controller and be successfully applied to the cluster, as long as the conflicting rule is placed after a non-conflicting rule in the YAML definition.
Specifically, in internal/ingress/controller/controller.go, inside the checkOverlap function, there is a return nil statement inside the inner Path loop. This causes the function to exit immediately after verifying the first path of the first rule, ignoring all remaining paths and rules.
What you expected to happen:
The Admission Controller should check ALL rules and paths defined in an Ingress object for conflicts. If any rule/path conflicts with an existing Ingress, the request should be rejected, regardless of the order of rules in the YAML.
NGINX Ingress controller version:
Latest (and affects previous versions as well). Code logic issue exists in main branch.
Kubernetes version:
All versions.
Environment:
- Cloud provider: Any (Logic issue)
- OS: Any
- Install tools: Any
How to reproduce this issue:
- Create a Victim Ingress (A) that occupies a specific host/path.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: victim
namespace: default
spec:
ingressClassName: nginx
rules:- host: conflict.example.com
http:
paths:- path: /
pathType: Prefix
backend:
service:
name: http-svc
port:
number: 80
- path: /
- Create an Intruder Ingress (B).
Crucial Step: Define a non-conflicting rule FIRST, and the conflicting rule SECOND.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: intruder
namespace: default
spec:
ingressClassName: nginx
rules:
Rule 1: No conflict (Safe)
- host: safe.example.com
http:
paths:- path: /
pathType: Prefix
backend:
service:
name: http-svc
port:
number: 80
- path: /
Rule 2: Conflict! (Should be rejected, but is accepted due to bug)
- host: conflict.example.com
http:
paths:- path: /
pathType: Prefix
backend:
service:
name: http-svc
port:
number: 80
- path: /
- Apply Ingress B.
- Actual Result:
ingress.networking.k8s.io/intruder created. (The conflict in Rule 2 is ignored). - Expected Result: Admission webhook should deny the request due to conflict in Rule 2.
- host: conflict.example.com
Anything else we need to know:
Root Cause Analysis:
The issue is located in internal/ingress/controller/controller.go.
func (n *NGINXController) checkOverlap(ing *networking.Ingress, servers []*ingress.Server) error {
for _, rule := range ing.Spec.Rules {
for _, path := range rule.HTTP.Paths {
// ... conflict checking logic ...
existingIngresses := ingressForHostPath(rule.Host, path.Path, servers)
if len(existingIngresses) == 0 {
continue
}
// ... checks ...
// BUG HERE:
// This 'return nil' is inside the loop.
// It causes the function to exit successfully after the FIRST valid path check.
// Subsequent paths and rules are never checked.
return nil
}
}
return nil
}Additionally, there is a secondary minor issue where it returns nil immediately if it encounters itself in the existingIngresses list, instead of continue, which might also skip checks in other edge cases.
Suggested Fix:
Remove the premature return nil inside the loop.
// ... inside loop ...
// return nil <-- REMOVE THIS
}
}
return nil
}
Metadata
Metadata
Assignees
Labels
Type
Projects
Status