Skip to content

Commit d7e05d5

Browse files
authored
Merge pull request #752 from JoelSpeed/remove-sg-rules-untagged-groups
Ensure removal of security group rules on deleting load balancers
2 parents ec9bfe1 + 912f047 commit d7e05d5

File tree

3 files changed

+144
-67
lines changed

3 files changed

+144
-67
lines changed

pkg/providers/v1/aws.go

Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,12 +1946,16 @@ func (c *Cloud) buildELBSecurityGroupList(serviceName types.NamespacedName, load
19461946
// from buildELBSecurityGroupList. The logic is:
19471947
// - securityGroups specified by ServiceAnnotationLoadBalancerSecurityGroups appears first in order
19481948
// - securityGroups specified by ServiceAnnotationLoadBalancerExtraSecurityGroups appears last in order
1949-
func (c *Cloud) sortELBSecurityGroupList(securityGroupIDs []string, annotations map[string]string) {
1949+
func (c *Cloud) sortELBSecurityGroupList(securityGroupIDs []string, annotations map[string]string, taggedLBSecurityGroups map[string]struct{}) {
19501950
annotatedSGList := getSGListFromAnnotation(annotations[ServiceAnnotationLoadBalancerSecurityGroups])
19511951
annotatedExtraSGList := getSGListFromAnnotation(annotations[ServiceAnnotationLoadBalancerExtraSecurityGroups])
19521952
annotatedSGIndex := make(map[string]int, len(annotatedSGList))
19531953
annotatedExtraSGIndex := make(map[string]int, len(annotatedExtraSGList))
19541954

1955+
if taggedLBSecurityGroups == nil {
1956+
taggedLBSecurityGroups = make(map[string]struct{})
1957+
}
1958+
19551959
for i, sgID := range annotatedSGList {
19561960
annotatedSGIndex[sgID] = i
19571961
}
@@ -1969,7 +1973,11 @@ func (c *Cloud) sortELBSecurityGroupList(securityGroupIDs []string, annotations
19691973
}
19701974
}
19711975
sort.Slice(securityGroupIDs, func(i, j int) bool {
1972-
return sgOrderMapping[securityGroupIDs[i]] < sgOrderMapping[securityGroupIDs[j]]
1976+
// If i is tagged but j is not, then i should be before j.
1977+
_, iTagged := taggedLBSecurityGroups[securityGroupIDs[i]]
1978+
_, jTagged := taggedLBSecurityGroups[securityGroupIDs[j]]
1979+
1980+
return sgOrderMapping[securityGroupIDs[i]] < sgOrderMapping[securityGroupIDs[j]] || iTagged && !jTagged
19731981
})
19741982
}
19751983

@@ -2498,7 +2506,7 @@ func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiS
24982506
}
24992507
}
25002508

