Skip to content

Commit

Permalink
feat: add security groups cleanup
Browse files Browse the repository at this point in the history
Signed-off-by: Carlos Salas <carlos.salas@suse.com>
  • Loading branch information
salasberryfin committed Mar 1, 2024
1 parent d361c08 commit e23c05b
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 2 deletions.
6 changes: 4 additions & 2 deletions action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/eks"
"github.com/aws/aws-sdk-go/service/elb"
)
Expand All @@ -32,10 +33,11 @@ func (a *action) Cleanup(ctx context.Context, input *Input) error {

//NOTE: ordering matters here!
cleanupFuncs := map[string]CleanupFunc{
elb.ServiceName: a.cleanLoadBalancers,
cloudformation.ServiceName: a.cleanCfStacks,
eks.ServiceName: a.cleanEKSClusters,
autoscaling.ServiceName: a.cleanASGs,
elb.ServiceName: a.cleanLoadBalancers,
ec2.ServiceName: a.cleanSecurityGroups,
cloudformation.ServiceName: a.cleanCfStacks,
}
inputRegions := strings.Split(input.Regions, ",")

Expand Down
133 changes: 133 additions & 0 deletions action/cleanup_sgs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package action

import (
"context"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
)

func (a *action) cleanSecurityGroups(ctx context.Context, input *CleanupScope) error {
client := ec2.New(input.Session)

sgsToDelete := []*ec2.SecurityGroup{}
// NOTE: we delete security groups based on whether we're later deleting the vpc they belong to or not.
pageFunc := func(page *ec2.DescribeVpcsOutput, _ bool) bool {
sgPageFunc := func(sgPage *ec2.GetSecurityGroupsForVpcOutput, _ bool) bool {
for _, sg := range sgPage.SecurityGroupForVpcs {
var ignore bool
for _, tag := range sg.Tags {
if *tag.Key == input.IgnoreTag {
ignore = true
break
}
}

if ignore || *sg.GroupName == "default" {
LogDebug("security group %s has ignore tag or is a default security group, skipping cleanup", *sg.GroupId)
continue
}

securityGroups, err := client.DescribeSecurityGroupsWithContext(ctx, &ec2.DescribeSecurityGroupsInput{GroupIds: []*string{sg.GroupId}})
if err != nil || len(securityGroups.SecurityGroups) != 1 {
LogError("failed to describe security group %s: %s", *sg.GroupId, err.Error())
continue
}

LogDebug("adding security group %s to delete list", *sg.GroupId)
sgsToDelete = append(sgsToDelete, securityGroups.SecurityGroups[0])
}

return true
}

for _, vpc := range page.Vpcs {
var ignore bool
for _, tag := range vpc.Tags {
if *tag.Key == input.IgnoreTag {
ignore = true
break
}
}

if ignore || aws.BoolValue(vpc.IsDefault) {
LogDebug("vpc %s has ignore tag or is a default vpc, won't delete security groups associated with it", *vpc.VpcId)
continue
}

if err := client.GetSecurityGroupsForVpcPagesWithContext(ctx, &ec2.GetSecurityGroupsForVpcInput{VpcId: vpc.VpcId}, sgPageFunc); err != nil {
LogError("failed getting list of security groups for vpc %s: %s", *vpc.VpcId, err.Error())
continue
}

}

return true
}

if err := client.DescribeVpcsPagesWithContext(ctx, &ec2.DescribeVpcsInput{}, pageFunc); err != nil {
return fmt.Errorf("failed getting list of vpcs: %w", err)
}

if len(sgsToDelete) == 0 {
Log("no security groups to delete")
return nil
}

// NOTE: some security groups may have rules that reference other security groups.
// deleting a security group that's referenced in another's rules will fail,
// so we need to delete the rules first.
for _, securityGroup := range sgsToDelete {
if !a.commit {
LogDebug("skipping deletion of security group %s as running in dry-mode", *securityGroup.GroupId)
continue
}

if err := a.deleteSecurityGroupRules(ctx, *securityGroup.GroupId, securityGroup.IpPermissions, securityGroup.IpPermissionsEgress, client); err != nil {
LogError("failed to delete security group rules for %s: %s", *securityGroup.GroupId, err.Error())
}

}

for _, securityGroup := range sgsToDelete {
if !a.commit {
LogDebug("skipping deletion of security group %s as running in dry-mode", *securityGroup.GroupId)
continue
}

if err := a.deleteSecurityGroup(ctx, *securityGroup.GroupId, client); err != nil {
LogError("failed to delete security group %s: %s", *securityGroup.GroupId, err.Error())
}
}

return nil
}

func (a *action) deleteSecurityGroupRules(ctx context.Context, sgId string, sgIngress, sgEgress []*ec2.IpPermission, client *ec2.EC2) error {
Log("Deleting Ingress/Egress Rules from security group %s", sgId)

if len(sgIngress) != 0 {
if _, err := client.RevokeSecurityGroupIngressWithContext(ctx, &ec2.RevokeSecurityGroupIngressInput{GroupId: &sgId, IpPermissions: sgIngress}); err != nil {
return fmt.Errorf("failed to revoke ingress rules from security group %s: %w", sgId, err)
}
}

if len(sgEgress) != 0 {
if _, err := client.RevokeSecurityGroupEgressWithContext(ctx, &ec2.RevokeSecurityGroupEgressInput{GroupId: &sgId, IpPermissions: sgEgress}); err != nil {
return fmt.Errorf("failed to revoke egress rules from security group %s: %w", sgId, err)
}
}

return nil
}

func (a *action) deleteSecurityGroup(ctx context.Context, sgId string, client *ec2.EC2) error {
Log("Deleting Security Group %s", sgId)

if _, err := client.DeleteSecurityGroupWithContext(ctx, &ec2.DeleteSecurityGroupInput{GroupId: &sgId}); err != nil {
return fmt.Errorf("failed to delete security group %s: %w", sgId, err)
}

return nil
}

0 comments on commit e23c05b

Please sign in to comment.