@@ -42,6 +42,7 @@ import (
4242 apierrors "k8s.io/apimachinery/pkg/api/errors"
4343 "k8s.io/apimachinery/pkg/api/meta"
4444 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
45+ "k8s.io/apimachinery/pkg/labels"
4546 "k8s.io/apimachinery/pkg/util/runtime"
4647 "k8s.io/apimachinery/pkg/util/wait"
4748 corev1informers "k8s.io/client-go/informers/core/v1"
@@ -55,9 +56,12 @@ import (
5556 "sigs.k8s.io/cloud-provider-kind/pkg/config"
5657 "sigs.k8s.io/cloud-provider-kind/pkg/tunnels"
5758 gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
59+ gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
5860 gatewayclient "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
5961 gatewayinformers "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions/apis/v1"
62+ gatewayinformersv1beta1 "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions/apis/v1beta1"
6063 gatewaylisters "sigs.k8s.io/gateway-api/pkg/client/listers/apis/v1"
64+ gatewaylistersv1beta1 "sigs.k8s.io/gateway-api/pkg/client/listers/apis/v1beta1"
6165)
6266
6367const (
@@ -113,6 +117,9 @@ type Controller struct {
113117 grpcrouteLister gatewaylisters.GRPCRouteLister
114118 grpcrouteListerSynced cache.InformerSynced
115119
120+ referenceGrantLister gatewaylistersv1beta1.ReferenceGrantLister
121+ referenceGrantListerSynced cache.InformerSynced
122+
116123 xdscache cachev3.SnapshotCache
117124 xdsserver serverv3.Server
118125 xdsLocalAddress string
@@ -133,6 +140,7 @@ func New(
133140 gatewayInformer gatewayinformers.GatewayInformer ,
134141 httprouteInformer gatewayinformers.HTTPRouteInformer ,
135142 grpcrouteInformer gatewayinformers.GRPCRouteInformer ,
143+ referenceGrantInformer gatewayinformersv1beta1.ReferenceGrantInformer ,
136144) (* Controller , error ) {
137145 c := & Controller {
138146 clusterName : clusterName ,
@@ -152,10 +160,12 @@ func New(
152160 workqueue .DefaultTypedControllerRateLimiter [string ](),
153161 workqueue.TypedRateLimitingQueueConfig [string ]{Name : "gateway" },
154162 ),
155- httprouteLister : httprouteInformer .Lister (),
156- httprouteListerSynced : httprouteInformer .Informer ().HasSynced ,
157- grpcrouteLister : grpcrouteInformer .Lister (),
158- grpcrouteListerSynced : grpcrouteInformer .Informer ().HasSynced ,
163+ httprouteLister : httprouteInformer .Lister (),
164+ httprouteListerSynced : httprouteInformer .Informer ().HasSynced ,
165+ grpcrouteLister : grpcrouteInformer .Lister (),
166+ grpcrouteListerSynced : grpcrouteInformer .Informer ().HasSynced ,
167+ referenceGrantLister : referenceGrantInformer .Lister (),
168+ referenceGrantListerSynced : referenceGrantInformer .Informer ().HasSynced ,
159169 }
160170 _ , err := gatewayClassInformer .Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
161171 AddFunc : func (obj interface {}) {
@@ -279,6 +289,15 @@ func New(
279289 return nil , err
280290 }
281291
292+ _ , err = referenceGrantInformer .Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
293+ AddFunc : c .processReferenceGrant ,
294+ UpdateFunc : func (old , new interface {}) { c .processReferenceGrant (new ) },
295+ DeleteFunc : c .processReferenceGrant ,
296+ })
297+ if err != nil {
298+ return nil , err
299+ }
300+
282301 if config .DefaultConfig .LoadBalancerConnectivity == config .Tunnel {
283302 c .tunnelManager = tunnels .NewTunnelManager ()
284303 }
@@ -430,6 +449,7 @@ func (c *Controller) Run(ctx context.Context) error {
430449 c .namespaceListerSynced ,
431450 c .serviceListerSynced ,
432451 c .secretListerSynced ,
452+ c .referenceGrantListerSynced ,
433453 ) {
434454 return fmt .Errorf ("timed out waiting for caches to sync" )
435455 }
@@ -463,6 +483,156 @@ func (c *Controller) processGateways(references []gatewayv1.ParentReference, loc
463483 }
464484}
465485
486+ // processReferenceGrant finds all Gateways that may be affected by a change to a
487+ // ReferenceGrant and enqueues them for reconciliation. This function handles grants
488+ // for both cross-namespace BackendRefs (from Routes) and cross-namespace
489+ // SecretRefs (from Gateways).
490+ func (c * Controller ) processReferenceGrant (obj interface {}) {
491+ grant , ok := obj .(* gatewayv1beta1.ReferenceGrant )
492+ if ! ok {
493+ tombstone , ok := obj .(cache.DeletedFinalStateUnknown )
494+ if ! ok {
495+ klog .Errorf ("error decoding object, invalid type" )
496+ return
497+ }
498+ grant , ok = tombstone .Obj .(* gatewayv1beta1.ReferenceGrant )
499+ if ! ok {
500+ klog .Errorf ("error decoding object tombstone, invalid type" )
501+ return
502+ }
503+ }
504+
505+ gatewaysToEnqueue := make (map [string ]struct {})
506+ // The ReferenceGrant lives in the namespace of the resource being referenced (the "To" side).
507+ targetNamespace := grant .Namespace
508+
509+ // Check for Grants allowing Routes to reference Services
510+ for _ , from := range grant .Spec .From {
511+ // As the controller supports more route types, they should be added here.
512+ if ! CloudProviderSupportedKinds .Has (from .Kind ) {
513+ continue
514+ }
515+
516+ // Check if the grant allows references TO a Service.
517+ isServiceGrant := false
518+ for _ , to := range grant .Spec .To {
519+ if to .Kind == "Service" {
520+ isServiceGrant = true
521+ break
522+ }
523+ }
524+ if ! isServiceGrant {
525+ continue
526+ }
527+
528+ // Find all routes in the "From" namespace that could be affected.
529+ httpRoutes , err := c .httprouteLister .HTTPRoutes (string (from .Namespace )).List (labels .Everything ())
530+ if err != nil {
531+ klog .Errorf ("Failed to list HTTPRoutes in namespace %s: %v" , from .Namespace , err )
532+ continue
533+ }
534+
535+ for _ , route := range httpRoutes {
536+ if routeReferencesBackendInNamespace (route , targetNamespace ) {
537+ // This route is affected. Find its parent Gateways and add them to the queue.
538+ for _ , parentRef := range route .Spec .ParentRefs {
539+ if (parentRef .Group != nil && string (* parentRef .Group ) != gatewayv1 .GroupName ) ||
540+ (parentRef .Kind != nil && string (* parentRef .Kind ) != "Gateway" ) {
541+ continue
542+ }
543+ gwNamespace := route .Namespace
544+ if parentRef .Namespace != nil {
545+ gwNamespace = string (* parentRef .Namespace )
546+ }
547+ key := gwNamespace + "/" + string (parentRef .Name )
548+ gatewaysToEnqueue [key ] = struct {}{}
549+ }
550+ }
551+ }
552+ }
553+
554+ // Check for Grants allowing Gateways to reference Secrets
555+ for _ , from := range grant .Spec .From {
556+ // We are looking for grants FROM Gateways.
557+ if from .Group != gatewayv1 .GroupName || from .Kind != "Gateway" {
558+ continue
559+ }
560+
561+ // Check if the grant allows references TO a Secret.
562+ isSecretGrant := false
563+ for _ , to := range grant .Spec .To {
564+ if to .Kind == "Secret" {
565+ isSecretGrant = true
566+ break
567+ }
568+ }
569+ if ! isSecretGrant {
570+ continue
571+ }
572+
573+ // Find all Gateways in the "From" namespace that could be affected.
574+ gateways , err := c .gatewayLister .Gateways (string (from .Namespace )).List (labels .Everything ())
575+ if err != nil {
576+ klog .Errorf ("Failed to list Gateways in namespace %s: %v" , from .Namespace , err )
577+ continue
578+ }
579+
580+ for _ , gw := range gateways {
581+ if gatewayReferencesSecretInNamespace (gw , targetNamespace ) {
582+ // This Gateway is affected. Add it to the queue.
583+ key := gw .Namespace + "/" + gw .Name
584+ gatewaysToEnqueue [key ] = struct {}{}
585+ }
586+ }
587+ }
588+
589+ // Enqueue all unique Gateways that were found to be affected.
590+ for key := range gatewaysToEnqueue {
591+ c .gatewayqueue .Add (key )
592+ }
593+ }
594+
595+ // routeReferencesBackendInNamespace is a helper to check if an HTTPRoute has a backendRef
596+ // pointing to the specified namespace.
597+ func routeReferencesBackendInNamespace (route * gatewayv1.HTTPRoute , namespace string ) bool {
598+ for _ , rule := range route .Spec .Rules {
599+ for _ , backendRef := range rule .BackendRefs {
600+ backendNamespace := route .Namespace
601+ if backendRef .Namespace != nil {
602+ backendNamespace = string (* backendRef .Namespace )
603+ }
604+ if backendNamespace == namespace {
605+ return true
606+ }
607+ }
608+ }
609+ return false
610+ }
611+
612+ // gatewayReferencesSecretInNamespace is a helper to check if a Gateway has a certificateRef
613+ // pointing to a Secret in the specified namespace.
614+ func gatewayReferencesSecretInNamespace (gateway * gatewayv1.Gateway , namespace string ) bool {
615+ for _ , listener := range gateway .Spec .Listeners {
616+ if listener .TLS == nil {
617+ continue
618+ }
619+ for _ , certRef := range listener .TLS .CertificateRefs {
620+ // We only care about references to Secrets.
621+ if (certRef .Group != nil && * certRef .Group != "" ) || (certRef .Kind != nil && * certRef .Kind != "Secret" ) {
622+ continue
623+ }
624+ secretNamespace := gateway .Namespace
625+ if certRef .Namespace != nil {
626+ secretNamespace = string (* certRef .Namespace )
627+ }
628+ if secretNamespace == namespace {
629+ return true
630+ }
631+ }
632+ }
633+ return false
634+ }
635+
466636func (c * Controller ) runGatewayWorker (ctx context.Context ) {
467637 for c .processNextGatewayItem (ctx ) {
468638 }
0 commit comments