Skip to content

Commit

Permalink
Merge pull request duo-labs#484 from 0xdabbad00/find_more_unused_reso…
Browse files Browse the repository at this point in the history
…urces

Find more unused resources
  • Loading branch information
0xdabbad00 authored Jul 18, 2019
2 parents a99a07b + a42d600 commit f7d78bd
Show file tree
Hide file tree
Showing 4 changed files with 399 additions and 59 deletions.
2 changes: 1 addition & 1 deletion cloudmapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import pkgutil
import importlib

__version__ = "2.5.9"
__version__ = "2.6.0"


def show_help(commands):
Expand Down
64 changes: 6 additions & 58 deletions commands/find_unused.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,14 @@
from __future__ import print_function
from shared.common import parse_arguments
from commands.prepare import build_data_structure
import pyjq
from shared.common import parse_arguments, make_list, query_aws, get_regions
from shared.nodes import Account, Region
import json

__description__ = "Find unused resources in accounts"
from shared.common import parse_arguments
from shared.find_unused import find_unused_resources


__description__ = "Find unused resources in accounts"

def run(arguments):
_, accounts, config = parse_arguments(arguments)

unused_resources = []
for account in accounts:
unused_resources_for_account = []
for region_json in get_regions(Account(None, account)):
unused_resources_for_region = {}
used_sgs = set()

region = Region(Account(None, account), region_json)
defined_sgs = query_aws(
Account(None, account), "ec2-describe-security-groups", region
)

network_interfaces = query_aws(
Account(None, account), "ec2-describe-network-interfaces", region
)

defined_sg_set = {}

for sg in pyjq.all(".SecurityGroups[]", defined_sgs):
defined_sg_set[sg["GroupId"]] = sg

for used_sg in pyjq.all(
".NetworkInterfaces[].Groups[].GroupId", network_interfaces
):
used_sgs.add(used_sg)

unused_sg_ids = set(defined_sg_set) - used_sgs
unused_sgs = []
for sg_id in unused_sg_ids:
unused_sgs.append(
{
"id": sg_id,
"name": defined_sg_set[sg_id]["GroupName"],
"description": defined_sg_set[sg_id].get("Description", ""),
}
)

unused_resources_for_region["security_groups"] = unused_sgs

unused_resources_for_account.append(
{
"region": region_json["RegionName"],
"unused_resources": unused_resources_for_region,
}
)
unused_resources.append(
{
"account": {"id": account["id"], "name": account["name"]},
"regions": unused_resources_for_account,
}
)
unused_resources = find_unused_resources(accounts)

print(json.dumps(unused_resources, indent=2, sort_keys=True))
119 changes: 119 additions & 0 deletions shared/find_unused.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import pyjq

from shared.common import query_aws, get_regions
from shared.nodes import Account, Region


def find_unused_security_groups(region):
# Get the defined security groups, then find all the Security Groups associated with the
# ENIs. Then diff these to find the unused Security Groups.
used_sgs = set()

defined_sgs = query_aws(region.account, "ec2-describe-security-groups", region)

network_interfaces = query_aws(
region.account, "ec2-describe-network-interfaces", region
)

defined_sg_set = {}

for sg in pyjq.all(".SecurityGroups[]", defined_sgs):
defined_sg_set[sg["GroupId"]] = sg

for used_sg in pyjq.all(
".NetworkInterfaces[].Groups[].GroupId", network_interfaces
):
used_sgs.add(used_sg)

unused_sg_ids = set(defined_sg_set) - used_sgs
unused_sgs = []
for sg_id in unused_sg_ids:
unused_sgs.append(
{
"id": sg_id,
"name": defined_sg_set[sg_id]["GroupName"],
"description": defined_sg_set[sg_id].get("Description", ""),
}
)
return unused_sgs


def find_unused_volumes(region):
unused_volumes = []
volumes = query_aws(region.account, "ec2-describe-volumes", region)
for volume in pyjq.all('.Volumes[]|select(.State=="available")', volumes):
unused_volumes.append({"id": volume["VolumeId"]})

return unused_volumes


def find_unused_elastic_ips(region):
unused_ips = []
ips = query_aws(region.account, "ec2-describe-addresses", region)
for ip in pyjq.all(".Addresses[] | select(.AssociationId == null)", ips):
unused_ips.append({"id": ip["AllocationId"], "ip": ip["PublicIp"]})

return unused_ips


def find_unused_network_interfaces(region):
unused_network_interfaces = []
network_interfaces = query_aws(
region.account, "ec2-describe-network-interfaces", region
)
for network_interface in pyjq.all(
'.NetworkInterfaces[]|select(.Status=="available")', network_interfaces
):
unused_network_interfaces.append(
{"id": network_interface["NetworkInterfaceId"]}
)

return unused_network_interfaces


def add_if_exists(dictionary, key, value):
if value:
dictionary[key] = value


def find_unused_resources(accounts):
unused_resources = []
for account in accounts:
unused_resources_for_account = []
for region_json in get_regions(Account(None, account)):
region = Region(Account(None, account), region_json)

unused_resources_for_region = {}

add_if_exists(
unused_resources_for_region,
"security_groups",
find_unused_security_groups(region),
)
add_if_exists(
unused_resources_for_region, "volumes", find_unused_volumes(region)
)
add_if_exists(
unused_resources_for_region,
"elastic_ips",
find_unused_elastic_ips(region),
)
add_if_exists(
unused_resources_for_region,
"network_interfaces",
find_unused_network_interfaces(region),
)

unused_resources_for_account.append(
{
"region": region_json["RegionName"],
"unused_resources": unused_resources_for_region,
}
)
unused_resources.append(
{
"account": {"id": account["id"], "name": account["name"]},
"regions": unused_resources_for_account,
}
)
return unused_resources
Loading

0 comments on commit f7d78bd

Please sign in to comment.