Skip to content

Commit 011edcd

Browse files
authored
[gw api] Reference Grant support to allow cross namespace service access (#4267)
* reference grant event handler * refactor build listener to support ref grants * refactor route utils to support ref grant * reference grant e2e tests * review comments
1 parent 3241ca9 commit 011edcd

37 files changed

+1888
-861
lines changed

config/rbac/role.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,15 @@ rules:
268268
- get
269269
- patch
270270
- update
271+
- apiGroups:
272+
- gateway.networking.k8s.io
273+
resources:
274+
- referencegrants
275+
verbs:
276+
- get
277+
- list
278+
- patch
279+
- watch
271280
- apiGroups:
272281
- gateway.networking.k8s.io
273282
resources:
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package eventhandlers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/go-logr/logr"
7+
"k8s.io/client-go/tools/record"
8+
"k8s.io/client-go/util/workqueue"
9+
"sigs.k8s.io/aws-load-balancer-controller/pkg/gateway/routeutils"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
"sigs.k8s.io/controller-runtime/pkg/event"
12+
"sigs.k8s.io/controller-runtime/pkg/handler"
13+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
14+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
15+
gwalpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
16+
gwbeta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
17+
)
18+
19+
// NewEnqueueRequestsForReferenceGrantEvent creates handler for ReferenceGrant resources
20+
func NewEnqueueRequestsForReferenceGrantEvent(httpRouteEventChan chan<- event.TypedGenericEvent[*gatewayv1.HTTPRoute],
21+
grpcRouteEventChan chan<- event.TypedGenericEvent[*gatewayv1.GRPCRoute],
22+
tcpRouteEventChan chan<- event.TypedGenericEvent[*gwalpha2.TCPRoute],
23+
udpRouteEventChan chan<- event.TypedGenericEvent[*gwalpha2.UDPRoute],
24+
tlsRouteEventChan chan<- event.TypedGenericEvent[*gwalpha2.TLSRoute],
25+
k8sClient client.Client, eventRecorder record.EventRecorder, logger logr.Logger) handler.TypedEventHandler[*gwbeta1.ReferenceGrant, reconcile.Request] {
26+
return &enqueueRequestsForReferenceGrantEvent{
27+
httpRouteEventChan: httpRouteEventChan,
28+
grpcRouteEventChan: grpcRouteEventChan,
29+
tcpRouteEventChan: tcpRouteEventChan,
30+
udpRouteEventChan: udpRouteEventChan,
31+
tlsRouteEventChan: tlsRouteEventChan,
32+
k8sClient: k8sClient,
33+
eventRecorder: eventRecorder,
34+
logger: logger,
35+
}
36+
}
37+
38+
var _ handler.TypedEventHandler[*gwbeta1.ReferenceGrant, reconcile.Request] = (*enqueueRequestsForReferenceGrantEvent)(nil)
39+
40+
// enqueueRequestsForReferenceGrantEvent handles ReferenceGrant events
41+
type enqueueRequestsForReferenceGrantEvent struct {
42+
httpRouteEventChan chan<- event.TypedGenericEvent[*gatewayv1.HTTPRoute]
43+
grpcRouteEventChan chan<- event.TypedGenericEvent[*gatewayv1.GRPCRoute]
44+
tcpRouteEventChan chan<- event.TypedGenericEvent[*gwalpha2.TCPRoute]
45+
udpRouteEventChan chan<- event.TypedGenericEvent[*gwalpha2.UDPRoute]
46+
tlsRouteEventChan chan<- event.TypedGenericEvent[*gwalpha2.TLSRoute]
47+
k8sClient client.Client
48+
eventRecorder record.EventRecorder
49+
logger logr.Logger
50+
}
51+
52+
func (h *enqueueRequestsForReferenceGrantEvent) Create(ctx context.Context, e event.TypedCreateEvent[*gwbeta1.ReferenceGrant], _ workqueue.TypedRateLimitingInterface[reconcile.Request]) {
53+
referenceGrantNew := e.Object
54+
h.logger.V(1).Info("enqueue reference grant create event", "reference grant", referenceGrantNew.Name)
55+
h.enqueueImpactedRoutes(ctx, referenceGrantNew, nil)
56+
}
57+
58+
func (h *enqueueRequestsForReferenceGrantEvent) Update(ctx context.Context, e event.TypedUpdateEvent[*gwbeta1.ReferenceGrant], _ workqueue.TypedRateLimitingInterface[reconcile.Request]) {
59+
referenceGrantNew := e.ObjectNew
60+
referenceGrantOld := e.ObjectOld
61+
h.logger.V(1).Info("enqueue reference grant update event", "reference grant", referenceGrantNew.Name)
62+
h.enqueueImpactedRoutes(ctx, referenceGrantNew, referenceGrantOld)
63+
}
64+
65+
func (h *enqueueRequestsForReferenceGrantEvent) Delete(ctx context.Context, e event.TypedDeleteEvent[*gwbeta1.ReferenceGrant], _ workqueue.TypedRateLimitingInterface[reconcile.Request]) {
66+
refgrant := e.Object
67+
h.logger.V(1).Info("enqueue reference grant delete event", "reference grant", refgrant.Name)
68+
h.enqueueImpactedRoutes(ctx, refgrant, nil)
69+
}
70+
71+
func (h *enqueueRequestsForReferenceGrantEvent) Generic(ctx context.Context, e event.TypedGenericEvent[*gwbeta1.ReferenceGrant], _ workqueue.TypedRateLimitingInterface[reconcile.Request]) {
72+
refgrant := e.Object
73+
h.logger.V(1).Info("enqueue reference grant generic event", "reference grant", refgrant.Name)
74+
h.enqueueImpactedRoutes(ctx, refgrant, nil)
75+
}
76+
77+
func (h *enqueueRequestsForReferenceGrantEvent) enqueueImpactedRoutes(ctx context.Context, newRefGrant *gwbeta1.ReferenceGrant, oldRefGrant *gwbeta1.ReferenceGrant) {
78+
79+
impactedRoutes := make(map[string]gwbeta1.ReferenceGrantFrom)
80+
81+
for i, from := range newRefGrant.Spec.From {
82+
impactedRoutes[generateGrantFromKey(from)] = newRefGrant.Spec.From[i]
83+
}
84+
85+
if oldRefGrant != nil {
86+
for i, from := range oldRefGrant.Spec.From {
87+
impactedRoutes[generateGrantFromKey(from)] = oldRefGrant.Spec.From[i]
88+
}
89+
}
90+
91+
for _, impactedFrom := range impactedRoutes {
92+
switch string(impactedFrom.Kind) {
93+
case string(routeutils.HTTPRouteKind):
94+
if h.httpRouteEventChan == nil {
95+
continue
96+
}
97+
routes, err := routeutils.ListHTTPRoutes(ctx, h.k8sClient, &client.ListOptions{Namespace: string(impactedFrom.Namespace)})
98+
if err == nil {
99+
for _, route := range routes {
100+
h.httpRouteEventChan <- event.TypedGenericEvent[*gatewayv1.HTTPRoute]{
101+
Object: route.GetRawRoute().(*gatewayv1.HTTPRoute),
102+
}
103+
}
104+
105+
} else {
106+
h.logger.Error(err, "Unable to list impacted http routes for reference grant event handler")
107+
}
108+
case string(routeutils.GRPCRouteKind):
109+
if h.grpcRouteEventChan == nil {
110+
continue
111+
}
112+
routes, err := routeutils.ListGRPCRoutes(ctx, h.k8sClient, &client.ListOptions{Namespace: string(impactedFrom.Namespace)})
113+
if err == nil {
114+
for _, route := range routes {
115+
h.grpcRouteEventChan <- event.TypedGenericEvent[*gatewayv1.GRPCRoute]{
116+
Object: route.GetRawRoute().(*gatewayv1.GRPCRoute),
117+
}
118+
}
119+
120+
} else {
121+
h.logger.Error(err, "Unable to list impacted grpc routes for reference grant event handler")
122+
}
123+
case string(routeutils.TCPRouteKind):
124+
if h.tcpRouteEventChan == nil {
125+
continue
126+
}
127+
routes, err := routeutils.ListTCPRoutes(ctx, h.k8sClient, &client.ListOptions{Namespace: string(impactedFrom.Namespace)})
128+
if err == nil {
129+
for _, route := range routes {
130+
h.tcpRouteEventChan <- event.TypedGenericEvent[*gwalpha2.TCPRoute]{
131+
Object: route.GetRawRoute().(*gwalpha2.TCPRoute),
132+
}
133+
}
134+
135+
} else {
136+
h.logger.Error(err, "Unable to list impacted tcp routes for reference grant event handler")
137+
}
138+
case string(routeutils.UDPRouteKind):
139+
if h.udpRouteEventChan == nil {
140+
continue
141+
}
142+
routes, err := routeutils.ListUDPRoutes(ctx, h.k8sClient, &client.ListOptions{Namespace: string(impactedFrom.Namespace)})
143+
if err == nil {
144+
for _, route := range routes {
145+
h.udpRouteEventChan <- event.TypedGenericEvent[*gwalpha2.UDPRoute]{
146+
Object: route.GetRawRoute().(*gwalpha2.UDPRoute),
147+
}
148+
}
149+
150+
} else {
151+
h.logger.Error(err, "Unable to list impacted udp routes for reference grant event handler")
152+
}
153+
case string(routeutils.TLSRouteKind):
154+
if h.tlsRouteEventChan == nil {
155+
continue
156+
}
157+
routes, err := routeutils.ListTLSRoutes(ctx, h.k8sClient, &client.ListOptions{Namespace: string(impactedFrom.Namespace)})
158+
if err == nil {
159+
for _, route := range routes {
160+
h.tlsRouteEventChan <- event.TypedGenericEvent[*gwalpha2.TLSRoute]{
161+
Object: route.GetRawRoute().(*gwalpha2.TLSRoute),
162+
}
163+
}
164+
165+
} else {
166+
h.logger.Error(err, "Unable to list impacted tls routes for reference grant event handler")
167+
}
168+
}
169+
}
170+
}
171+
172+
func generateGrantFromKey(from gwbeta1.ReferenceGrantFrom) string {
173+
return fmt.Sprintf("%s-%s", from.Kind, from.Namespace)
174+
}

