Skip to content

Commit ac6857f

Browse files
committed
reject route if not allowed by listener
1 parent 92db570 commit ac6857f

File tree

2 files changed

+193
-24
lines changed

2 files changed

+193
-24
lines changed

internal/mode/static/state/graph/route_common.go

+29-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
apiv1 "k8s.io/api/core/v1"
88
"k8s.io/apimachinery/pkg/labels"
9+
"k8s.io/apimachinery/pkg/runtime/schema"
910
"k8s.io/apimachinery/pkg/types"
1011
"k8s.io/apimachinery/pkg/util/validation/field"
1112
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -354,7 +355,11 @@ func tryToAttachRouteToListeners(
354355
rk := CreateRouteKey(route.Source)
355356

356357
bind := func(l *Listener) (allowed, attached bool) {
357-
if !routeAllowedByListener(l, route.Source.GetNamespace(), gw.Source.Namespace, namespaces) {
358+
if !isRouteNamespaceAllowedByListener(l, route.Source.GetNamespace(), gw.Source.Namespace, namespaces) {
359+
return false, false
360+
}
361+
362+
if !isRouteKindAllowedByListener(l, route.Source.GetObjectKind()) {
358363
return false, false
359364
}
360365

@@ -502,13 +507,14 @@ func GetMoreSpecificHostname(hostname1, hostname2 string) string {
502507
return ""
503508
}
504509

505-
func routeAllowedByListener(
510+
// isRouteNamespaceAllowedByListener checks if the route namespace is allowed by the listener.
511+
func isRouteNamespaceAllowedByListener(
506512
listener *Listener,
507513
routeNS,
508514
gwNS string,
509515
namespaces map[types.NamespacedName]*apiv1.Namespace,
510516
) bool {
511-
if listener.Source.AllowedRoutes != nil {
517+
if listener.Source.AllowedRoutes != nil && listener.Source.AllowedRoutes.Namespaces != nil {
512518
switch *listener.Source.AllowedRoutes.Namespaces.From {
513519
case v1.NamespacesFromAll:
514520
return true
@@ -529,6 +535,26 @@ func routeAllowedByListener(
529535
return true
530536
}
531537

538+
// isRouteKindAllowedByListener checks if the route kind is allowed by the listener.
539+
// If the listener does not specify allowed kinds, all kinds can attach to it.
540+
// If the listener specifies allowed kinds, the route kind must be in the list.
541+
// If the listener specifies HTTPRoute, a GRPCRoute can be attached to it.
542+
func isRouteKindAllowedByListener(listener *Listener, routeKind schema.ObjectKind) bool {
543+
if listener.Source.AllowedRoutes != nil && listener.Source.AllowedRoutes.Kinds != nil {
544+
for _, kind := range listener.Source.AllowedRoutes.Kinds {
545+
routeKind := v1.Kind(routeKind.GroupVersionKind().Kind)
546+
if kind.Kind == routeKind {
547+
return true
548+
}
549+
if kind.Kind == kinds.HTTPRoute && routeKind == kinds.GRPCRoute {
550+
return true
551+
}
552+
}
553+
return false
554+
}
555+
return true
556+
}
557+
532558
func getHostname(h *v1.Hostname) string {
533559
if h == nil {
534560
return ""

internal/mode/static/state/graph/route_common_test.go

+164-21
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ func TestBindRouteToListeners(t *testing.T) {
262262
Namespace: "test",
263263
Name: "hr",
264264
},
265+
TypeMeta: metav1.TypeMeta{
266+
Kind: "HTTPRoute",
267+
},
265268
Spec: gatewayv1.HTTPRouteSpec{
266269
CommonRouteSpec: gatewayv1.CommonRouteSpec{
267270
ParentRefs: []gatewayv1.ParentReference{
@@ -291,9 +294,9 @@ func TestBindRouteToListeners(t *testing.T) {
291294
nil,
292295
)
293296

294-
var normalRoute *L7Route
295-
createNormalRoute := func(gateway *gatewayv1.Gateway) *L7Route {
296-
normalRoute = &L7Route{
297+
var normalHTTPRoute *L7Route
298+
createNormalHTTPRoute := func(gateway *gatewayv1.Gateway) *L7Route {
299+
normalHTTPRoute = &L7Route{
297300
RouteType: RouteTypeHTTP,
298301
Source: hr,
299302
Spec: L7RouteSpec{
@@ -309,10 +312,11 @@ func TestBindRouteToListeners(t *testing.T) {
309312
},
310313
},
311314
}
312-
return normalRoute
315+
return normalHTTPRoute
313316
}
314-
getLastNormalRoute := func() *L7Route {
315-
return normalRoute
317+
318+
getLastNormalHTTPRoute := func() *L7Route {
319+
return normalHTTPRoute
316320
}
317321

318322
invalidAttachableRoute1 := &L7Route{
@@ -430,6 +434,62 @@ func TestBindRouteToListeners(t *testing.T) {
430434
l.Source.Hostname = helpers.GetPointer[gatewayv1.Hostname]("bar.example.com")
431435
})
432436

437+
createGRPCRouteWithSectionNameAndPort := func(
438+
sectionName *gatewayv1.SectionName,
439+
port *gatewayv1.PortNumber,
440+
) *gatewayv1.GRPCRoute {
441+
return &gatewayv1.GRPCRoute{
442+
ObjectMeta: metav1.ObjectMeta{
443+
Namespace: "test",
444+
Name: "hr",
445+
},
446+
TypeMeta: metav1.TypeMeta{
447+
Kind: "GRPCRoute",
448+
},
449+
Spec: gatewayv1.GRPCRouteSpec{
450+
CommonRouteSpec: gatewayv1.CommonRouteSpec{
451+
ParentRefs: []gatewayv1.ParentReference{
452+
{
453+
Name: gatewayv1.ObjectName(gw.Name),
454+
SectionName: sectionName,
455+
Port: port,
456+
},
457+
},
458+
},
459+
Hostnames: []gatewayv1.Hostname{
460+
"foo.example.com",
461+
},
462+
},
463+
}
464+
}
465+
466+
gr := createGRPCRouteWithSectionNameAndPort(helpers.GetPointer[gatewayv1.SectionName]("listener-80-1"), nil)
467+
468+
var normalGRPCRoute *L7Route
469+
createNormalGRPCRoute := func(gateway *gatewayv1.Gateway) *L7Route {
470+
normalGRPCRoute = &L7Route{
471+
RouteType: RouteTypeGRPC,
472+
Source: gr,
473+
Spec: L7RouteSpec{
474+
Hostnames: gr.Spec.Hostnames,
475+
},
476+
Valid: true,
477+
Attachable: true,
478+
ParentRefs: []ParentRef{
479+
{
480+
Idx: 0,
481+
Gateway: client.ObjectKeyFromObject(gateway),
482+
SectionName: gr.Spec.ParentRefs[0].SectionName,
483+
},
484+
},
485+
}
486+
return normalGRPCRoute
487+
}
488+
489+
getLastNormalGRPCRoute := func() *L7Route {
490+
return normalGRPCRoute
491+
}
492+
433493
tests := []struct {
434494
route *L7Route
435495
gateway *Gateway
@@ -439,7 +499,7 @@ func TestBindRouteToListeners(t *testing.T) {
439499
expectedConditions []conditions.Condition
440500
}{
441501
{
442-
route: createNormalRoute(gw),
502+
route: createNormalHTTPRoute(gw),
443503
gateway: &Gateway{
444504
Source: gw,
445505
Valid: true,
@@ -463,7 +523,7 @@ func TestBindRouteToListeners(t *testing.T) {
463523
expectedGatewayListeners: []*Listener{
464524
createModifiedListener("listener-80-1", func(l *Listener) {
465525
l.Routes = map[RouteKey]*L7Route{
466-
CreateRouteKey(hr): getLastNormalRoute(),
526+
CreateRouteKey(hr): getLastNormalHTTPRoute(),
467527
}
468528
}),
469529
},
@@ -620,7 +680,7 @@ func TestBindRouteToListeners(t *testing.T) {
620680
name: "listener doesn't exist",
621681
},
622682
{
623-
route: createNormalRoute(gw),
683+
route: createNormalHTTPRoute(gw),
624684
gateway: &Gateway{
625685
Source: gw,
626686
Valid: true,
@@ -646,7 +706,7 @@ func TestBindRouteToListeners(t *testing.T) {
646706
name: "listener isn't valid and attachable",
647707
},
648708
{
649-
route: createNormalRoute(gw),
709+
route: createNormalHTTPRoute(gw),
650710
gateway: &Gateway{
651711
Source: gw,
652712
Valid: true,
@@ -720,7 +780,7 @@ func TestBindRouteToListeners(t *testing.T) {
720780
name: "route isn't valid",
721781
},
722782
{
723-
route: createNormalRoute(gw),
783+
route: createNormalHTTPRoute(gw),
724784
gateway: &Gateway{
725785
Source: gw,
726786
Valid: false,
@@ -746,7 +806,7 @@ func TestBindRouteToListeners(t *testing.T) {
746806
name: "invalid gateway",
747807
},
748808
{
749-
route: createNormalRoute(gw),
809+
route: createNormalHTTPRoute(gw),
750810
gateway: &Gateway{
751811
Source: gw,
752812
Valid: true,
@@ -773,7 +833,7 @@ func TestBindRouteToListeners(t *testing.T) {
773833
createModifiedListener("listener-80-1", func(l *Listener) {
774834
l.Valid = false
775835
l.Routes = map[RouteKey]*L7Route{
776-
CreateRouteKey(hr): getLastNormalRoute(),
836+
CreateRouteKey(hr): getLastNormalHTTPRoute(),
777837
}
778838
}),
779839
},
@@ -847,7 +907,7 @@ func TestBindRouteToListeners(t *testing.T) {
847907
name: "invalid attachable listener with invalid attachable route",
848908
},
849909
{
850-
route: createNormalRoute(gw),
910+
route: createNormalHTTPRoute(gw),
851911
gateway: &Gateway{
852912
Source: gw,
853913
Valid: true,
@@ -889,7 +949,7 @@ func TestBindRouteToListeners(t *testing.T) {
889949
name: "route not allowed via labels",
890950
},
891951
{
892-
route: createNormalRoute(gw),
952+
route: createNormalHTTPRoute(gw),
893953
gateway: &Gateway{
894954
Source: gw,
895955
Valid: true,
@@ -928,14 +988,14 @@ func TestBindRouteToListeners(t *testing.T) {
928988
},
929989
}
930990
l.Routes = map[RouteKey]*L7Route{
931-
CreateRouteKey(hr): getLastNormalRoute(),
991+
CreateRouteKey(hr): getLastNormalHTTPRoute(),
932992
}
933993
}),
934994
},
935995
name: "route allowed via labels",
936996
},
937997
{
938-
route: createNormalRoute(gwDiffNamespace),
998+
route: createNormalHTTPRoute(gwDiffNamespace),
939999
gateway: &Gateway{
9401000
Source: gwDiffNamespace,
9411001
Valid: true,
@@ -973,7 +1033,7 @@ func TestBindRouteToListeners(t *testing.T) {
9731033
name: "route not allowed via same namespace",
9741034
},
9751035
{
976-
route: createNormalRoute(gw),
1036+
route: createNormalHTTPRoute(gw),
9771037
gateway: &Gateway{
9781038
Source: gw,
9791039
Valid: true,
@@ -1008,14 +1068,14 @@ func TestBindRouteToListeners(t *testing.T) {
10081068
},
10091069
}
10101070
l.Routes = map[RouteKey]*L7Route{
1011-
CreateRouteKey(hr): getLastNormalRoute(),
1071+
CreateRouteKey(hr): getLastNormalHTTPRoute(),
10121072
}
10131073
}),
10141074
},
10151075
name: "route allowed via same namespace",
10161076
},
10171077
{
1018-
route: createNormalRoute(gwDiffNamespace),
1078+
route: createNormalHTTPRoute(gwDiffNamespace),
10191079
gateway: &Gateway{
10201080
Source: gwDiffNamespace,
10211081
Valid: true,
@@ -1050,12 +1110,95 @@ func TestBindRouteToListeners(t *testing.T) {
10501110
},
10511111
}
10521112
l.Routes = map[RouteKey]*L7Route{
1053-
CreateRouteKey(hr): getLastNormalRoute(),
1113+
CreateRouteKey(hr): getLastNormalHTTPRoute(),
10541114
}
10551115
}),
10561116
},
10571117
name: "route allowed via all namespaces",
10581118
},
1119+
{
1120+
route: createNormalHTTPRoute(gw),
1121+
gateway: &Gateway{
1122+
Source: gw,
1123+
Valid: true,
1124+
Listeners: []*Listener{
1125+
createModifiedListener("listener-80-1", func(l *Listener) {
1126+
l.Source.AllowedRoutes = &gatewayv1.AllowedRoutes{
1127+
Kinds: []gatewayv1.RouteGroupKind{
1128+
{Kind: "GRPCRoute"},
1129+
},
1130+
}
1131+
}),
1132+
},
1133+
},
1134+
expectedSectionNameRefs: []ParentRef{
1135+
{
1136+
Idx: 0,
1137+
Gateway: client.ObjectKeyFromObject(gw),
1138+
SectionName: hr.Spec.ParentRefs[0].SectionName,
1139+
Attachment: &ParentRefAttachmentStatus{
1140+
Attached: false,
1141+
FailedCondition: staticConds.NewRouteNotAllowedByListeners(),
1142+
AcceptedHostnames: map[string][]string{},
1143+
},
1144+
},
1145+
},
1146+
expectedGatewayListeners: []*Listener{
1147+
createModifiedListener("listener-80-1", func(l *Listener) {
1148+
l.Source.AllowedRoutes = &gatewayv1.AllowedRoutes{
1149+
Kinds: []gatewayv1.RouteGroupKind{
1150+
{Kind: "GRPCRoute"},
1151+
},
1152+
}
1153+
}),
1154+
},
1155+
name: "http route not allowed when listener allows only grpc routes",
1156+
},
1157+
{
1158+
route: createNormalGRPCRoute(gw),
1159+
gateway: &Gateway{
1160+
Source: gw,
1161+
Valid: true,
1162+
Listeners: []*Listener{
1163+
createModifiedListener("listener-80-1", func(l *Listener) {
1164+
l.Source.AllowedRoutes = &gatewayv1.AllowedRoutes{
1165+
Kinds: []gatewayv1.RouteGroupKind{
1166+
{Kind: "HTTPRoute"},
1167+
},
1168+
}
1169+
l.Routes = map[RouteKey]*L7Route{
1170+
CreateRouteKey(gr): getLastNormalGRPCRoute(),
1171+
}
1172+
}),
1173+
},
1174+
},
1175+
expectedSectionNameRefs: []ParentRef{
1176+
{
1177+
Idx: 0,
1178+
Gateway: client.ObjectKeyFromObject(gw),
1179+
SectionName: gr.Spec.ParentRefs[0].SectionName,
1180+
Attachment: &ParentRefAttachmentStatus{
1181+
Attached: true,
1182+
AcceptedHostnames: map[string][]string{
1183+
"listener-80-1": {"foo.example.com"},
1184+
},
1185+
},
1186+
},
1187+
},
1188+
expectedGatewayListeners: []*Listener{
1189+
createModifiedListener("listener-80-1", func(l *Listener) {
1190+
l.Source.AllowedRoutes = &gatewayv1.AllowedRoutes{
1191+
Kinds: []gatewayv1.RouteGroupKind{
1192+
{Kind: "HTTPRoute"},
1193+
},
1194+
}
1195+
l.Routes = map[RouteKey]*L7Route{
1196+
CreateRouteKey(gr): getLastNormalGRPCRoute(),
1197+
}
1198+
}),
1199+
},
1200+
name: "grpc route allowed when listener kind is HTTPRoute",
1201+
},
10591202
}
10601203

10611204
namespaces := map[types.NamespacedName]*v1.Namespace{

0 commit comments

Comments
 (0)