Skip to content

Commit ccad1f3

Browse files
committed
set OverlappingTLSConfig condition for merged Gateways
Signed-off-by: Huabing (Robin) Zhao <[email protected]>
1 parent 68a2713 commit ccad1f3

6 files changed

+897
-64
lines changed

internal/gatewayapi/listener.go

+97-37
Original file line numberDiff line numberDiff line change
@@ -175,30 +175,53 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource
175175
foundPorts[irKey] = append(foundPorts[irKey], servicePort)
176176
}
177177
}
178-
179-
checkOverlappingTLSConfig(gateway)
180178
}
179+
180+
t.checkOverlappingTLSConfig(gateways)
181181
}
182182

183183
// checkOverlappingTLSConfig checks for overlapping hostnames and certificates between listeners and sets
184184
// the `OverlappingTLSConfig` condition if there are overlapping hostnames or certificates.
185-
func checkOverlappingTLSConfig(gateway *GatewayContext) {
186-
// Note: order of processing matters here.
187-
// According to the Gateway API spec, If both hostname and certificate overlap,
188-
// the controller SHOULD set the "OverlappingCertificates" Reason.
189-
checkOverlappingHostnames(gateway)
190-
checkOverlappingCertificates(gateway)
191-
}
192-
193-
func checkOverlappingHostnames(gateway *GatewayContext) {
194-
httpsListeners := []*ListenerContext{}
195-
for _, listener := range gateway.listeners {
196-
if listener.Protocol == gwapiv1.HTTPSProtocolType {
197-
httpsListeners = append(httpsListeners, listener)
185+
func (t *Translator) checkOverlappingTLSConfig(gateways []*GatewayContext) {
186+
// If merging gateways, check overlapping hostnames and certificates between listeners in all merged gateways.
187+
if t.MergeGateways {
188+
httpsListeners := []*ListenerContext{}
189+
for _, gateway := range gateways {
190+
for _, listener := range gateway.listeners {
191+
if listener.Protocol == gwapiv1.HTTPSProtocolType {
192+
httpsListeners = append(httpsListeners, listener)
193+
}
194+
}
195+
}
196+
// Note: order of processing matters here.
197+
// According to the Gateway API spec, If both hostname and certificate overlap,
198+
// the controller SHOULD set the "OverlappingCertificates" Reason.
199+
checkOverlappingHostnames(httpsListeners)
200+
checkOverlappingCertificates(httpsListeners)
201+
} else {
202+
// Check overlapping hostnames and certificates between listeners in each gateway.
203+
for _, gateway := range gateways {
204+
httpsListeners := []*ListenerContext{}
205+
for _, listener := range gateway.listeners {
206+
if listener.Protocol == gwapiv1.HTTPSProtocolType {
207+
httpsListeners = append(httpsListeners, listener)
208+
}
209+
}
210+
// Note: order of processing matters here.
211+
// According to the Gateway API spec, If both hostname and certificate overlap,
212+
// the controller SHOULD set the "OverlappingCertificates" Reason.
213+
checkOverlappingHostnames(httpsListeners)
214+
checkOverlappingCertificates(httpsListeners)
198215
}
199216
}
217+
}
200218

219+
// checkOverlappingHostnames checks for overlapping hostnames between HTTPS listeners and sets
220+
// the `OverlappingTLSConfig` condition if there are overlapping hostnames.
221+
func checkOverlappingHostnames(httpsListeners []*ListenerContext) {
201222
type overlappingListener struct {
223+
gateway1 *GatewayContext
224+
gateway2 *GatewayContext
202225
listener1 string
203226
listener2 string
204227
hostname1 string
@@ -219,12 +242,16 @@ func checkOverlappingHostnames(gateway *GatewayContext) {
219242
if isOverlappingHostname(httpsListeners[i].Hostname, httpsListeners[j].Hostname) {
220243
// Overlapping listeners can be more than two, we only report the first two for simplicity.
221244
overlappingListeners[i] = &overlappingListener{
245+
gateway1: httpsListeners[i].gateway,
246+
gateway2: httpsListeners[j].gateway,
222247
listener1: string(httpsListeners[i].Name),
223248
listener2: string(httpsListeners[j].Name),
224249
hostname1: string(ptr.Deref(httpsListeners[i].Hostname, "")),
225250
hostname2: string(ptr.Deref(httpsListeners[j].Hostname, "")),
226251
}
227252
overlappingListeners[j] = &overlappingListener{
253+
gateway1: httpsListeners[j].gateway,
254+
gateway2: httpsListeners[i].gateway,
228255
listener1: string(httpsListeners[j].Name),
229256
listener2: string(httpsListeners[i].Name),
230257
hostname1: string(ptr.Deref(httpsListeners[j].Hostname, "")),
@@ -236,17 +263,33 @@ func checkOverlappingHostnames(gateway *GatewayContext) {
236263

237264
for i, listener := range httpsListeners {
238265
if overlappingListeners[i] != nil {
239-
status.SetGatewayListenerStatusCondition(gateway.Gateway,
240-
listener.listenerStatusIdx,
241-
gwapiv1.ListenerConditionOverlappingTLSConfig,
242-
metav1.ConditionTrue,
243-
gwapiv1.ListenerReasonOverlappingHostnames,
244-
fmt.Sprintf(
266+
var message string
267+
gateway1 := overlappingListeners[i].gateway1
268+
gateway2 := overlappingListeners[i].gateway2
269+
if gateway1.Name == gateway2.Name &&
270+
gateway1.Namespace == gateway2.Namespace {
271+
message = fmt.Sprintf(
245272
"The hostname %s overlaps with the hostname %s in listener %s. ALPN is set to HTTP/1.1 to prevent HTTP/2 connection coalescing",
246273
overlappingListeners[i].hostname1,
247274
overlappingListeners[i].hostname2,
248275
overlappingListeners[i].listener2,
249-
),
276+
)
277+
} else {
278+
message = fmt.Sprintf(
279+
"The hostname %s overlaps with the hostname %s in listener %s of gateway %s. ALPN is set to HTTP/1.1 to prevent HTTP/2 connection coalescing",
280+
overlappingListeners[i].hostname1,
281+
overlappingListeners[i].hostname2,
282+
overlappingListeners[i].listener2,
283+
gateway2.GetName(),
284+
)
285+
}
286+
287+
status.SetGatewayListenerStatusCondition(listener.gateway.Gateway,
288+
listener.listenerStatusIdx,
289+
gwapiv1.ListenerConditionOverlappingTLSConfig,
290+
metav1.ConditionTrue,
291+
gwapiv1.ListenerReasonOverlappingHostnames,
292+
message,
250293
)
251294
if listener.httpIR != nil {
252295
listener.httpIR.TLSOverlaps = true
@@ -255,15 +298,12 @@ func checkOverlappingHostnames(gateway *GatewayContext) {
255298
}
256299
}
257300

258-
func checkOverlappingCertificates(gateway *GatewayContext) {
259-
httpsListeners := []*ListenerContext{}
260-
for _, listener := range gateway.listeners {
261-
if listener.Protocol == gwapiv1.HTTPSProtocolType {
262-
httpsListeners = append(httpsListeners, listener)
263-
}
264-
}
265-
301+
// checkOverlappingCertificates checks for overlapping certificates SANs between HTTPSlisteners and sets
302+
// the `OverlappingTLSConfig` condition if there are overlapping certificates.
303+
func checkOverlappingCertificates(httpsListeners []*ListenerContext) {
266304
type overlappingListener struct {
305+
gateway1 *GatewayContext
306+
gateway2 *GatewayContext
267307
listener1 string
268308
listener2 string
269309
san1 string
@@ -287,12 +327,16 @@ func checkOverlappingCertificates(gateway *GatewayContext) {
287327
if overlappingCertificate != nil {
288328
// Overlapping listeners can be more than two, we only report the first two for simplicity.
289329
overlappingListeners[i] = &overlappingListener{
330+
gateway1: httpsListeners[i].gateway,
331+
gateway2: httpsListeners[j].gateway,
290332
listener1: string(httpsListeners[i].Name),
291333
listener2: string(httpsListeners[j].Name),
292334
san1: overlappingCertificate.san1,
293335
san2: overlappingCertificate.san2,
294336
}
295337
overlappingListeners[j] = &overlappingListener{
338+
gateway1: httpsListeners[j].gateway,
339+
gateway2: httpsListeners[i].gateway,
296340
listener1: string(httpsListeners[j].Name),
297341
listener2: string(httpsListeners[i].Name),
298342
san1: overlappingCertificate.san2,
@@ -304,17 +348,33 @@ func checkOverlappingCertificates(gateway *GatewayContext) {
304348

305349
for i, listener := range httpsListeners {
306350
if overlappingListeners[i] != nil {
307-
status.SetGatewayListenerStatusCondition(gateway.Gateway,
308-
listener.listenerStatusIdx,
309-
gwapiv1.ListenerConditionOverlappingTLSConfig,
310-
metav1.ConditionTrue,
311-
gwapiv1.ListenerReasonOverlappingCertificates,
312-
fmt.Sprintf(
351+
var message string
352+
gateway1 := overlappingListeners[i].gateway1
353+
gateway2 := overlappingListeners[i].gateway2
354+
if gateway1.Name == gateway2.Name &&
355+
gateway1.Namespace == gateway2.Namespace {
356+
message = fmt.Sprintf(
313357
"The certificate san %s overlaps with the certificate san %s in listener %s. ALPN is set to HTTP/1.1 to prevent HTTP/2 connection coalescing",
314358
overlappingListeners[i].san1,
315359
overlappingListeners[i].san2,
316360
overlappingListeners[i].listener2,
317-
),
361+
)
362+
} else {
363+
message = fmt.Sprintf(
364+
"The certificate san %s overlaps with the certificate san %s in listener %s of gateway %s. ALPN is set to HTTP/1.1 to prevent HTTP/2 connection coalescing",
365+
overlappingListeners[i].san1,
366+
overlappingListeners[i].san2,
367+
overlappingListeners[i].listener2,
368+
gateway2.GetName(),
369+
)
370+
}
371+
372+
status.SetGatewayListenerStatusCondition(listener.gateway.Gateway,
373+
listener.listenerStatusIdx,
374+
gwapiv1.ListenerConditionOverlappingTLSConfig,
375+
metav1.ConditionTrue,
376+
gwapiv1.ListenerReasonOverlappingCertificates,
377+
message,
318378
)
319379
if listener.httpIR != nil {
320380
listener.httpIR.TLSOverlaps = true

internal/gatewayapi/listener_test.go

+6-27
Original file line numberDiff line numberDiff line change
@@ -306,30 +306,6 @@ func TestCheckOverlappingHostnames(t *testing.T) {
306306
2: "*.example.com",
307307
},
308308
},
309-
{
310-
name: "non-HTTPS listeners",
311-
gateway: &GatewayContext{
312-
listeners: []*ListenerContext{
313-
{
314-
Listener: &gwapiv1.Listener{
315-
Name: "listener-1",
316-
Protocol: gwapiv1.HTTPProtocolType,
317-
Port: 80,
318-
Hostname: ptr.To(gwapiv1.Hostname("example.com")),
319-
},
320-
},
321-
{
322-
Listener: &gwapiv1.Listener{
323-
Name: "listener-2",
324-
Protocol: gwapiv1.HTTPProtocolType,
325-
Port: 80,
326-
Hostname: ptr.To(gwapiv1.Hostname("example.com")),
327-
},
328-
},
329-
},
330-
},
331-
expected: map[int]string{},
332-
},
333309
{
334310
name: "nil hostnames",
335311
gateway: &GatewayContext{
@@ -369,13 +345,14 @@ func TestCheckOverlappingHostnames(t *testing.T) {
369345
}
370346
for i := range tt.gateway.listeners {
371347
tt.gateway.listeners[i].listenerStatusIdx = i
348+
tt.gateway.listeners[i].gateway = tt.gateway
372349
tt.gateway.Gateway.Status.Listeners[i] = gwapiv1.ListenerStatus{
373350
Name: tt.gateway.listeners[i].Listener.Name,
374351
Conditions: []metav1.Condition{},
375352
}
376353
}
377354

378-
checkOverlappingHostnames(tt.gateway)
355+
checkOverlappingHostnames(tt.gateway.listeners)
379356

380357
// Verify the status conditions
381358
for idx, expectedHostname := range tt.expected {
@@ -603,16 +580,18 @@ func TestCheckOverlappingCertificates(t *testing.T) {
603580
listeners: tt.listeners,
604581
}
605582

606-
// Initialize listener status indices
583+
// Initialize listener
607584
for i := range gateway.Gateway.Status.Listeners {
608585
gateway.Gateway.Status.Listeners[i] = gwapiv1.ListenerStatus{
609586
Name: tt.listeners[i].Listener.Name,
610587
Conditions: []metav1.Condition{},
611588
}
589+
gateway.listeners[i].listenerStatusIdx = i
590+
gateway.listeners[i].gateway = gateway
612591
}
613592

614593
// Process overlapping certificates
615-
checkOverlappingCertificates(gateway)
594+
checkOverlappingCertificates(tt.listeners)
616595

617596
// Verify the status conditions
618597
for _, expected := range tt.expectedStatus {

0 commit comments

Comments
 (0)