Skip to content

Commit 868eb5f

Browse files
committed
add reference grant and targetgroup config look up
1 parent 1f1fe70 commit 868eb5f

File tree

5 files changed

+677
-48
lines changed

5 files changed

+677
-48
lines changed

controllers/gateway/gateway_controller.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ var _ Reconciler = &gatewayReconciler{}
3939

4040
// NewNLBGatewayReconciler constructs a gateway reconciler to handle specifically for NLB gateways
4141
func NewNLBGatewayReconciler(routeLoader routeutils.Loader, cloud services.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, networkingSGReconciler networking.SecurityGroupReconciler, networkingSGManager networking.SecurityGroupManager, elbv2TaggingManager elbv2deploy.TaggingManager, subnetResolver networking.SubnetsResolver, vpcInfoProvider networking.VPCInfoProvider, backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger, metricsCollector lbcmetrics.MetricCollector, reconcileCounters *metricsutil.ReconcileCounters) Reconciler {
42-
return newGatewayReconciler(nlbGatewayController, controllerConfig.NLBGatewayMaxConcurrentReconciles, nlbGatewayTagPrefix, nlbGatewayFinalizer, routeLoader, routeutils.L4RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters)
42+
return newGatewayReconciler(nlbGatewayController, controllerConfig.NLBGatewayMaxConcurrentReconciles, nlbGatewayTagPrefix, nlbGatewayFinalizer, routeLoader, routeutils.L4RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters.IncrementNLBGateway)
4343
}
4444

4545
// NewALBGatewayReconciler constructs a gateway reconciler to handle specifically for ALB gateways
4646
func NewALBGatewayReconciler(routeLoader routeutils.Loader, cloud services.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, networkingSGReconciler networking.SecurityGroupReconciler, networkingSGManager networking.SecurityGroupManager, elbv2TaggingManager elbv2deploy.TaggingManager, subnetResolver networking.SubnetsResolver, vpcInfoProvider networking.VPCInfoProvider, backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger, metricsCollector lbcmetrics.MetricCollector, reconcileCounters *metricsutil.ReconcileCounters) Reconciler {
47-
return newGatewayReconciler(albGatewayController, controllerConfig.ALBGatewayMaxConcurrentReconciles, albGatewayTagPrefix, albGatewayFinalizer, routeLoader, routeutils.L7RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters)
47+
return newGatewayReconciler(albGatewayController, controllerConfig.ALBGatewayMaxConcurrentReconciles, albGatewayTagPrefix, albGatewayFinalizer, routeLoader, routeutils.L7RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters.IncrementALBGateway)
4848
}
4949

