Skip to content

Commit fa2ab45

Browse files
committed
refactor: Centralize and streamline ReferenceGrant validation
Reorganized and simplified the predicate logic for ReferenceGrant handling across gateway and HTTPRoute controllers. Consolidated duplicate code into reusable functions, reducing redundancy and improving maintainability. This centralization ensures consistent behavior and clearer code structure.
1 parent b18866a commit fa2ab45

File tree

3 files changed

+81
-112
lines changed

3 files changed

+81
-112
lines changed

internal/controller/gateway_controller.go

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
ctrl "sigs.k8s.io/controller-runtime"
2828
"sigs.k8s.io/controller-runtime/pkg/builder"
2929
"sigs.k8s.io/controller-runtime/pkg/client"
30-
"sigs.k8s.io/controller-runtime/pkg/event"
3130
"sigs.k8s.io/controller-runtime/pkg/handler"
3231
"sigs.k8s.io/controller-runtime/pkg/predicate"
3332
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -87,20 +86,7 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
8786
).
8887
Watches(&v1beta1.ReferenceGrant{},
8988
handler.EnqueueRequestsFromMapFunc(r.listReferenceGrantsForGateway),
90-
builder.WithPredicates(predicate.Funcs{
91-
CreateFunc: func(e event.CreateEvent) bool {
92-
return referenceGrantHasGatewayFrom(e.Object)
93-
},
94-
UpdateFunc: func(e event.UpdateEvent) bool {
95-
return referenceGrantHasGatewayFrom(e.ObjectOld) || referenceGrantHasGatewayFrom(e.ObjectNew)
96-
},
97-
DeleteFunc: func(e event.DeleteEvent) bool {
98-
return referenceGrantHasGatewayFrom(e.Object)
99-
},
100-
GenericFunc: func(e event.GenericEvent) bool {
101-
return referenceGrantHasGatewayFrom(e.Object)
102-
},
103-
}),
89+
builder.WithPredicates(referenceGrantPredicates(KindGateway)),
10490
).
10591
Complete(r)
10692
}
@@ -190,7 +176,7 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
190176
}
191177
listenerStatuses, err := getListenerStatus(ctx, r.Client, gateway, referenceGrantList.Items)
192178
if err != nil {
193-
r.Log.Error(err, "failed to get listener status", "gateway", types.NamespacedName{Namespace: gateway.GetNamespace(), Name: gateway.GetName()})
179+
r.Log.Error(err, "failed to get listener status", "gateway", types.NamespacedName{Namespace: gateway.GetNamespace()})
194180
return ctrl.Result{}, err
195181
}
196182

@@ -390,12 +376,12 @@ func (r *GatewayReconciler) listReferenceGrantsForGateway(ctx context.Context, o
390376
}
391377