controllers/gateway/gateway_controller.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"sigs.k8s.io/controller-runtime/pkg/source"
3939
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
4040
gwalpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
41+
gwbeta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
4142
"time"
4243
)
4344

@@ -125,6 +126,8 @@ type gatewayReconciler struct {
125126
routeReconciler routeutils.RouteReconciler
126127
}
127128

129+
//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=referencegrants,verbs=get;list;watch;patch
130+
128131
//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=gateways,verbs=get;list;watch;patch
129132
//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=gateways/status,verbs=get;update;patch
130133
//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=gateways/finalizers,verbs=update;patch
@@ -457,6 +460,8 @@ func (r *gatewayReconciler) setupALBGatewayControllerWatches(ctrl controller.Con
457460
loggerPrefix.WithName("HTTPRoute"))
458461
svcEventHandler := eventhandlers.NewEnqueueRequestsForServiceEvent(httpRouteEventChan, grpcRouteEventChan, nil, nil, nil, r.k8sClient, r.eventRecorder,
459462
loggerPrefix.WithName("Service"), constants.ALBGatewayController)
463+
refGrantHandler := eventhandlers.NewEnqueueRequestsForReferenceGrantEvent(httpRouteEventChan, grpcRouteEventChan, nil, nil, nil, r.k8sClient, r.eventRecorder,
464+
loggerPrefix.WithName("ReferenceGrant"))
460465
if err := ctrl.Watch(source.Channel(tbConfigEventChan, tgConfigEventHandler)); err != nil {
461466
return err
462467
}
@@ -475,6 +480,9 @@ func (r *gatewayReconciler) setupALBGatewayControllerWatches(ctrl controller.Con
475480
if err := ctrl.Watch(source.Kind(mgr.GetCache(), &corev1.Service{}, svcEventHandler)); err != nil {
476481
return err
477482
}
483+
if err := ctrl.Watch(source.Kind(mgr.GetCache(), &gwbeta1.ReferenceGrant{}, refGrantHandler)); err != nil {
484+
return err
485+
}
478486
if err := ctrl.Watch(source.Kind(mgr.GetCache(), &gwv1.HTTPRoute{}, httpRouteEventHandler)); err != nil {
479487
return err
480488
}
@@ -501,6 +509,8 @@ func (r *gatewayReconciler) setupNLBGatewayControllerWatches(ctrl controller.Con
501509
loggerPrefix.WithName("TLSRoute"))
502510
svcEventHandler := eventhandlers.NewEnqueueRequestsForServiceEvent(nil, nil, tcpRouteEventChan, udpRouteEventChan, tlsRouteEventChan, r.k8sClient, r.eventRecorder,
503511
loggerPrefix.WithName("Service"), constants.NLBGatewayController)
512+
refGrantHandler := eventhandlers.NewEnqueueRequestsForReferenceGrantEvent(nil, nil, tcpRouteEventChan, udpRouteEventChan, tlsRouteEventChan, r.k8sClient, r.eventRecorder,
513+
loggerPrefix.WithName("ReferenceGrant"))
504514
if err := ctrl.Watch(source.Channel(tbConfigEventChan, tgConfigEventHandler)); err != nil {
505515
return err
506516
}
@@ -522,6 +532,9 @@ func (r *gatewayReconciler) setupNLBGatewayControllerWatches(ctrl controller.Con
522532
if err := ctrl.Watch(source.Kind(mgr.GetCache(), &corev1.Service{}, svcEventHandler)); err != nil {
523533
return err
524534
}
535+
if err := ctrl.Watch(source.Kind(mgr.GetCache(), &gwbeta1.ReferenceGrant{}, refGrantHandler)); err != nil {
536+
return err
537+
}
525538
if err := ctrl.Watch(source.Kind(mgr.GetCache(), &gwalpha2.TCPRoute{}, tcpRouteEventHandler)); err != nil {
526539
return err
527540
}

helm/aws-load-balancer-controller/templates/rbac.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ rules:
101101
- apiGroups: ["gateway.networking.k8s.io"]
102102
resources: [gatewayclasses, gateways]
103103
verbs: [get, list, watch, patch]
104+
- apiGroups: ["gateway.networking.k8s.io"]
105+
resources: [referencegrants]
106+
verbs: [get, list, watch]
104107
- apiGroups: ["gateway.networking.k8s.io"]
105108
resources: [gatewayclasses/finalizers, gateways/finalizers]
106109
verbs: [update, patch]

main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"sigs.k8s.io/controller-runtime/pkg/client"
3131
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
3232
gwalpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
33+
gwbeta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
3334
"sync"
3435

3536
"k8s.io/client-go/util/workqueue"
@@ -82,6 +83,7 @@ func init() {
8283
_ = elbv2gw.AddToScheme(scheme)
8384
_ = gwv1.AddToScheme(scheme)
8485
_ = gwalpha2.AddToScheme(scheme)
86+
_ = gwbeta1.AddToScheme(scheme)
8587
// +kubebuilder:scaffold:scheme
8688
}
8789

0 commit comments

Comments
 (0)