5050
// newGatewayReconciler constructs a reconciler that responds to gateway object changes
51-
func newGatewayReconciler(controllerName string, maxConcurrentReconciles int, gatewayTagPrefix string, finalizer string, routeLoader routeutils.Loader, routeFilter routeutils.LoadRouteFilter, cloud services.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, networkingSGReconciler networking.SecurityGroupReconciler, networkingSGManager networking.SecurityGroupManager, elbv2TaggingManager elbv2deploy.TaggingManager, subnetResolver networking.SubnetsResolver, vpcInfoProvider networking.VPCInfoProvider, backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger, metricsCollector lbcmetrics.MetricCollector, reconcileCounters *metricsutil.ReconcileCounters) Reconciler {
51+
func newGatewayReconciler(controllerName string, maxConcurrentReconciles int, gatewayTagPrefix string, finalizer string, routeLoader routeutils.Loader, routeFilter routeutils.LoadRouteFilter, cloud services.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, networkingSGReconciler networking.SecurityGroupReconciler, networkingSGManager networking.SecurityGroupManager, elbv2TaggingManager elbv2deploy.TaggingManager, subnetResolver networking.SubnetsResolver, vpcInfoProvider networking.VPCInfoProvider, backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger, metricsCollector lbcmetrics.MetricCollector, reconcileTracker func(namespaceName types.NamespacedName)) Reconciler {
5252

5353
trackingProvider := tracking.NewDefaultProvider(gatewayTagPrefix, controllerConfig.ClusterName)
5454
modelBuilder := gatewaymodel.NewDefaultModelBuilder(subnetResolver, vpcInfoProvider, cloud.VpcID(), trackingProvider, elbv2TaggingManager, cloud.EC2(), controllerConfig.FeatureGates, controllerConfig.ClusterName, controllerConfig.DefaultTags, sets.New(controllerConfig.ExternalManagedTags...), controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, controllerConfig.DefaultLoadBalancerScheme, backendSGProvider, sgResolver, controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules, logger)
@@ -71,7 +71,7 @@ func newGatewayReconciler(controllerName string, maxConcurrentReconciles int, ga
7171
eventRecorder: eventRecorder,
7272
logger: logger,
7373
metricsCollector: metricsCollector,
74-
reconcileCounters: reconcileCounters,
74+
reconcileTracker: reconcileTracker,
7575
}
7676
}
7777

@@ -91,8 +91,8 @@ type gatewayReconciler struct {
9191
eventRecorder record.EventRecorder
9292
logger logr.Logger
9393

94-
metricsCollector lbcmetrics.MetricCollector
95-
reconcileCounters *metricsutil.ReconcileCounters
94+
metricsCollector lbcmetrics.MetricCollector
95+
reconcileTracker func(namespaceName types.NamespacedName)
9696
}
9797

9898
// TODO - Add Gateway and TG configuration permissions
@@ -110,6 +110,7 @@ type gatewayReconciler struct {
110110
//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=tcproutes/finalizers,verbs=update
111111

112112
func (r *gatewayReconciler) Reconcile(ctx context.Context, req reconcile.Request) (ctrl.Result, error) {
113+
r.reconcileTracker(req.NamespacedName)
113114
err := r.reconcileHelper(ctx, req)
114115
if err != nil {
115116
r.logger.Error(err, "Got this error!")

pkg/gateway/routeutils/backend.go

+110-25
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,26 @@ import (
66
"github.com/pkg/errors"
77
corev1 "k8s.io/api/core/v1"
88
"k8s.io/apimachinery/pkg/types"
9+
elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
10+
"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
911
"sigs.k8s.io/controller-runtime/pkg/client"
1012
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
13+
gwbeta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
14+
)
15+
16+
const (
17+
serviceKind = "Service"
1118
)
1219

1320
// Backend an abstraction on the Gateway Backend, meant to hide the underlying backend type from consumers (unless they really want to see it :))
1421
type Backend struct {
15-
Service *corev1.Service
16-
ServicePort *corev1.ServicePort
17-
TypeSpecificBackend interface{}
18-
Weight int
19-
// Add TG config here //
22+
Service *corev1.Service
23+
ELBv2TargetGroupConfig *elbv2gw.TargetGroupConfiguration
24+
ServicePort *corev1.ServicePort
25+
TypeSpecificBackend interface{}
26+
Weight int
2027
}
2128

22-
// TODOs:
23-
// 1/ Add reference grant checking
24-
// 2/ Add target group configuration resolution
25-
26-
// NOTE: Currently routeKind is not used, however, we will need it to load TG specific configuration.
2729
// commonBackendLoader this function will load the services and target group configurations associated with this gateway backend.
2830
func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpecificBackend interface{}, backendRef gwv1.BackendRef, routeIdentifier types.NamespacedName, routeKind string) (*Backend, error) {
2931

@@ -40,23 +42,37 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
4042
return nil, errors.Errorf("Missing port in backend reference")
4143
}
4244

43-
var namespace string
45+
var svcNamespace string
4446
if backendRef.Namespace == nil {
45-
namespace = routeIdentifier.Namespace
47+
svcNamespace = routeIdentifier.Namespace
4648
} else {
47-
namespace = string(*backendRef.Namespace)
49+
svcNamespace = string(*backendRef.Namespace)
4850
}
4951

50-
// TODO - Need to implement reference grant check here
51-
52-
svcName := types.NamespacedName{
53-
Namespace: namespace,
52+
svcIdentifier := types.NamespacedName{
53+
Namespace: svcNamespace,
5454
Name: string(backendRef.Name),
5555
}
56+
57+
// Check for reference grant when performing crossname gateway -> route attachment
58+
if svcNamespace != routeIdentifier.Namespace {
59+
allowed, err := referenceGrantCheck(ctx, k8sClient, svcIdentifier, routeIdentifier, routeKind)
60+
if err != nil {
61+
return nil, errors.Wrapf(err, "Unable to perform reference grant check")
62+
}
63+
64+
// We should not give any hints about the existence of this resource, therefore, we return nil.
65+
// That way, users can't infer if the route is missing because of a misconfigured service reference
66+
// or the sentence grant is not allowing the connection.
67+
if !allowed {
68+
return nil, nil
69+
}
70+
}
71+
5672
svc := &corev1.Service{}
57-
err := k8sClient.Get(ctx, svcName, svc)
73+
err := k8sClient.Get(ctx, svcIdentifier, svc)
5874
if err != nil {
59-
return nil, errors.Wrap(err, fmt.Sprintf("Unable to fetch svc object %+v", svcName))
75+
return nil, errors.Wrap(err, fmt.Sprintf("Unable to fetch svc object %+v", svcIdentifier))
6076
}
6177

6278
var servicePort *corev1.ServicePort
@@ -68,12 +84,16 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
6884
}
6985
}
7086

87+
tgConfig, err := lookUpTargetGroupConfiguration(ctx, k8sClient, k8s.NamespacedName(svc))
88+
89+
if err != nil {
90+
return nil, errors.Wrap(err, fmt.Sprintf("Unable to fetch tg config object"))
91+
}
92+
7193
if servicePort == nil {
7294
return nil, errors.Errorf("Unable to find service port for port %d", *backendRef.Port)
7395
}
7496

75-
// TODO - Need to TG CRD look up here
76-
7797
// Weight specifies the proportion of requests forwarded to the referenced
7898
// backend. This is computed as weight/(sum of all weights in this
7999
// BackendRefs list). For non-zero values, there may be some epsilon from
@@ -90,9 +110,74 @@ func commonBackendLoader(ctx context.Context, k8sClient client.Client, typeSpeci
90110
weight = int(*backendRef.Weight)
91111
}
92112
return &Backend{
93-
Service: svc,
94-
ServicePort: servicePort,
95-
Weight: weight,
96-
TypeSpecificBackend: typeSpecificBackend,
113+
Service: svc,
114+
ServicePort: servicePort,
115+
Weight: weight,
116+
TypeSpecificBackend: typeSpecificBackend,
117+
ELBv2TargetGroupConfig: tgConfig,
97118
}, nil
98119
}
120+
121+
// lookUpTargetGroupConfiguration given a service, lookup the target group configuration associated with the service.
122+
// recall that target group configuration always lives within the same namespace as the service.
123+
func lookUpTargetGroupConfiguration(ctx context.Context, k8sClient client.Client, serviceMetadata types.NamespacedName) (*elbv2gw.TargetGroupConfiguration, error) {
124+
tgConfigList := &elbv2gw.TargetGroupConfigurationList{}
125+
126+
// TODO - Add index
127+
if err := k8sClient.List(ctx, tgConfigList, client.InNamespace(serviceMetadata.Namespace)); err != nil {
128+
return nil, err
129+
}
130+
131+
for _, tgConfig := range tgConfigList.Items {
132+
if tgConfig.Spec.TargetReference.Kind != nil && *tgConfig.Spec.TargetReference.Kind != serviceKind {
133+
continue
134+
}
135+
136+
// TODO - Add a webhook to validate that only one target group config references this service.
137+
// TODO - Add an index for this
138+
if tgConfig.Spec.TargetReference.Name == serviceMetadata.Name {
139+
return &tgConfig, nil
140+
}
141+
}
142+
return nil, nil
143+
}
144+
145+
// Implements the reference grant API
146+
// https://gateway-api.sigs.k8s.io/api-types/referencegrant/
147+
func referenceGrantCheck(ctx context.Context, k8sClient client.Client, svcIdentifier types.NamespacedName, routeIdentifier types.NamespacedName, routeKind string) (bool, error) {
148+
referenceGrantList := &gwbeta1.ReferenceGrantList{}
149+
if err := k8sClient.List(ctx, referenceGrantList, client.InNamespace(svcIdentifier.Namespace)); err != nil {
150+
return false, err
151+
}
152+
153+
for _, grant := range referenceGrantList.Items {
154+
var routeAllowed bool
155+
156+
for _, from := range grant.Spec.From {
157+
// Kind check maybe?
158+
if string(from.Kind) == routeKind && string(from.Namespace) == routeIdentifier.Namespace {
159+
routeAllowed = true
160+
break
161+
}
162+
}
163+
164+
if routeAllowed {
165+
for _, to := range grant.Spec.To {
166+
// As this is a backend reference, we only care about the "Service" Kind.
167+
if to.Kind != serviceKind {
168+
continue
169+
}
170+
171+
// If name is specified, we need to ensure that svc name matches the "to" name.
172+
if to.Name != nil && string(*to.Name) != svcIdentifier.Name {
173+
continue
174+
}
175+
176+
return true, nil
177+
}
178+
179+
}
180+
}
181+
182+
return false, nil
183+
}

0 commit comments

Comments
 (0)