392378
for _, gateway := range gatewayList.Items {
379+
gw := v1beta1.ReferenceGrantFrom{
380+
Group: gatewayv1.GroupName,
381+
Kind: KindGateway,
382+
Namespace: v1beta1.Namespace(gateway.GetNamespace()),
383+
}
393384
for _, from := range grant.Spec.From {
394-
gw := v1beta1.ReferenceGrantFrom{
395-
Group: gatewayv1.GroupName,
396-
Kind: KindGateway,
397-
Namespace: v1beta1.Namespace(gateway.GetNamespace()),
398-
}
399385
if from == gw {
400386
requests = append(requests, reconcile.Request{
401387
NamespacedName: types.NamespacedName{
@@ -409,19 +395,6 @@ func (r *GatewayReconciler) listReferenceGrantsForGateway(ctx context.Context, o
409395
return requests
410396
}
411397

412-
func referenceGrantHasGatewayFrom(obj client.Object) bool {
413-
grant, ok := obj.(*v1beta1.ReferenceGrant)
414-
if !ok {
415-
return false
416-
}
417-
for _, from := range grant.Spec.From {
418-
if from.Kind == KindGateway && string(from.Group) == gatewayv1.GroupName {
419-
return true
420-
}
421-
}
422-
return false
423-
}
424-
425398
func (r *GatewayReconciler) processInfrastructure(tctx *provider.TranslateContext, gateway *gatewayv1.Gateway) error {
426399
rk := provider.ResourceKind{
427400
Kind: gateway.Kind,

internal/controller/httproute_controller.go

Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error {
104104
).
105105
Watches(&v1beta1.ReferenceGrant{},
106106
handler.EnqueueRequestsFromMapFunc(r.lisHTTPRoutesForReferenceGrant),
107-
builder.WithPredicates(httpRouteReferenceGrantPredicates()),
107+
builder.WithPredicates(referenceGrantPredicates(KindHTTPRoute)),
108108
).
109109
WatchesRawSource(
110110
source.Channel(
@@ -464,7 +464,19 @@ func (r *HTTPRouteReconciler) processHTTPRouteBackendRefs(tctx *provider.Transla
464464
r.Log.Error(err, "failed to list ReferenceGrants", "namespace", targetNN.Namespace)
465465
return err
466466
}
467-
if !checkReferenceGrantBetweenHTTPRouteAndService(hrNN, targetNN, referenceGrantList.Items) {
467+
if !checkReferenceGrant(
468+
v1beta1.ReferenceGrantFrom{
469+
Group: gatewayv1.GroupName,
470+
Kind: KindHTTPRoute,
471+
Namespace: v1beta1.Namespace(hrNN.Namespace),
472+
},
473+
v1beta1.ReferenceGrantTo{
474+
Group: corev1.GroupName,
475+
Kind: KindService,
476+
Name: (*gatewayv1.ObjectName)(&targetNN.Name),
477+
},
478+
referenceGrantList.Items,
479+
) {
468480
terr = ReasonError{
469481
Reason: string(v1beta1.RouteReasonRefNotPermitted),
470482
Message: fmt.Sprintf("%s is in a different namespace than the HTTPRoute %s and no ReferenceGrant allowing reference is configured", targetNN, hrNN),
@@ -639,12 +651,12 @@ func (r *HTTPRouteReconciler) lisHTTPRoutesForReferenceGrant(ctx context.Context
639651
}
640652

641653
for _, httpRoute := range httpRouteList.Items {
654+
hr := v1beta1.ReferenceGrantFrom{
655+
Group: gatewayv1.GroupName,
656+
Kind: KindHTTPRoute,
657+
Namespace: v1beta1.Namespace(httpRoute.GetNamespace()),
658+
}
642659
for _, from := range grant.Spec.From {
643-
hr := v1beta1.ReferenceGrantFrom{
644-
Group: gatewayv1.GroupName,
645-
Kind: KindHTTPRoute,
646-
Namespace: v1beta1.Namespace(httpRoute.GetNamespace()),
647-
}
648660
if from == hr {
649661
requests = append(requests, reconcile.Request{
650662
NamespacedName: client.ObjectKey{
@@ -657,43 +669,3 @@ func (r *HTTPRouteReconciler) lisHTTPRoutesForReferenceGrant(ctx context.Context
657669
}
658670
return requests
659671
}
660-
661-
func httpRouteReferenceGrantPredicates() predicate.Funcs {
662-
var filter = func(obj client.Object) bool {
663-
grant, ok := obj.(*v1beta1.ReferenceGrant)
664-
if !ok {
665-
return false
666-
}
667-
for _, from := range grant.Spec.From {
668-
if from.Kind == KindHTTPRoute && string(from.Group) == gatewayv1.GroupName {
669-
return true
670-
}
671-
}
672-
return false
673-
}
674-
predicates := predicate.NewPredicateFuncs(filter)
675-
predicates.UpdateFunc = func(e event.UpdateEvent) bool {
676-
return filter(e.ObjectOld) || filter(e.ObjectNew)
677-
}
678-
return predicates
679-
}
680-
681-
func checkReferenceGrantBetweenHTTPRouteAndService(hrNN, targetNN types.NamespacedName, grants []v1beta1.ReferenceGrant) bool {
682-
hr := v1beta1.ReferenceGrantFrom{
683-
Group: gatewayv1.GroupName,
684-
Kind: KindHTTPRoute,
685-
Namespace: v1beta1.Namespace(hrNN.Namespace),
686-
}
687-
for _, grant := range grants {
688-
fromHTTPRoute := slices.ContainsFunc(grant.Spec.From, func(from v1beta1.ReferenceGrantFrom) bool {
689-
return from == hr
690-
})
691-
toService := slices.ContainsFunc(grant.Spec.To, func(to v1beta1.ReferenceGrantTo) bool {
692-
return to.Group == corev1.GroupName && to.Kind == KindService && (to.Name == nil || string(*to.Name) == targetNN.Name)
693-
})
694-
if fromHTTPRoute && toService {
695-
return true
696-
}
697-
}
698-
return false
699-
}

internal/controller/utils.go

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package controller
1414

1515
import (
16+
"cmp"
1617
"context"
1718
"encoding/pem"
1819
"errors"
@@ -31,6 +32,8 @@ import (
3132
"k8s.io/apimachinery/pkg/labels"
3233
"k8s.io/apimachinery/pkg/types"
3334
"sigs.k8s.io/controller-runtime/pkg/client"
35+
"sigs.k8s.io/controller-runtime/pkg/event"
36+
"sigs.k8s.io/controller-runtime/pkg/predicate"
3437
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3538
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
3639
"sigs.k8s.io/gateway-api/apis/v1beta1"
@@ -736,19 +739,32 @@ func getListenerStatus(
736739
conditionProgrammed.Reason = string(gatewayv1.ListenerReasonInvalid)
737740
break
738741
}
739-
if ok := checkReferenceGrantBetweenGatewayAndSecret(gateway.Namespace, ref, grants); !ok {
740-
conditionResolvedRefs.Status = metav1.ConditionFalse
741-
conditionResolvedRefs.Reason = string(gatewayv1.ListenerReasonRefNotPermitted)
742-
conditionResolvedRefs.Message = "certificateRefs cross namespaces is not permitted"
743-
conditionProgrammed.Status = metav1.ConditionFalse
744-
conditionProgrammed.Reason = string(gatewayv1.ListenerReasonInvalid)
745-
break
746-
}
747-
ns := gateway.Namespace
748-
if ref.Namespace != nil {
749-
ns = string(*ref.Namespace)
742+
// if cross namespaces, check if the Gateway has the permission to access the Secret
743+
if ref.Namespace != nil && string(*ref.Namespace) != gateway.Namespace {
744+
if ok := checkReferenceGrant(
745+
v1beta1.ReferenceGrantFrom{
746+
Group: gatewayv1.GroupName,
747+
Kind: KindGateway,
748+
Namespace: v1beta1.Namespace(gateway.Namespace),
749+
},
750+
v1beta1.ReferenceGrantTo{
751+
Group: corev1.GroupName,
752+
Kind: KindSecret,
753+
Name: &ref.Name,
754+
},
755+
grants,
756+
); !ok {
757+
conditionResolvedRefs.Status = metav1.ConditionFalse
758+
conditionResolvedRefs.Reason = string(gatewayv1.ListenerReasonRefNotPermitted)
759+
conditionResolvedRefs.Message = "certificateRefs cross namespaces is not permitted"
760+
conditionProgrammed.Status = metav1.ConditionFalse
761+
conditionProgrammed.Reason = string(gatewayv1.ListenerReasonInvalid)
762+
break
763+
}
750764
}
751-
if err := mrgc.Get(ctx, client.ObjectKey{Namespace: ns, Name: string(ref.Name)}, &secret); err != nil {
765+
766+
ns := cmp.Or(ref.Namespace, (*gatewayv1.Namespace)(&gateway.Namespace))
767+
if err := mrgc.Get(ctx, client.ObjectKey{Namespace: string(*ns), Name: string(ref.Name)}, &secret); err != nil {
752768
conditionResolvedRefs.Status = metav1.ConditionFalse
753769
conditionResolvedRefs.Reason = string(gatewayv1.ListenerReasonInvalidCertificateRef)
754770
conditionResolvedRefs.Message = err.Error()
@@ -1070,28 +1086,36 @@ func isTLSSecretValid(secret *corev1.Secret) (string, bool) {
10701086
return "", true
10711087
}
10721088

1073-
func checkReferenceGrantBetweenGatewayAndSecret(gwNamespace string, certRef gatewayv1.SecretObjectReference, grants []v1beta1.ReferenceGrant) bool {
1074-
// if not cross namespaces
1075-
if certRef.Namespace == nil || string(*certRef.Namespace) == gwNamespace {
1076-
return true
1089+
func referenceGrantPredicates(kind gatewayv1.Kind) predicate.Funcs {
1090+
var filter = func(obj client.Object) bool {
1091+
grant, ok := obj.(*v1beta1.ReferenceGrant)
1092+
if !ok {
1093+
return false
1094+
}
1095+
for _, from := range grant.Spec.From {
1096+
if from.Kind == kind && string(from.Group) == gatewayv1.GroupName {
1097+
return true
1098+
}
1099+
}
1100+
return false
1101+
}
1102+
predicates := predicate.NewPredicateFuncs(filter)
1103+
predicates.UpdateFunc = func(e event.UpdateEvent) bool {
1104+
return filter(e.ObjectOld) || filter(e.ObjectNew)
10771105
}
1106+
return predicates
1107+
}
10781108

1109+
func checkReferenceGrant(from v1beta1.ReferenceGrantFrom, to v1beta1.ReferenceGrantTo, grants []v1beta1.ReferenceGrant) bool {
10791110
for _, grant := range grants {
1080-
if grant.Namespace == string(*certRef.Namespace) {
1081-
for _, from := range grant.Spec.From {
1082-
gw := v1beta1.ReferenceGrantFrom{
1083-
Group: gatewayv1.GroupName,
1084-
Kind: KindGateway,
1085-
Namespace: v1beta1.Namespace(gwNamespace),
1086-
}
1087-
if from == gw {
1088-
for _, to := range grant.Spec.To {
1089-
if to.Group == corev1.GroupName && to.Kind == KindSecret && (to.Name == nil || *to.Name == certRef.Name) {
1090-
return true
1091-
}
1092-
}
1093-
}
1094-
}
1111+
grantFrom := slices.ContainsFunc(grant.Spec.From, func(item v1beta1.ReferenceGrantFrom) bool {
1112+
return item == from
1113+
})
1114+
grantTo := slices.ContainsFunc(grant.Spec.To, func(item v1beta1.ReferenceGrantTo) bool {
1115+
return item.Group == to.Group && item.Kind == to.Kind && to.Name != nil && (item.Name == nil || *item.Name == *to.Name)
1116+
})
1117+
if grantFrom && grantTo {
1118+
return true
10951119
}
10961120
}
10971121
return false

0 commit comments

Comments
 (0)