Skip to content

Commit ff8c13d

Browse files
authored
refactor backend SG provider (#2836)
* refactor backend SG provider * fix ExtractIngresses array append * make classifiedIngress type satisfy ObjectMetaAccessor * refactor backend SG provider apis
1 parent 4cf7c33 commit ff8c13d

15 files changed

+947
-125
lines changed

controllers/ingress/group_controller.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
corev1 "k8s.io/api/core/v1"
1010
networking "k8s.io/api/networking/v1"
1111
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/types"
1213
"k8s.io/client-go/kubernetes"
1314
"k8s.io/client-go/tools/record"
1415
elbv2api "sigs.k8s.io/aws-load-balancer-controller/apis/elbv2/v1beta1"
@@ -45,7 +46,8 @@ const (
4546
func NewGroupReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder,
4647
finalizerManager k8s.FinalizerManager, networkingSGManager networkingpkg.SecurityGroupManager,
4748
networkingSGReconciler networkingpkg.SecurityGroupReconciler, subnetsResolver networkingpkg.SubnetsResolver,
48-
controllerConfig config.ControllerConfig, backendSGProvider networkingpkg.BackendSGProvider, logger logr.Logger) *groupReconciler {
49+
controllerConfig config.ControllerConfig, backendSGProvider networkingpkg.BackendSGProvider,
50+
sgResolver networkingpkg.SecurityGroupResolver, logger logr.Logger) *groupReconciler {
4951

5052
annotationParser := annotations.NewSuffixAnnotationParser(annotations.AnnotationPrefixIngress)
5153
authConfigBuilder := ingress.NewDefaultAuthConfigBuilder(annotationParser)
@@ -58,7 +60,7 @@ func NewGroupReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorder
5860
annotationParser, subnetsResolver,
5961
authConfigBuilder, enhancedBackendBuilder, trackingProvider, elbv2TaggingManager, controllerConfig.FeatureGates,
6062
cloud.VpcID(), controllerConfig.ClusterName, controllerConfig.DefaultTags, controllerConfig.ExternalManagedTags,
61-
controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, backendSGProvider,
63+
controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, backendSGProvider, sgResolver,
6264
controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules, controllerConfig.FeatureGates.Enabled(config.EnableIPTargetType), logger)
6365
stackMarshaller := deploy.NewDefaultStackMarshaller()
6466
stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler,
@@ -144,12 +146,6 @@ func (r *groupReconciler) reconcile(ctx context.Context, req ctrl.Request) error
144146
}
145147
}
146148

