-
-
Save TomRyan-321/0cf6e48937cbe9513afc50117d6ffd6f to your computer and use it in GitHub Desktop.
| #!/usr/bin/env python | |
| import boto3 | |
| import argparse | |
| def lookup_by_id(sgid): | |
| sg = ec2.get_all_security_groups(group_ids=sgid) | |
| return sg[0].name | |
| # get a full list of the available regions | |
| client = boto3.client('ec2') | |
| regions_dict = client.describe_regions() | |
| region_list = [region['RegionName'] for region in regions_dict['Regions']] | |
| # parse arguments | |
| parser = argparse.ArgumentParser(description="Show unused security groups") | |
| parser.add_argument("-r", "--region", type=str, default="us-east-1", | |
| help="The default region is us-east-1. The list of available regions are as follows: %s" % sorted( | |
| region_list)) | |
| parser.add_argument("-d", "--delete", help="delete security groups from AWS", action="store_true") | |
| args = parser.parse_args() | |
| client = boto3.client('ec2', region_name=args.region) | |
| ec2 = boto3.resource('ec2', region_name=args.region) | |
| all_groups = [] | |
| security_groups_in_use = [] | |
| # Get ALL security groups names | |
| security_groups_dict = client.describe_security_groups() | |
| security_groups = security_groups_dict['SecurityGroups'] | |
| for groupobj in security_groups: | |
| if groupobj['GroupName'] == 'default' or groupobj['GroupName'].startswith('d-') or groupobj['GroupName'].startswith('AWS-OpsWorks-'): | |
| security_groups_in_use.append(groupobj['GroupId']) | |
| all_groups.append(groupobj['GroupId']) | |
| # Get all security groups used by instances | |
| instances_dict = client.describe_instances() | |
| reservations = instances_dict['Reservations'] | |
| network_interface_count = 0 | |
| for i in reservations: | |
| for j in i['Instances']: | |
| for k in j['SecurityGroups']: | |
| if k['GroupId'] not in security_groups_in_use: | |
| security_groups_in_use.append(k['GroupId']) | |
| # Security Groups in use by Network Interfaces | |
| eni_client = boto3.client('ec2', region_name=args.region) | |
| eni_dict = eni_client.describe_network_interfaces() | |
| for i in eni_dict['NetworkInterfaces']: | |
| for j in i['Groups']: | |
| if j['GroupId'] not in security_groups_in_use: | |
| security_groups_in_use.append(j['GroupId']) | |
| # Security groups used by classic ELBs | |
| elb_client = boto3.client('elb', region_name=args.region) | |
| elb_dict = elb_client.describe_load_balancers() | |
| for i in elb_dict['LoadBalancerDescriptions']: | |
| for j in i['SecurityGroups']: | |
| if j not in security_groups_in_use: | |
| security_groups_in_use.append(j) | |
| # Security groups used by ALBs | |
| elb2_client = boto3.client('elbv2', region_name=args.region) | |
| elb2_dict = elb2_client.describe_load_balancers() | |
| for i in elb2_dict['LoadBalancers']: | |
| for j in i['SecurityGroups']: | |
| if j not in security_groups_in_use: | |
| security_groups_in_use.append(j) | |
| # Security groups used by RDS | |
| rds_client = boto3.client('rds', region_name=args.region) | |
| rds_dict = rds_client.describe_db_instances() | |
| for i in rds_dict['DBInstances']: | |
| for j in i['VpcSecurityGroups']: | |
| if j['VpcSecurityGroupId'] not in security_groups_in_use: | |
| security_groups_in_use.append(j['VpcSecurityGroupId']) | |
| delete_candidates = [] | |
| for group in all_groups: | |
| if group not in security_groups_in_use: | |
| delete_candidates.append(group) | |
| if args.delete: | |
| print("We will now delete security groups identified to not be in use.") | |
| for group in delete_candidates: | |
| security_group = ec2.SecurityGroup(group) | |
| try: | |
| security_group.delete() | |
| except Exception as e: | |
| print(e) | |
| print("{0} requires manual remediation.".format(security_group.group_name)) | |
| else: | |
| print("The list of security groups to be removed is below.") | |
| print("Run this again with `-d` to remove them") | |
| for group in sorted(delete_candidates): | |
| print(" " + group) | |
| print("---------------") | |
| print("Activity Report") | |
| print("---------------") | |
| print(u"Total number of Security Groups evaluated: {0:d}".format(len(all_groups))) | |
| print(u"Total number of EC2 Instances evaluated: {0:d}".format(len(reservations))) | |
| print(u"Total number of Load Balancers evaluated: {0:d}".format(len(elb_dict['LoadBalancerDescriptions']) + | |
| len(elb2_dict['LoadBalancers']))) | |
| print(u"Total number of RDS Instances evaluated: {0:d}".format(len(rds_dict['DBInstances']))) | |
| print(u"Total number of Network Interfaces evaluated: {0:d}".format(len(eni_dict['NetworkInterfaces']))) | |
| print(u"Total number of Security Groups in-use evaluated: {0:d}".format(len(security_groups_in_use))) | |
| if args.delete: | |
| print(u"Total number of Unused Security Groups deleted: {0:d}".format(len(delete_candidates))) | |
| else: | |
| print(u"Total number of Unused Security Groups targeted for removal: {0:d}".format(len(delete_candidates))) | |
| # For each security group in the total list, if not in the "used" list, flag for deletion | |
| # If running with a "--delete" flag, delete the ones flagged. |
Changed Network Interface check to directly check all network interfaces rather than just instance attached interfaces.
Thanks a lot!
Great script...I did find one issue around line 67 and dealing with elbv2 and security groups.
We have a number of 'network' load balancers, and these do not have any Security Groups associated with them, and thus would fail on your for loop. I added the following and all is well.
# Security groups used by ALBs
elb2_client = boto3.client('elbv2', region_name=args.region)
elb2_dict = elb2_client.describe_load_balancers()
for i in elb2_dict['LoadBalancers']:
try:
for j in i['SecurityGroups']:
if j not in security_groups_in_use:
security_groups_in_use.append(j)
except KeyError:
pass
Nice script, works great! Thanks.
Thanks for the code!
Small improvement. Most AWS users may set AWS_DEFALUT_REGION in the environmental variables.
So,
import os
# .... snip ....
try:
default_region = os.environ["AWS_DEFAULT_REGION"]
except:
default_region = "us-east-1"
# parse arguments
parser = argparse.ArgumentParser(description="Show unused security groups")
parser.add_argument("-r", "--region", type=str, default=default_region,
help="The default region is us-east-1. The list of available regions are as follows: %s" % sorted(
region_list))
may be good.
network loadbalancer not have SecurityGroups..
# Security groups used by ALBs
elb2_client = boto3.client('elbv2', region_name=args.region)
elb2_dict = elb2_client.describe_load_balancers()
for i in elb2_dict['LoadBalancers']:
if i['Type']=='network':
continue
for j in i['SecurityGroups']:
if j not in security_groups_in_use:
security_groups_in_use.append(j)
Thanks for ce code very best, but security group lamdba check :
Security groups used by lambda
lambda_client = boto3.client('lambda', region_name=args.region)
lambda_functions = lambda_client.list_functions()
while True:
if "NextMarker" in lambda_functions:
nextMarker = lambda_functions["NextMarker"]
else:
nextMarker = ""
for function in lambda_functions["Functions"]:
functionName = function["FunctionName"]
print ("name"+functionName)
functionVpcConfig=""
functionSecurityGroupIds=""
try:
functionVpcConfig = function["VpcConfig"]
functionSecurityGroupIds = functionVpcConfig["SecurityGroupIds"]
for j in functionSecurityGroupIds:
if j not in security_groups_in_use:
security_groups_in_use.append(j)
except KeyError:
continue
finally:
print (functionSecurityGroupIds)
if nextMarker == "":
break
else:
lambda_functions = lambda_client.list_functions(
Marker= nextMarker
)
Hey thank you for this, I added a few more checks and options if you're interested:
https://gist.github.com/snixon/059b0a0edf87e9a34d020bb2c9546874
Great script...I did find one issue around line 67 and dealing with elbv2 and security groups. We have a number of 'network' load balancers, and these do not have any Security Groups associated with them, and thus would fail on your for loop. I added the following and all is well.
# Security groups used by ALBs elb2_client = boto3.client('elbv2', region_name=args.region) elb2_dict = elb2_client.describe_load_balancers() for i in elb2_dict['LoadBalancers']: try: for j in i['SecurityGroups']: if j not in security_groups_in_use: security_groups_in_use.append(j) except KeyError: pass
or we can do
for i in elb2_dict['LoadBalancers']:
if "SecurityGroups" in i:
for j in i["SecurityGroups"]:
if j not in security_groups_in_use:
security_groups_in_use.append(j)
else:
print(f"ALB -> {i['LoadBalancerName']} didn't use any security group")
Fixed checks for Security groups that start with 'AWS-OpsWorks-' & 'd-' (directory service).