-
Notifications
You must be signed in to change notification settings - Fork 604
Description
When talking about Listener acceptance and merging behavior as part of #2288, we discovered that there was a particularly important part of the spec that we had not clarified enough, and that this has created a behavior variance between implementations.
I (@youngnick) summarized this as follows:
That concept is important because, for better or for worse, it has always been intended that the traffic-matching between Listeners and Routes is a two stage process. First you match a Listener, then you look for matching routes. In the case that there's a wildcard hostname, it was definitely not intended that a request could match both (for example, the
cafe.example.comand*.example.comListeners.) That is, having different values at all for hostname has been intended to make the Listeners distinct and unmergeable. We certainly have not done enough to explain that this is the intention, and I'm sorry for that.
That is, it was the original intention in the spec that, if there is a precise hostname match in one Listener, and a wildcard match in another, that traffic that matches the precise hostname will arrive only at Routes bound to that Listener.
Another way to put this is that if a precise hostname match is present, then a wildcard match should never also match that precise hostname.
Because we were not clear about this in the spec originally, many implementations have implemented their rules such that requests that match a precise hostname may, if there are no matching Routes for the request, match Routes attached to the wildcard hostname.
To use an example, here is a Gateway that @pleshakov supplied in #2288.
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: gateway
spec:
gatewayClassName: nginx
listeners:
- name: example
port: 80
protocol: HTTP
hostname: "*.example.com"
- name: cafe-http
port: 80
protocol: HTTP
hostname: "cafe.example.com"And here are some Routes that illustrate the config that may result in cascading behavior. I've left out hostnames on the HTTPRoutes so that only the Listener hostname is relevant.
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: coffee
spec:
parentRefs:
- name: gateway
sectionName: cafe-http
rules:
- matches:
- path:
type: PathPrefix
value: /coffee
backendRefs:
- name: backend
port: 3000
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: tea
spec:
parentRefs:
- name: gateway
sectionName: example
rules:
- matches:
- path:
type: PathPrefix
value: /tea
backendRefs:
- name: backend
port: 3000In this example, cafe.example.com has one HTTPRoute attached, /coffee, and *.example.com has one HTTPRoute attached, /tea.
The original intent of the spec is that the only valid request using cafe.example.com is http://cafe.example.com/coffee. Any request that does not match the set of Routes attached to the cafe-http Listener should be 404ed.
However, many implementations allow the request to cascade between Listeners, which means that request to either http://cafe.example.com/coffee or http://cafe.example.com/tea will succeed.
This issue is to discuss how to proceed here.
My personal preference is to tighten up the language here, and make the originally-implied behavior explicit and compulsory, with conformance tests to back it up. I'm aware that this will be painful for a number of implementations, but I really think that this is better in the long run. This is a very subtle difference that will be very difficult to explain to end users, and I think that it will significantly decrease portability to have this be optional in an extended feature.