147-
if len(ingGroup.Members) == 0 {
148-
if err := r.backendSGProvider.Release(ctx); err != nil {
149-
return err
150-
}
151-
}
152-
153149
if len(ingGroup.InactiveMembers) > 0 {
154150
if err := r.groupFinalizerManager.RemoveGroupFinalizer(ctx, ingGroupID, ingGroup.InactiveMembers); err != nil {
155151
r.recordIngressGroupEvent(ctx, ingGroup, corev1.EventTypeWarning, k8s.IngressEventReasonFailedRemoveFinalizer, fmt.Sprintf("Failed remove finalizer due to %v", err))
@@ -162,7 +158,7 @@ func (r *groupReconciler) reconcile(ctx context.Context, req ctrl.Request) error
162158
}
163159

164160
func (r *groupReconciler) buildAndDeployModel(ctx context.Context, ingGroup ingress.Group) (core.Stack, *elbv2model.LoadBalancer, error) {
165-
stack, lb, secrets, err := r.modelBuilder.Build(ctx, ingGroup)
161+
stack, lb, secrets, backendSGRequired, err := r.modelBuilder.Build(ctx, ingGroup)
166162
if err != nil {
167163
r.recordIngressGroupEvent(ctx, ingGroup, corev1.EventTypeWarning, k8s.IngressEventReasonFailedBuildModel, fmt.Sprintf("Failed build model due to %v", err))
168164
return nil, nil, err
@@ -180,7 +176,15 @@ func (r *groupReconciler) buildAndDeployModel(ctx context.Context, ingGroup ingr
180176
}
181177
r.logger.Info("successfully deployed model", "ingressGroup", ingGroup.ID)
182178
r.secretsManager.MonitorSecrets(ingGroup.ID.String(), secrets)
183-
return stack, lb, err
179+
var inactiveResources []types.NamespacedName
180+
inactiveResources = append(inactiveResources, k8s.ToSliceOfNamespacedNames(ingGroup.InactiveMembers)...)
181+
if !backendSGRequired {
182+
inactiveResources = append(inactiveResources, k8s.ToSliceOfNamespacedNames(ingGroup.Members)...)
183+
}
184+
if err := r.backendSGProvider.Release(ctx, networkingpkg.ResourceTypeIngress, inactiveResources); err != nil {
185+
return nil, nil, err
186+
}
187+
return stack, lb, nil
184188
}
185189

186190
func (r *groupReconciler) recordIngressGroupEvent(_ context.Context, ingGroup ingress.Group, eventType string, reason string, message string) {

main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,10 @@ func main() {
111111
mgr.GetEventRecorderFor("targetGroupBinding"), ctrl.Log)
112112
backendSGProvider := networking.NewBackendSGProvider(controllerCFG.ClusterName, controllerCFG.BackendSecurityGroup,
113113
cloud.VpcID(), cloud.EC2(), mgr.GetClient(), controllerCFG.DefaultTags, ctrl.Log.WithName("backend-sg-provider"))
114+
sgResolver := networking.NewDefaultSecurityGroupResolver(cloud.EC2(), cloud.VpcID())
114115
ingGroupReconciler := ingress.NewGroupReconciler(cloud, mgr.GetClient(), mgr.GetEventRecorderFor("ingress"),
115116
finalizerManager, sgManager, sgReconciler, subnetResolver,
116-
controllerCFG, backendSGProvider, ctrl.Log.WithName("controllers").WithName("ingress"))
117+
controllerCFG, backendSGProvider, sgResolver, ctrl.Log.WithName("controllers").WithName("ingress"))
117118
svcReconciler := service.NewServiceReconciler(cloud, mgr.GetClient(), mgr.GetEventRecorderFor("service"),
118119
finalizerManager, sgManager, sgReconciler, subnetResolver, vpcInfoProvider,
119120
controllerCFG, ctrl.Log.WithName("controllers").WithName("service"))

pkg/deploy/elbv2/listener_manager.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package elbv2
22

33
import (
44
"context"
5+
"time"
6+
57
awssdk "github.com/aws/aws-sdk-go/aws"
68
elbv2sdk "github.com/aws/aws-sdk-go/service/elbv2"
79
"github.com/go-logr/logr"
@@ -15,7 +17,6 @@ import (
1517
elbv2equality "sigs.k8s.io/aws-load-balancer-controller/pkg/equality/elbv2"
1618
elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
1719
"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
18-
"time"
1920
)
2021

2122
// ListenerManager is responsible for create/update/delete Listener resources.

pkg/ingress/class.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ingress
22

33
import (
44
networking "k8s.io/api/networking/v1"
5+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
56
elbv2api "sigs.k8s.io/aws-load-balancer-controller/apis/elbv2/v1beta1"
67
)
78

@@ -19,3 +20,7 @@ type ClassConfiguration struct {
1920
// The IngressClassParams for Ingress if any.
2021
IngClassParams *elbv2api.IngressClassParams
2122
}
23+
24+
func (c ClassifiedIngress) GetObjectMeta() metav1.Object {
25+
return c.Ing
26+
}

pkg/ingress/model_build_load_balancer.go

Lines changed: 5 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"encoding/hex"
77
"fmt"
88
"regexp"
9-
"strings"
109

1110
awssdk "github.com/aws/aws-sdk-go/aws"
1211
ec2sdk "github.com/aws/aws-sdk-go/service/ec2"
@@ -284,11 +283,12 @@ func (t *defaultModelBuildTask) buildLoadBalancerSecurityGroups(ctx context.Cont
284283
if !t.enableBackendSG {
285284
t.backendSGIDToken = managedSG.GroupID()
286285
} else {
287-
backendSGID, err := t.backendSGProvider.Get(ctx)
286+
backendSGID, err := t.backendSGProvider.Get(ctx, networking.ResourceTypeIngress, k8s.ToSliceOfNamespacedNames(t.ingGroup.Members))
288287
if err != nil {
289288
return nil, err
290289
}
291290
t.backendSGIDToken = core.LiteralStringToken((backendSGID))
291+
t.backendSGAllocated = true
292292
lbSGTokens = append(lbSGTokens, t.backendSGIDToken)
293293
}
294294
t.logger.Info("Auto Create SG", "LB SGs", lbSGTokens, "backend SG", t.backendSGIDToken)
@@ -297,7 +297,7 @@ func (t *defaultModelBuildTask) buildLoadBalancerSecurityGroups(ctx context.Cont
297297
if err != nil {
298298
return nil, err
299299
}
300-
frontendSGIDs, err := t.resolveSecurityGroupIDsViaNameOrIDSlice(ctx, sgNameOrIDsViaAnnotation)
300+
frontendSGIDs, err := t.sgResolver.ResolveViaNameOrID(ctx, sgNameOrIDsViaAnnotation)
301301
if err != nil {
302302
return nil, err
303303
}
@@ -309,11 +309,12 @@ func (t *defaultModelBuildTask) buildLoadBalancerSecurityGroups(ctx context.Cont
309309
if !t.enableBackendSG {
310310
return nil, errors.New("backendSG feature is required to manage worker node SG rules when frontendSG manually specified")
311311
}
312-
backendSGID, err := t.backendSGProvider.Get(ctx)
312+
backendSGID, err := t.backendSGProvider.Get(ctx, networking.ResourceTypeIngress, k8s.ToSliceOfNamespacedNames(t.ingGroup.Members))
313313
if err != nil {
314314
return nil, err
315315
}
316316
t.backendSGIDToken = core.LiteralStringToken(backendSGID)
317+
t.backendSGAllocated = true
317318
lbSGTokens = append(lbSGTokens, t.backendSGIDToken)
318319
}
319320
t.logger.Info("SG configured via annotation", "LB SGs", lbSGTokens, "backend SG", t.backendSGIDToken)
@@ -390,56 +391,6 @@ func (t *defaultModelBuildTask) buildLoadBalancerTags(_ context.Context) (map[st
390391
return algorithm.MergeStringMap(t.defaultTags, ingGroupTags), nil
391392
}
392393

393-
func (t *defaultModelBuildTask) resolveSecurityGroupIDsViaNameOrIDSlice(ctx context.Context, sgNameOrIDs []string) ([]string, error) {
394-
var sgIDs []string
395-
var sgNames []string
396-
for _, nameOrID := range sgNameOrIDs {
397-
if strings.HasPrefix(nameOrID, "sg-") {
398-
sgIDs = append(sgIDs, nameOrID)
399-
} else {
400-
sgNames = append(sgNames, nameOrID)
401-
}
402-
}
403-
var resolvedSGs []*ec2sdk.SecurityGroup
404-
if len(sgIDs) > 0 {
405-
req := &ec2sdk.DescribeSecurityGroupsInput{
406-
GroupIds: awssdk.StringSlice(sgIDs),
407-
}
408-
sgs, err := t.ec2Client.DescribeSecurityGroupsAsList(ctx, req)
409-
if err != nil {
410-
return nil, err
411-
}
412-
resolvedSGs = append(resolvedSGs, sgs...)
413-
}
414-
if len(sgNames) > 0 {
415-
req := &ec2sdk.DescribeSecurityGroupsInput{
416-
Filters: []*ec2sdk.Filter{
417-
{
418-
Name: awssdk.String("tag:Name"),
419-
Values: awssdk.StringSlice(sgNames),
420-
},
421-
{
422-
Name: awssdk.String("vpc-id"),
423-
Values: awssdk.StringSlice([]string{t.vpcID}),
424-
},
425-
},
426-
}
427-
sgs, err := t.ec2Client.DescribeSecurityGroupsAsList(ctx, req)
428-
if err != nil {
429-
return nil, err
430-
}
431-
resolvedSGs = append(resolvedSGs, sgs...)
432-
}
433-
resolvedSGIDs := make([]string, 0, len(resolvedSGs))
434-
for _, sg := range resolvedSGs {
435-
resolvedSGIDs = append(resolvedSGIDs, awssdk.StringValue(sg.GroupId))
436-
}
437-
if len(resolvedSGIDs) != len(sgNameOrIDs) {
438-
return nil, errors.Errorf("couldn't find all securityGroups, nameOrIDs: %v, found: %v", sgNameOrIDs, resolvedSGIDs)
439-
}
440-
return resolvedSGIDs, nil
441-
}
442-
443394
func buildLoadBalancerSubnetMappingsWithSubnets(subnets []*ec2sdk.Subnet) []elbv2model.SubnetMapping {
444395
subnetMappings := make([]elbv2model.SubnetMapping, 0, len(subnets))
445396
for _, subnet := range subnets {

pkg/ingress/model_builder.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const (
3232
// ModelBuilder is responsible for build mode stack for a IngressGroup.
3333
type ModelBuilder interface {
3434
// build mode stack for a IngressGroup.
35-
Build(ctx context.Context, ingGroup Group) (core.Stack, *elbv2model.LoadBalancer, []types.NamespacedName, error)
35+
Build(ctx context.Context, ingGroup Group) (core.Stack, *elbv2model.LoadBalancer, []types.NamespacedName, bool, error)
3636
}
3737

3838
// NewDefaultModelBuilder constructs new defaultModelBuilder.
@@ -42,7 +42,8 @@ func NewDefaultModelBuilder(k8sClient client.Client, eventRecorder record.EventR
4242
authConfigBuilder AuthConfigBuilder, enhancedBackendBuilder EnhancedBackendBuilder,
4343
trackingProvider tracking.Provider, elbv2TaggingManager elbv2deploy.TaggingManager, featureGates config.FeatureGates,
4444
vpcID string, clusterName string, defaultTags map[string]string, externalManagedTags []string, defaultSSLPolicy string, defaultTargetType string,
45-
backendSGProvider networkingpkg.BackendSGProvider, enableBackendSG bool, disableRestrictedSGRules bool, enableIPTargetType bool, logger logr.Logger) *defaultModelBuilder {
45+
backendSGProvider networkingpkg.BackendSGProvider, sgResolver networkingpkg.SecurityGroupResolver,
46+
enableBackendSG bool, disableRestrictedSGRules bool, enableIPTargetType bool, logger logr.Logger) *defaultModelBuilder {
4647
certDiscovery := NewACMCertDiscovery(acmClient, logger)
4748
ruleOptimizer := NewDefaultRuleOptimizer(logger)
4849
return &defaultModelBuilder{
@@ -54,6 +55,7 @@ func NewDefaultModelBuilder(k8sClient client.Client, eventRecorder record.EventR
5455
annotationParser: annotationParser,
5556
subnetsResolver: subnetsResolver,
5657
backendSGProvider: backendSGProvider,
58+
sgResolver: sgResolver,
5759
certDiscovery: certDiscovery,
5860
authConfigBuilder: authConfigBuilder,
5961
enhancedBackendBuilder: enhancedBackendBuilder,
@@ -86,6 +88,7 @@ type defaultModelBuilder struct {
8688
annotationParser annotations.Parser
8789
subnetsResolver networkingpkg.SubnetsResolver
8890
backendSGProvider networkingpkg.BackendSGProvider
91+
sgResolver networkingpkg.SecurityGroupResolver
8992
certDiscovery CertDiscovery
9093
authConfigBuilder AuthConfigBuilder
9194
enhancedBackendBuilder EnhancedBackendBuilder
@@ -105,7 +108,7 @@ type defaultModelBuilder struct {
105108
}
106109

107110
// build mode stack for a IngressGroup.
108-
func (b *defaultModelBuilder) Build(ctx context.Context, ingGroup Group) (core.Stack, *elbv2model.LoadBalancer, []types.NamespacedName, error) {
111+
func (b *defaultModelBuilder) Build(ctx context.Context, ingGroup Group) (core.Stack, *elbv2model.LoadBalancer, []types.NamespacedName, bool, error) {
109112
stack := core.NewDefaultStack(core.StackID(ingGroup.ID))
110113
task := &defaultModelBuildTask{
111114
k8sClient: b.k8sClient,
@@ -123,6 +126,7 @@ func (b *defaultModelBuilder) Build(ctx context.Context, ingGroup Group) (core.S
123126
elbv2TaggingManager: b.elbv2TaggingManager,
124127
featureGates: b.featureGates,
125128
backendSGProvider: b.backendSGProvider,
129+
sgResolver: b.sgResolver,
126130
logger: b.logger,
127131
enableBackendSG: b.enableBackendSG,
128132
disableRestrictedSGRules: b.disableRestrictedSGRules,
@@ -153,9 +157,9 @@ func (b *defaultModelBuilder) Build(ctx context.Context, ingGroup Group) (core.S
153157
backendServices: make(map[types.NamespacedName]*corev1.Service),
154158
}
155159
if err := task.run(ctx); err != nil {
156-
return nil, nil, nil, err
160+
return nil, nil, nil, false, err
157161
}
158-
return task.stack, task.loadBalancer, task.secretKeys, nil
162+
return task.stack, task.loadBalancer, task.secretKeys, task.backendSGAllocated, nil
159163
}
160164

161165
// the default model build task
@@ -168,6 +172,7 @@ type defaultModelBuildTask struct {
168172
annotationParser annotations.Parser
169173
subnetsResolver networkingpkg.SubnetsResolver
170174
backendSGProvider networkingpkg.BackendSGProvider
175+
sgResolver networkingpkg.SecurityGroupResolver
171176
certDiscovery CertDiscovery
172177
authConfigBuilder AuthConfigBuilder
173178
enhancedBackendBuilder EnhancedBackendBuilder
@@ -181,6 +186,7 @@ type defaultModelBuildTask struct {
181186
sslRedirectConfig *SSLRedirectConfig
182187
stack core.Stack
183188
backendSGIDToken core.StringToken
189+
backendSGAllocated bool
184190
enableBackendSG bool
185191
disableRestrictedSGRules bool
186192
enableIPTargetType bool

pkg/ingress/model_builder_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2920,13 +2920,14 @@ func Test_defaultModelBuilder_Build(t *testing.T) {
29202920
trackingProvider := tracking.NewDefaultProvider("ingress.k8s.aws", clusterName)
29212921
stackMarshaller := deploy.NewDefaultStackMarshaller()
29222922
backendSGProvider := networkingpkg.NewMockBackendSGProvider(ctrl)
2923+
sgResolver := networkingpkg.NewDefaultSecurityGroupResolver(ec2Client, vpcID)
29232924
if tt.fields.enableBackendSG {
29242925
if len(tt.fields.backendSecurityGroup) > 0 {
2925-
backendSGProvider.EXPECT().Get(gomock.Any()).Return(tt.fields.backendSecurityGroup, nil).AnyTimes()
2926+
backendSGProvider.EXPECT().Get(gomock.Any(), networkingpkg.ResourceType(networkingpkg.ResourceTypeIngress), gomock.Any()).Return(tt.fields.backendSecurityGroup, nil).AnyTimes()
29262927
} else {
2927-
backendSGProvider.EXPECT().Get(gomock.Any()).Return("sg-auto", nil).AnyTimes()
2928+
backendSGProvider.EXPECT().Get(gomock.Any(), networkingpkg.ResourceType(networkingpkg.ResourceTypeIngress), gomock.Any()).Return("sg-auto", nil).AnyTimes()
29282929
}
2929-
backendSGProvider.EXPECT().Release(gomock.Any()).Return(nil).AnyTimes()
2930+
backendSGProvider.EXPECT().Release(gomock.Any(), networkingpkg.ResourceType(networkingpkg.ResourceTypeIngress), gomock.Any()).Return(nil).AnyTimes()
29302931
}
29312932
defaultTargetType := tt.defaultTargetType
29322933
if defaultTargetType == "" {
@@ -2941,6 +2942,7 @@ func Test_defaultModelBuilder_Build(t *testing.T) {
29412942
clusterName: clusterName,
29422943
annotationParser: annotationParser,
29432944
subnetsResolver: subnetsResolver,
2945+
sgResolver: sgResolver,
29442946
backendSGProvider: backendSGProvider,
29452947
certDiscovery: certDiscovery,
29462948
authConfigBuilder: authConfigBuilder,
@@ -2962,7 +2964,7 @@ func Test_defaultModelBuilder_Build(t *testing.T) {
29622964
b.enableIPTargetType = *tt.enableIPTargetType
29632965
}
29642966

2965-
gotStack, _, _, err := b.Build(context.Background(), tt.args.ingGroup)
2967+
gotStack, _, _, _, err := b.Build(context.Background(), tt.args.ingGroup)
29662968
if tt.wantErr != "" {
29672969
assert.EqualError(t, err, tt.wantErr)
29682970
} else {

pkg/k8s/utils.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,12 @@ func NamespacedName(obj metav1.Object) types.NamespacedName {
1212
Name: obj.GetName(),
1313
}
1414
}
15+
16+
// ToSliceOfNamespacedNames gets the slice of types.NamespacedName from the input slice s
17+
func ToSliceOfNamespacedNames[T metav1.ObjectMetaAccessor](s []T) []types.NamespacedName {
18+
result := make([]types.NamespacedName, len(s))
19+
for i, v := range s {
20+
result[i] = NamespacedName(v.GetObjectMeta())
21+
}
22+
return result
23+
}

0 commit comments

Comments
 (0)