Skip to content

Commit 048625f

Browse files
authored
Merge pull request #5 from aws-samples/MO-7967
Adding code to support the delete_graph functionality
2 parents a52e239 + 2dcddf6 commit 048625f

File tree

2 files changed

+54
-14
lines changed

2 files changed

+54
-14
lines changed

disableDetective.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,28 @@ def _master_account_type(val: str, pattern: str = r'[0-9]{12}'):
4242
return val
4343

4444
# Setup command line arguments
45-
parser = argparse.ArgumentParser(description=('Link AWS Accounts to central '
46-
'Detective Account.'))
45+
parser = argparse.ArgumentParser(description=('Unlink AWS Accounts from a central '
46+
'Detective Account, or delete the entire Detective graph.'))
4747
parser.add_argument('--master_account', type=_master_account_type,
4848
required=True,
4949
help="AccountId for Central AWS Account.")
5050
parser.add_argument('--input_file', type=argparse.FileType('r'),
51-
required=True,
5251
help=('Path to CSV file containing the list of '
53-
'account IDs and Email addresses.'))
52+
'account IDs and Email addresses. '
53+
'This does not need to be provided if you use the delete_graph flag.'))
5454
parser.add_argument('--assume_role', type=str, required=True,
5555
help="Role Name to assume in each account.")
56-
parser.add_argument('--delete_master', action='store_true', default=False,
57-
help="Delete the master Detective graph.")
56+
parser.add_argument('--delete_graph', action='store_true',
57+
help=('Delete the master Detective graph. '
58+
'If not provided, you must provide an input file.'))
5859
parser.add_argument('--disabled_regions', type=str,
5960
help=('Regions to disable Detective. If not specified, '
6061
'all available regions disabled.'))
61-
return parser.parse_args(args)
62+
args = parser.parse_args(args)
63+
if not args.delete_graph and not args.input_file:
64+
raise parser.error("Either an input file or the delete_graph flag should be provided.")
65+
66+
return args
6267

6368

6469
def read_accounts_csv(input_file: typing.IO) -> typing.Dict:
@@ -74,6 +79,9 @@ def read_accounts_csv(input_file: typing.IO) -> typing.Dict:
7479
account_re = re.compile(r'[0-9]{12}')
7580
aws_account_dict = {}
7681

82+
if not input_file:
83+
return aws_account_dict
84+
7785
for acct in input_file.readlines():
7886
split_line = acct.strip().split(',')
7987

@@ -255,6 +263,12 @@ def delete_members(d_client: botocore.client.BaseClient, graph_arn: str,
255263
args = setup_command_line()
256264
aws_account_dict = read_accounts_csv(args.input_file)
257265

266+
# making sure that we either have an account list to delete from graphs or the delete_graph flag is provided.
267+
if len(list(aws_account_dict.keys())) == 0 and not args.delete_graph:
268+
logging.error("The delete_graph flag was False while the provided account list is empty. "\
269+
"Please check your inputs and re-run the script.")
270+
exit(1)
271+
258272
try:
259273
session = boto3.session.Session()
260274
detective_regions = get_regions(session, args.disabled_regions)
@@ -277,15 +291,16 @@ def delete_members(d_client: botocore.client.BaseClient, graph_arn: str,
277291
d_client = master_session.client('detective', region_name=region)
278292
graphs = get_graphs(d_client)
279293
if not graphs:
280-
logging.info(f'Amazon Detective is NOT disabled in {region}')
281-
continue
282-
logging.info(f'Amazon Detective is disabled in region {region}')
294+
logging.info(f'Amazon Detective has already been disabled in {region}')
295+
else:
296+
logging.info(f'Disabling Amazon Detective in region {region}')
283297

284298
try:
285-
286299
for graph in graphs:
287-
delete_members(
288-
d_client, graph, aws_account_dict)
300+
if not args.delete_graph:
301+
delete_members(d_client, graph, aws_account_dict)
302+
else:
303+
d_client.delete_graph(graph)
289304
except NameError as e:
290305
logging.error(f'account is not defined: {e}')
291306
except Exception as e:

tests/test_scripts.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,23 @@ def test_setup_command_line_disableDetective():
5757
with pytest.raises(SystemExit):
5858
disableDetective.setup_command_line(['--master_account', '12345', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1', '--input_file', 'accounts.csv'])
5959

60-
# Non existent input file
60+
# Non existent input file and no delete_graph flag
6161
with pytest.raises(SystemExit):
6262
disableDetective.setup_command_line(['--master_account', '000000000001', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1', '--input_file', 'accounts1.csv'])
6363

64+
# Non existent input file with delete_graph flag provided
65+
with pytest.raises(SystemExit):
66+
disableDetective.setup_command_line(['--master_account', '000000000001', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1', '--input_file', 'accounts1.csv', '--delete_graph'])
67+
68+
# No input file provided and no delete_graph flag
69+
with pytest.raises(SystemExit):
70+
disableDetective.setup_command_line(['--master_account', '000000000001', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1'])
71+
72+
# No input file provided but delete_graph is set
73+
args = disableDetective.setup_command_line(['--master_account', '000000000001', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1', '--delete_graph'])
74+
assert args.input_file == None
75+
assert args.delete_graph == True
76+
6477
###
6578
# The purpose of this test is to make sure we read accounts and emails correctly from the input .csv file in enableDetective.py
6679
###
@@ -76,13 +89,25 @@ def test_read_accounts_csv_enableDetective():
7689
# The purpose of this test is to make sure we read accounts and emails correctly from the input .csv file in disableDetective.py
7790
###
7891
def test_read_accounts_csv_disableDetective():
92+
# a test case where an input file is provided, although some of the lines are not correct
7993
args = disableDetective.setup_command_line(['--master_account', '555555555555', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1', '--input_file', 'accounts.csv'])
8094

8195
accounts_dict = disableDetective.read_accounts_csv(args.input_file)
8296

8397
assert len(accounts_dict.keys()) == 6
8498
assert accounts_dict == {"123456789012":"random@gmail.com", "000012345678":"email@gmail.com", "555555555555":"test5@gmail.com", "111111111111":"test1@gmail.com", "222222222222":"test2@gmail.com", "333333333333":"test3@gmail.com"}
8599

100+
# a test case where no input file is provided
101+
args = disableDetective.setup_command_line(['--master_account', '555555555555', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1', '--delete_graph'])
102+
assert args.input_file == None
103+
accounts_dict = disableDetective.read_accounts_csv(args.input_file)
104+
assert accounts_dict == {}
105+
106+
# a test case where an empty input file is provided, along with delete_graph. This is not an error, although clients should not run with this kind of input
107+
args = disableDetective.setup_command_line(['--master_account', '555555555555', '--assume_role', 'detectiveAdmin', '--disabled_regions', 'us-east-1,us-east-2,us-west-2,ap-northeast-1,eu-west-1', '--input_file', 'accounts2.csv', '--delete_graph'])
108+
accounts_dict = disableDetective.read_accounts_csv(args.input_file)
109+
assert accounts_dict == {}
110+
assert args.delete_graph == True
86111

87112
###
88113
# The purpose of this test is to make sure we extract regions correctly in enableDetective.py

0 commit comments

Comments
 (0)