in tool/clean/clean_security_group/clean_security_group.go [241:314]
func cleanSecurityGroupRules(ctx context.Context, client ec2Client, securityGroup types.SecurityGroup) error {
sgID := *securityGroup.GroupId
// Get fresh security group data in one call
describeOutput, err := client.DescribeSecurityGroups(ctx, &ec2.DescribeSecurityGroupsInput{
GroupIds: []string{sgID},
})
if err != nil {
return fmt.Errorf("describing security group %s: %w", sgID, err)
}
if len(describeOutput.SecurityGroups) == 0 {
return fmt.Errorf("security group %s not found", sgID)
}
sg := describeOutput.SecurityGroups[0]
// Handle both ingress and egress rules concurrently
var wg sync.WaitGroup
var ingressErr, egressErr error
if len(sg.IpPermissions) > 0 {
if cfg.dryRun {
log.Printf("🛑 Dry-Run: Would revoke %d ingress rules from security group: %s",
len(sg.IpPermissions), sgID)
} else {
wg.Add(1)
go func() {
defer wg.Done()
_, err := client.RevokeSecurityGroupIngress(ctx, &ec2.RevokeSecurityGroupIngressInput{
GroupId: aws.String(sgID),
IpPermissions: sg.IpPermissions,
})
if err != nil {
ingressErr = fmt.Errorf("revoking ingress rules: %w", err)
} else {
log.Printf("✅ Revoked ingress rules from security group: %s", sgID)
}
}()
}
}
if len(sg.IpPermissionsEgress) > 0 {
if cfg.dryRun {
log.Printf("🛑 Dry-Run: Would revoke %d egress rules from security group: %s",
len(sg.IpPermissionsEgress), sgID)
} else {
wg.Add(1)
go func() {
defer wg.Done()
_, err := client.RevokeSecurityGroupEgress(ctx, &ec2.RevokeSecurityGroupEgressInput{
GroupId: aws.String(sgID),
IpPermissions: sg.IpPermissionsEgress,
})
if err != nil {
egressErr = fmt.Errorf("revoking egress rules: %w", err)
} else {
log.Printf("✅ Revoked egress rules from security group: %s", sgID)
}
}()
}
}
wg.Wait()
if ingressErr != nil {
return ingressErr
}
if egressErr != nil {
return egressErr
}
return nil
}