2501-
err = c.updateInstanceSecurityGroupsForLoadBalancer(loadBalancer, instances, annotations)
2509+
err = c.updateInstanceSecurityGroupsForLoadBalancer(loadBalancer, instances, annotations, false)
25022510
if err != nil {
25032511
klog.Warningf("Error opening ingress rules for the load balancer to the instances: %q", err)
25042512
return nil, err
@@ -2659,7 +2667,7 @@ func (c *Cloud) getTaggedSecurityGroups() (map[string]*ec2.SecurityGroup, error)
26592667

26602668
// Open security group ingress rules on the instances so that the load balancer can talk to them
26612669
// Will also remove any security groups ingress rules for the load balancer that are _not_ needed for allInstances
2662-
func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancerDescription, instances map[InstanceID]*ec2.Instance, annotations map[string]string) error {
2670+
func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancerDescription, instances map[InstanceID]*ec2.Instance, annotations map[string]string, isDeleting bool) error {
26632671
if c.cfg.Global.DisableSecurityGroupIngress {
26642672
return nil
26652673
}
@@ -2669,11 +2677,24 @@ func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancer
26692677
if len(lbSecurityGroupIDs) == 0 {
26702678
return fmt.Errorf("could not determine security group for load balancer: %s", aws.StringValue(lb.LoadBalancerName))
26712679
}
2672-
c.sortELBSecurityGroupList(lbSecurityGroupIDs, annotations)
2680+
2681+
taggedSecurityGroups, err := c.getTaggedSecurityGroups()
2682+
if err != nil {
2683+
return fmt.Errorf("error querying for tagged security groups: %q", err)
2684+
}
2685+
2686+
taggedLBSecurityGroups := make(map[string]struct{})
2687+
for _, sg := range lbSecurityGroupIDs {
2688+
if _, ok := taggedSecurityGroups[sg]; ok {
2689+
taggedLBSecurityGroups[sg] = struct{}{}
2690+
}
2691+
}
2692+
2693+
c.sortELBSecurityGroupList(lbSecurityGroupIDs, annotations, taggedLBSecurityGroups)
26732694
loadBalancerSecurityGroupID := lbSecurityGroupIDs[0]
26742695

26752696
// Get the actual list of groups that allow ingress from the load-balancer
2676-
var actualGroups []*ec2.SecurityGroup
2697+
actualGroups := make(map[*ec2.SecurityGroup]bool)
26772698
{
26782699
describeRequest := &ec2.DescribeSecurityGroupsInput{}
26792700
describeRequest.Filters = []*ec2.Filter{
@@ -2684,18 +2705,10 @@ func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancer
26842705
return fmt.Errorf("error querying security groups for ELB: %q", err)
26852706
}
26862707
for _, sg := range response {
2687-
if !c.tagging.hasClusterTag(sg.Tags) {
2688-
continue
2689-
}
2690-
actualGroups = append(actualGroups, sg)
2708+
actualGroups[sg] = c.tagging.hasClusterTag(sg.Tags)
26912709
}
26922710
}
26932711

2694-
taggedSecurityGroups, err := c.getTaggedSecurityGroups()
2695-
if err != nil {
2696-
return fmt.Errorf("error querying for tagged security groups: %q", err)
2697-
}
2698-
26992712
// Open the firewall from the load balancer to the instance
27002713
// We don't actually have a trivial way to know in advance which security group the instance is in
27012714
// (it is probably the node security group, but we don't easily have that).
@@ -2725,7 +2738,7 @@ func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancer
27252738
}
27262739

