Skip to content

Commit 9f7cd52

Browse files
author
VikramBedi
committed
feat: implement Gateway API allowedRoutes namespace and kind validation
1 parent 6e0d020 commit 9f7cd52

File tree

9 files changed

+3420
-458
lines changed

9 files changed

+3420
-458
lines changed

pkg/controllers/route_controller.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,14 @@ func (r *routeReconciler) validateRoute(ctx context.Context, route core.Route) e
473473
return fmt.Errorf("validate route: %w", err)
474474
}
475475

476+
if core.HasAllParentRefsRejected(route) {
477+
r.eventRecorder.Event(route.K8sObject(), corev1.EventTypeWarning,
478+
k8s.RouteEventReasonFailedBuildModel,
479+
"No VPC Lattice resources created. Route's parentRefs rejected by all Gateway listeners due to allowedRoutes policies. Check route status conditions for more detail.")
480+
return fmt.Errorf("%w: route has validation errors, see status", ErrValidation)
481+
}
482+
483+
// Additional broader validation check for any issues
476484
if r.hasNotAcceptedCondition(route) {
477485
return fmt.Errorf("%w: route has validation errors, see status", ErrValidation)
478486
}
@@ -500,8 +508,9 @@ func (r *routeReconciler) hasNotAcceptedCondition(route core.Route) bool {
500508
//
501509
// If parent GW exists will check:
502510
// - NoMatchingParent: parentRef sectionName and port matches Listener name and port
511+
// - NotAllowedByListeners: listener allowedRoutes.namespaces allows route
512+
// - NotAllowedByListeners: listener allowedRoutes.kinds contains route GroupKind
503513
// - TODO: NoMatchingListenerHostname: listener hostname matches one of route hostnames
504-
// - TODO: NotAllowedByListeners: listener allowedRoutes contains route GroupKind
505514
func (r *routeReconciler) validateRouteParentRefs(ctx context.Context, route core.Route) ([]gwv1.RouteParentStatus, error) {
506515
if len(route.Spec().ParentRefs()) == 0 {
507516
return nil, ErrParentRefsNotFound
@@ -516,6 +525,8 @@ func (r *routeReconciler) validateRouteParentRefs(ctx context.Context, route cor
516525
gw := gws[0]
517526
for _, parentRef := range route.Spec().ParentRefs() {
518527
noMatchingParent := true
528+
notAllowedByAnyMatchingListener := true
529+
519530
for _, listener := range gw.Spec.Listeners {
520531
if parentRef.Port != nil && *parentRef.Port != listener.Port {
521532
continue
@@ -524,6 +535,16 @@ func (r *routeReconciler) validateRouteParentRefs(ctx context.Context, route cor
524535
continue
525536
}
526537
noMatchingParent = false
538+
539+
allowed, err := core.IsRouteAllowedByListener(ctx, r.client, route, gw, listener)
540+
if err != nil {
541+
return nil, err
542+
}
543+
544+
if allowed {
545+
notAllowedByAnyMatchingListener = false
546+
break
547+
}
527548
}
528549

529550
parentStatus := gwv1.RouteParentStatus{
@@ -536,6 +557,9 @@ func (r *routeReconciler) validateRouteParentRefs(ctx context.Context, route cor
536557
switch {
537558
case noMatchingParent:
538559
cnd = r.newCondition(route, gwv1.RouteConditionAccepted, gwv1.RouteReasonNoMatchingParent, "")
560+
case notAllowedByAnyMatchingListener:
561+
cnd = r.newCondition(route, gwv1.RouteConditionAccepted, gwv1.RouteReasonNotAllowedByListeners,
562+
"No matching listeners allow this route. Check Gateway listener allowedRoutes policies")
539563
default:
540564
cnd = r.newCondition(route, gwv1.RouteConditionAccepted, gwv1.RouteReasonAccepted, "")
541565
}

pkg/gateway/model_build_lattice_service.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ func (t *latticeServiceModelBuildTask) buildModel(ctx context.Context) error {
7474
return err
7575
}
7676

77+
if modelSvc == nil {
78+
t.log.Debugf(ctx, "Service creation skipped no further processing needed")
79+
return nil
80+
}
81+
7782
err = t.buildListeners(ctx, modelSvc.ID())
7883
if err != nil {
7984
return fmt.Errorf("failed to build listener due to %w", err)
@@ -103,6 +108,11 @@ func (t *latticeServiceModelBuildTask) buildModel(ctx context.Context) error {
103108
}
104109

105110
func (t *latticeServiceModelBuildTask) buildLatticeService(ctx context.Context) (*model.Service, error) {
111+
if core.HasAllParentRefsRejected(t.route) {
112+
t.log.Debugf(ctx, "Skipping VPC Lattice Service creation all parentRefs rejected")
113+
return nil, nil
114+
}
115+
106116
var routeType core.RouteType
107117
switch t.route.(type) {
108118
case *core.HTTPRoute:
@@ -141,7 +151,15 @@ func (t *latticeServiceModelBuildTask) buildLatticeService(ctx context.Context)
141151

142152
if !standalone {
143153
// Standard mode: populate ServiceNetworkNames from parent references
154+
155+
// For deduping ServiceNetworkNames since 2 parentRefs can point to same ServiceNetwork(Gateway)
156+
serviceNetworkSet := make(map[string]struct{})
144157
for _, parentRef := range t.route.Spec().ParentRefs() {
158+
if !core.IsParentRefAccepted(t.route, parentRef) {
159+
t.log.Debugf(ctx, "Skipping service network association for rejected parentRef %s", parentRef.Name)
160+
continue
161+
}
162+
145163
gw := &gwv1.Gateway{}
146164
parentNamespace := t.route.Namespace()
147165
if parentRef.Namespace != nil {
@@ -153,11 +171,16 @@ func (t *latticeServiceModelBuildTask) buildLatticeService(ctx context.Context)
153171
continue
154172
}
155173
if k8s.IsControlledByLatticeGatewayController(ctx, t.client, gw) {
156-
spec.ServiceNetworkNames = append(spec.ServiceNetworkNames, string(parentRef.Name))
174+
serviceNetworkSet[string(parentRef.Name)] = struct{}{}
157175
} else {
158176
t.log.Infof(ctx, "Ignoring route %s because gateway %s is not managed by lattice gateway controller", t.route.Name(), gw.Name)
159177
}
160178
}
179+
180+
for serviceNetwork := range serviceNetworkSet {
181+
spec.ServiceNetworkNames = append(spec.ServiceNetworkNames, serviceNetwork)
182+
}
183+
161184
if config.ServiceNetworkOverrideMode {
162185
spec.ServiceNetworkNames = []string{config.DefaultServiceNetwork}
163186
}

0 commit comments

Comments
 (0)