27272740
// Compare to actual groups
2728-
for _, actualGroup := range actualGroups {
2741+
for actualGroup, hasClusterTag := range actualGroups {
27292742
actualGroupID := aws.StringValue(actualGroup.GroupId)
27302743
if actualGroupID == "" {
27312744
klog.Warning("Ignoring group without ID: ", actualGroup)
@@ -2737,8 +2750,12 @@ func (c *Cloud) updateInstanceSecurityGroupsForLoadBalancer(lb *elb.LoadBalancer
27372750
// We don't need to make a change; the permission is already in place
27382751
delete(instanceSecurityGroupIds, actualGroupID)
27392752
} else {
2740-
// This group is not needed by allInstances; delete it
2741-
instanceSecurityGroupIds[actualGroupID] = false
2753+
if hasClusterTag || isDeleting {
2754+
// If the group is tagged, and we don't need the rule, we should remove it.
2755+
// If the security group is deleting, we should also remove the rule else
2756+
// we cannot remove the security group, we wiil get a dependency violation.
2757+
instanceSecurityGroupIds[actualGroupID] = false
2758+
}
27422759
}
27432760
}
27442761

@@ -2847,28 +2864,11 @@ func (c *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName strin
28472864
return nil
28482865
}
28492866

2850-
{
2851-
// De-authorize the load balancer security group from the instances security group
2852-
err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, nil, service.Annotations)
2853-
if err != nil {
2854-
klog.Errorf("Error deregistering load balancer from instance security groups: %q", err)
2855-
return err
2856-
}
2857-
}
2858-
2859-
{
2860-
// Delete the load balancer itself
2861-
request := &elb.DeleteLoadBalancerInput{}
2862-
request.LoadBalancerName = lb.LoadBalancerName
2863-
2864-
_, err = c.elb.DeleteLoadBalancer(request)
2865-
if err != nil {
2866-
// TODO: Check if error was because load balancer was concurrently deleted
2867-
klog.Errorf("Error deleting load balancer: %q", err)
2868-
return err
2869-
}
2870-
}
2871-
2867+
// Collect the security groups to delete.
2868+
// We need to know this ahead of time so that we can check
2869+
// if the load balancer security group is being deleted.
2870+
securityGroupIDs := map[string]struct{}{}
2871+
taggedLBSecurityGroups := map[string]struct{}{}
28722872
{
28732873
// Delete the security group(s) for the load balancer
28742874
// Note that this is annoying: the load balancer disappears from the API immediately, but it is still
@@ -2884,9 +2884,6 @@ func (c *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName strin
28842884
if err != nil {
28852885
return fmt.Errorf("error querying security groups for ELB: %q", err)
28862886
}
2887-
2888-
// Collect the security groups to delete
2889-
securityGroupIDs := map[string]struct{}{}
28902887
annotatedSgSet := map[string]bool{}
28912888
annotatedSgsList := getSGListFromAnnotation(service.Annotations[ServiceAnnotationLoadBalancerSecurityGroups])
28922889
annotatedExtraSgsList := getSGListFromAnnotation(service.Annotations[ServiceAnnotationLoadBalancerExtraSecurityGroups])
@@ -2911,6 +2908,8 @@ func (c *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName strin
29112908
if !c.tagging.hasClusterTag(sg.Tags) {
29122909
klog.Warningf("Ignoring security group with no cluster tag in %s", service.Name)
29132910
continue
2911+
} else {
2912+
taggedLBSecurityGroups[sgID] = struct{}{}
29142913
}
29152914

29162915
// This is an extra protection of deletion of non provisioned Security Group which is annotated with `service.beta.kubernetes.io/aws-load-balancer-security-groups`.
@@ -2921,6 +2920,41 @@ func (c *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName strin
29212920

29222921
securityGroupIDs[sgID] = struct{}{}
29232922
}
2923+
}
2924+
2925+
{
2926+
// Determine the load balancer security group id
2927+
lbSecurityGroupIDs := aws.StringValueSlice(lb.SecurityGroups)
2928+
if len(lbSecurityGroupIDs) == 0 {
2929+
return fmt.Errorf("could not determine security group for load balancer: %s", aws.StringValue(lb.LoadBalancerName))
2930+
}
2931+
c.sortELBSecurityGroupList(lbSecurityGroupIDs, service.Annotations, taggedLBSecurityGroups)
2932+
loadBalancerSecurityGroupID := lbSecurityGroupIDs[0]
2933+
2934+
_, isDeleteingLBSecurityGroup := securityGroupIDs[loadBalancerSecurityGroupID]
2935+
2936+
// De-authorize the load balancer security group from the instances security group
2937+
err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, nil, service.Annotations, isDeleteingLBSecurityGroup)
2938+
if err != nil {
2939+
klog.Errorf("Error deregistering load balancer from instance security groups: %q", err)
2940+
return err
2941+
}
2942+
}
2943+
2944+
{
2945+
// Delete the load balancer itself
2946+
request := &elb.DeleteLoadBalancerInput{}
2947+
request.LoadBalancerName = lb.LoadBalancerName
2948+
2949+
_, err = c.elb.DeleteLoadBalancer(request)
2950+
if err != nil {
2951+
// TODO: Check if error was because load balancer was concurrently deleted
2952+
klog.Errorf("Error deleting load balancer: %q", err)
2953+
return err
2954+
}
2955+
}
2956+
2957+
{
29242958

29252959
// Loop through and try to delete them
29262960
timeoutAt := time.Now().Add(time.Second * 600)
@@ -3017,7 +3051,7 @@ func (c *Cloud) UpdateLoadBalancer(ctx context.Context, clusterName string, serv
30173051
return err
30183052
}
30193053

3020-
err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, instances, service.Annotations)
3054+
err = c.updateInstanceSecurityGroupsForLoadBalancer(lb, instances, service.Annotations, false)
30213055
if err != nil {
30223056
return err
30233057
}

pkg/providers/v1/aws_fakes.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -522,108 +522,108 @@ type FakeELB struct {
522522

523523
// CreateLoadBalancer is not implemented but is required for interface
524524
// conformance
525-
func (elb *FakeELB) CreateLoadBalancer(*elb.CreateLoadBalancerInput) (*elb.CreateLoadBalancerOutput, error) {
525+
func (e *FakeELB) CreateLoadBalancer(*elb.CreateLoadBalancerInput) (*elb.CreateLoadBalancerOutput, error) {
526526
panic("Not implemented")
527527
}
528528

529529
// DeleteLoadBalancer is not implemented but is required for interface
530530
// conformance
531-
func (elb *FakeELB) DeleteLoadBalancer(input *elb.DeleteLoadBalancerInput) (*elb.DeleteLoadBalancerOutput, error) {
532-
panic("Not implemented")
531+
func (e *FakeELB) DeleteLoadBalancer(input *elb.DeleteLoadBalancerInput) (*elb.DeleteLoadBalancerOutput, error) {
532+
return &elb.DeleteLoadBalancerOutput{}, nil
533533
}
534534

535535
// DescribeLoadBalancers is not implemented but is required for interface
536536
// conformance
537-
func (elb *FakeELB) DescribeLoadBalancers(input *elb.DescribeLoadBalancersInput) (*elb.DescribeLoadBalancersOutput, error) {
537+
func (e *FakeELB) DescribeLoadBalancers(input *elb.DescribeLoadBalancersInput) (*elb.DescribeLoadBalancersOutput, error) {
538538
panic("Not implemented")
539539
}
540540

541541
// AddTags is not implemented but is required for interface conformance
542-
func (elb *FakeELB) AddTags(input *elb.AddTagsInput) (*elb.AddTagsOutput, error) {
542+
func (e *FakeELB) AddTags(input *elb.AddTagsInput) (*elb.AddTagsOutput, error) {
543543
panic("Not implemented")
544544
}
545545

546546
// RegisterInstancesWithLoadBalancer is not implemented but is required for
547547
// interface conformance
548-
func (elb *FakeELB) RegisterInstancesWithLoadBalancer(*elb.RegisterInstancesWithLoadBalancerInput) (*elb.RegisterInstancesWithLoadBalancerOutput, error) {
548+
func (e *FakeELB) RegisterInstancesWithLoadBalancer(*elb.RegisterInstancesWithLoadBalancerInput) (*elb.RegisterInstancesWithLoadBalancerOutput, error) {
549549
panic("Not implemented")
550550
}
551551

552552
// DeregisterInstancesFromLoadBalancer is not implemented but is required for
553553
// interface conformance
554-
func (elb *FakeELB) DeregisterInstancesFromLoadBalancer(*elb.DeregisterInstancesFromLoadBalancerInput) (*elb.DeregisterInstancesFromLoadBalancerOutput, error) {
554+
func (e *FakeELB) DeregisterInstancesFromLoadBalancer(*elb.DeregisterInstancesFromLoadBalancerInput) (*elb.DeregisterInstancesFromLoadBalancerOutput, error) {
555555
panic("Not implemented")
556556
}
557557

558558
// DetachLoadBalancerFromSubnets is not implemented but is required for
559559
// interface conformance
560-
func (elb *FakeELB) DetachLoadBalancerFromSubnets(*elb.DetachLoadBalancerFromSubnetsInput) (*elb.DetachLoadBalancerFromSubnetsOutput, error) {
560+
func (e *FakeELB) DetachLoadBalancerFromSubnets(*elb.DetachLoadBalancerFromSubnetsInput) (*elb.DetachLoadBalancerFromSubnetsOutput, error) {
561561
panic("Not implemented")
562562
}
563563

564564
// AttachLoadBalancerToSubnets is not implemented but is required for interface
565565
// conformance
566-
func (elb *FakeELB) AttachLoadBalancerToSubnets(*elb.AttachLoadBalancerToSubnetsInput) (*elb.AttachLoadBalancerToSubnetsOutput, error) {
566+
func (e *FakeELB) AttachLoadBalancerToSubnets(*elb.AttachLoadBalancerToSubnetsInput) (*elb.AttachLoadBalancerToSubnetsOutput, error) {
567567
panic("Not implemented")
568568
}
569569

570570
// CreateLoadBalancerListeners is not implemented but is required for interface
571571
// conformance
572-
func (elb *FakeELB) CreateLoadBalancerListeners(*elb.CreateLoadBalancerListenersInput) (*elb.CreateLoadBalancerListenersOutput, error) {
572+
func (e *FakeELB) CreateLoadBalancerListeners(*elb.CreateLoadBalancerListenersInput) (*elb.CreateLoadBalancerListenersOutput, error) {
573573
panic("Not implemented")
574574
}
575575

576576
// DeleteLoadBalancerListeners is not implemented but is required for interface
577577
// conformance
578-
func (elb *FakeELB) DeleteLoadBalancerListeners(*elb.DeleteLoadBalancerListenersInput) (*elb.DeleteLoadBalancerListenersOutput, error) {
578+
func (e *FakeELB) DeleteLoadBalancerListeners(*elb.DeleteLoadBalancerListenersInput) (*elb.DeleteLoadBalancerListenersOutput, error) {
579579
panic("Not implemented")
580580
}
581581

582582
// ApplySecurityGroupsToLoadBalancer is not implemented but is required for
583583
// interface conformance
584-
func (elb *FakeELB) ApplySecurityGroupsToLoadBalancer(*elb.ApplySecurityGroupsToLoadBalancerInput) (*elb.ApplySecurityGroupsToLoadBalancerOutput, error) {
584+
func (e *FakeELB) ApplySecurityGroupsToLoadBalancer(*elb.ApplySecurityGroupsToLoadBalancerInput) (*elb.ApplySecurityGroupsToLoadBalancerOutput, error) {
585585
panic("Not implemented")
586586
}
587587

588588
// ConfigureHealthCheck is not implemented but is required for interface
589589
// conformance
590-
func (elb *FakeELB) ConfigureHealthCheck(*elb.ConfigureHealthCheckInput) (*elb.ConfigureHealthCheckOutput, error) {
590+
func (e *FakeELB) ConfigureHealthCheck(*elb.ConfigureHealthCheckInput) (*elb.ConfigureHealthCheckOutput, error) {
591591
panic("Not implemented")
592592
}
593593

594594
// CreateLoadBalancerPolicy is not implemented but is required for interface
595595
// conformance
596-
func (elb *FakeELB) CreateLoadBalancerPolicy(*elb.CreateLoadBalancerPolicyInput) (*elb.CreateLoadBalancerPolicyOutput, error) {
596+
func (e *FakeELB) CreateLoadBalancerPolicy(*elb.CreateLoadBalancerPolicyInput) (*elb.CreateLoadBalancerPolicyOutput, error) {
597597
panic("Not implemented")
598598
}
599599

600600
// SetLoadBalancerPoliciesForBackendServer is not implemented but is required
601601
// for interface conformance
602-
func (elb *FakeELB) SetLoadBalancerPoliciesForBackendServer(*elb.SetLoadBalancerPoliciesForBackendServerInput) (*elb.SetLoadBalancerPoliciesForBackendServerOutput, error) {
602+
func (e *FakeELB) SetLoadBalancerPoliciesForBackendServer(*elb.SetLoadBalancerPoliciesForBackendServerInput) (*elb.SetLoadBalancerPoliciesForBackendServerOutput, error) {
603603
panic("Not implemented")
604604
}
605605

606606
// SetLoadBalancerPoliciesOfListener is not implemented but is required for
607607
// interface conformance
608-
func (elb *FakeELB) SetLoadBalancerPoliciesOfListener(input *elb.SetLoadBalancerPoliciesOfListenerInput) (*elb.SetLoadBalancerPoliciesOfListenerOutput, error) {
608+
func (e *FakeELB) SetLoadBalancerPoliciesOfListener(input *elb.SetLoadBalancerPoliciesOfListenerInput) (*elb.SetLoadBalancerPoliciesOfListenerOutput, error) {
609609
panic("Not implemented")
610610
}
611611

612612
// DescribeLoadBalancerPolicies is not implemented but is required for
613613
// interface conformance
614-
func (elb *FakeELB) DescribeLoadBalancerPolicies(input *elb.DescribeLoadBalancerPoliciesInput) (*elb.DescribeLoadBalancerPoliciesOutput, error) {
614+
func (e *FakeELB) DescribeLoadBalancerPolicies(input *elb.DescribeLoadBalancerPoliciesInput) (*elb.DescribeLoadBalancerPoliciesOutput, error) {
615615
panic("Not implemented")
616616
}
617617

618618
// DescribeLoadBalancerAttributes is not implemented but is required for
619619
// interface conformance
620-
func (elb *FakeELB) DescribeLoadBalancerAttributes(*elb.DescribeLoadBalancerAttributesInput) (*elb.DescribeLoadBalancerAttributesOutput, error) {
620+
func (e *FakeELB) DescribeLoadBalancerAttributes(*elb.DescribeLoadBalancerAttributesInput) (*elb.DescribeLoadBalancerAttributesOutput, error) {
621621
panic("Not implemented")
622622
}
623623

624624
// ModifyLoadBalancerAttributes is not implemented but is required for
625625
// interface conformance
626-
func (elb *FakeELB) ModifyLoadBalancerAttributes(*elb.ModifyLoadBalancerAttributesInput) (*elb.ModifyLoadBalancerAttributesOutput, error) {
626+
func (e *FakeELB) ModifyLoadBalancerAttributes(*elb.ModifyLoadBalancerAttributesInput) (*elb.ModifyLoadBalancerAttributesOutput, error) {
627627
panic("Not implemented")
628628
}
629629

0 commit comments

Comments
 (0)