def test_find_monitor_change(self): RUNTIME_AUDITORS.clear() RUNTIME_WATCHERS.clear() find_changes(['TEST_ACCOUNT'], ['s3']) self.assertEqual(first=len(RUNTIME_WATCHERS.keys()), second=1, msg="Should run one watchers but ran {}".format( len(RUNTIME_WATCHERS.keys()))) expected_auditor_count = 0 for au in auditor_registry['s3']: expected_auditor_count = expected_auditor_count + 1 au_list = RUNTIME_AUDITORS[au.__name__] self.assertEqual( first=len(au_list), second=1, msg="Auditor {} should run once but ran {} time(s)".format( au.__name__, len(au_list))) self.assertEqual(first=len(RUNTIME_AUDITORS.keys()), second=expected_auditor_count, msg="Should run {} auditor but ran {}".format( expected_auditor_count, len(RUNTIME_AUDITORS.keys())))
def test_find_account_changes(self): RUNTIME_AUDITORS.clear() RUNTIME_WATCHERS.clear() find_changes(['TEST_ACCOUNT'], watcher_registry.keys()) expected_watcher_count = 0 expected_auditor_count = 0 for key in orig_watcher_registry: expected_watcher_count = expected_watcher_count + 1 wa_list = RUNTIME_WATCHERS[orig_watcher_registry[key].__name__] self.assertEqual(first=len(wa_list), second=1, msg="Watcher {} should run once but ran {} time(s)" .format(orig_watcher_registry[key].__name__, len(wa_list))) for au in auditor_registry[orig_watcher_registry[key].index]: expected_auditor_count = expected_auditor_count + 1 au_list = RUNTIME_AUDITORS[au.__name__] self.assertEqual(first=len(au_list), second=1, msg="Auditor {} should run once but ran {} time(s)" .format(au.__name__, len(au_list))) self.assertEqual(first=len(RUNTIME_WATCHERS.keys()), second=expected_watcher_count, msg="Should run {} watchers but ran {}" .format(expected_watcher_count, len(RUNTIME_WATCHERS.keys()))) self.assertEqual(first=len(RUNTIME_AUDITORS.keys()), second=expected_auditor_count, msg="Should run {} auditor(s) but ran {}" .format(expected_auditor_count, len(RUNTIME_AUDITORS.keys())))
def test_find_account_changes(self): RUNTIME_AUDITORS.clear() RUNTIME_WATCHERS.clear() find_changes(['TEST_ACCOUNT'], watcher_registry.keys()) expected_watcher_count = 0 expected_auditor_count = 0 for key in orig_watcher_registry: expected_watcher_count = expected_watcher_count + 1 wa_list = RUNTIME_WATCHERS[orig_watcher_registry[key].__name__] self.assertEqual( first=len(wa_list), second=1, msg="Watcher {} should run once but ran {} time(s)".format( orig_watcher_registry[key].__name__, len(wa_list))) for au in auditor_registry[orig_watcher_registry[key].index]: expected_auditor_count = expected_auditor_count + 1 au_list = RUNTIME_AUDITORS[au.__name__] self.assertEqual( first=len(au_list), second=1, msg="Auditor {} should run once but ran {} time(s)".format( au.__name__, len(au_list))) self.assertEqual(first=len(RUNTIME_WATCHERS.keys()), second=expected_watcher_count, msg="Should run {} watchers but ran {}".format( expected_watcher_count, len(RUNTIME_WATCHERS.keys()))) self.assertEqual(first=len(RUNTIME_AUDITORS.keys()), second=expected_auditor_count, msg="Should run {} auditor(s) but ran {}".format( expected_auditor_count, len(RUNTIME_AUDITORS.keys())))
def test_find_all_changes(self): from security_monkey.scheduler import find_changes build_mock_result(watcher_configs, auditor_configs) find_changes(['TEST_ACCOUNT1', 'TEST_ACCOUNT2'], ['index1', 'index2', 'index3']) watcher_keys = RUNTIME_WATCHERS.keys() self.assertEqual(first=3, second=len(watcher_keys), msg="Should run 3 watchers but ran {}".format( len(watcher_keys))) self.assertTrue('index1' in watcher_keys, msg="Watcher index1 not run") self.assertTrue('index2' in watcher_keys, msg="Watcher index3 not run") self.assertTrue('index3' in watcher_keys, msg="Watcher index3 not run") self.assertEqual( first=2, second=len(RUNTIME_WATCHERS['index1']), msg="Watcher index1 should run twice but ran {} times".format( len(RUNTIME_WATCHERS['index1']))) self.assertEqual( first=2, second=len(RUNTIME_WATCHERS['index2']), msg="Watcher index2 should run twice but ran {} times".format( len(RUNTIME_WATCHERS['index2']))) self.assertEqual( first=2, second=len(RUNTIME_WATCHERS['index3']), msg="Watcher index2 should run twice but ran {} times".format( len(RUNTIME_WATCHERS['index3']))) auditor_keys = RUNTIME_AUDIT_COUNTS.keys() self.assertEqual(first=3, second=len(auditor_keys), msg="Should run 3 auditors but ran {}".format( len(auditor_keys))) self.assertTrue('index1' in auditor_keys, msg="Auditor index1 not run") self.assertTrue('index2' in auditor_keys, msg="Auditor index2 not run") self.assertTrue('index3' in auditor_keys, msg="Auditor index3 not run") self.assertEqual( first=2, second=RUNTIME_AUDIT_COUNTS['index1'], msg="Auditor index1 should have audited 2 items but audited {}". format(RUNTIME_AUDIT_COUNTS['index1'])) self.assertEqual( first=2, second=RUNTIME_AUDIT_COUNTS['index2'], msg="Auditor index2 should have audited 2 items but audited {}". format(RUNTIME_AUDIT_COUNTS['index2'])) self.assertEqual( first=2, second=RUNTIME_AUDIT_COUNTS['index3'], msg="Auditor index3 should have audited 2 items but audited {}". format(RUNTIME_AUDIT_COUNTS['index3']))
def test_find_account_changes(self): from security_monkey.scheduler import find_changes build_mock_result(watcher_configs, auditor_configs) find_changes(['TEST_ACCOUNT1'], ['index1', 'index2', 'index3']) watcher_keys = RUNTIME_WATCHERS.keys() self.assertEqual(first=3, second=len(watcher_keys), msg="Should run 3 watchers but ran {}" .format(len(watcher_keys))) self.assertTrue('index1' in watcher_keys, msg="Watcher index1 not run") self.assertTrue('index2' in watcher_keys, msg="Watcher index3 not run") self.assertTrue('index3' in watcher_keys, msg="Watcher index3 not run") self.assertEqual(first=1, second=len(RUNTIME_WATCHERS['index1']), msg="Watcher index1 should run once but ran {} times" .format(len(RUNTIME_WATCHERS['index1']))) self.assertEqual(first=1, second=len(RUNTIME_WATCHERS['index2']), msg="Watcher index2 should run once but ran {} times" .format(len(RUNTIME_WATCHERS['index2']))) self.assertEqual(first=1, second=len(RUNTIME_WATCHERS['index3']), msg="Watcher index2 should run once but ran {} times" .format(len(RUNTIME_WATCHERS['index3']))) auditor_keys = RUNTIME_AUDIT_COUNTS.keys() self.assertEqual(first=3, second=len(auditor_keys), msg="Should run 3 auditors but ran {}" .format(len(auditor_keys))) self.assertTrue('index1' in auditor_keys, msg="Auditor index1 not run") self.assertTrue('index2' in auditor_keys, msg="Auditor index2 not run") self.assertTrue('index3' in auditor_keys, msg="Auditor index3 not run") self.assertEqual(first=1, second=RUNTIME_AUDIT_COUNTS['index1'], msg="Auditor index1 should have audited 1 item but audited {}" .format(RUNTIME_AUDIT_COUNTS['index1'])) self.assertEqual(first=1, second=RUNTIME_AUDIT_COUNTS['index2'], msg="Auditor index2 should have audited 1 item but audited {}" .format(RUNTIME_AUDIT_COUNTS['index2'])) self.assertEqual(first=1, second=RUNTIME_AUDIT_COUNTS['index3'], msg="Auditor index3 should have audited 1 item but audited {}" .format(RUNTIME_AUDIT_COUNTS['index3']))
def test_find_monitor_change(self): RUNTIME_AUDITORS.clear() RUNTIME_WATCHERS.clear() find_changes(['TEST_ACCOUNT'], ['s3']) self.assertEqual(first=len(RUNTIME_WATCHERS.keys()), second=1, msg="Should run one watchers but ran {}" .format(len(RUNTIME_WATCHERS.keys()))) expected_auditor_count = 0 for au in auditor_registry['s3']: expected_auditor_count = expected_auditor_count + 1 au_list = RUNTIME_AUDITORS[au.__name__] self.assertEqual(first=len(au_list), second=1, msg="Auditor {} should run once but ran {} time(s)" .format(au.__name__, len(au_list))) self.assertEqual(first=len(RUNTIME_AUDITORS.keys()), second=expected_auditor_count, msg="Should run {} auditor but ran {}" .format(expected_auditor_count, len(RUNTIME_AUDITORS.keys())))
def test_find_batch_changes(self): """ Runs through a full find job via the IAMRole watcher, as that supports batching. However, this is mostly testing the logic through each function call -- this is not going to do any boto work and that will instead be mocked out. :return: """ from security_monkey.scheduler import find_changes from security_monkey.monitors import Monitor from security_monkey.watchers.iam.iam_role import IAMRole from security_monkey.auditors.iam.iam_role import IAMRoleAuditor test_account = Account(name="TEST_ACCOUNT1") watcher = IAMRole(accounts=[test_account.name]) technology = Technology(name="iamrole") db.session.add(technology) db.session.commit() watcher.batched_size = 3 # should loop 4 times self.add_roles() # Set up the monitor: batched_monitor = Monitor(IAMRole, test_account) batched_monitor.watcher = watcher batched_monitor.auditors = [ IAMRoleAuditor(accounts=[test_account.name]) ] import security_monkey.scheduler security_monkey.scheduler.get_monitors = lambda x, y, z: [ batched_monitor ] # Moto screws up the IAM Role ARN -- so we need to fix it: original_slurp_list = watcher.slurp_list original_slurp = watcher.slurp def mock_slurp_list(): items, exception_map = original_slurp_list() for item in watcher.total_list: item["Arn"] = "arn:aws:iam::012345678910:role/{}".format( item["RoleName"]) return items, exception_map def mock_slurp(): batched_items, exception_map = original_slurp() for item in batched_items: item.arn = "arn:aws:iam::012345678910:role/{}".format( item.name) item.config["Arn"] = item.arn item.config["RoleId"] = item.name # Need this to stay the same return batched_items, exception_map watcher.slurp_list = mock_slurp_list watcher.slurp = mock_slurp find_changes([test_account.name], test_account.name) # Check that all items were added to the DB: assert len(Item.query.all()) == 11 # Check that we have exactly 11 item revisions: assert len(ItemRevision.query.all()) == 11 # Check that there are audit issues for all 11 items: assert len(ItemAudit.query.all()) == 11 # Delete one of the items: # Moto lacks implementation for "delete_role" (and I'm too lazy to submit a PR :D) -- so need to create again... mock_iam().stop() mock_sts().stop() self.add_roles(initial=False) # Run the it again: watcher.current_account = None # Need to reset the watcher find_changes([test_account.name], test_account.name) # Check that nothing new was added: assert len(Item.query.all()) == 11 # There should be the same number of issues and 2 more revisions: assert len(ItemAudit.query.all()) == 11 assert len(ItemRevision.query.all()) == 13 # Check that the deleted roles show as being inactive: ir = ItemRevision.query.join((Item, ItemRevision.id == Item.latest_revision_id)) \ .filter(Item.arn.in_( ["arn:aws:iam::012345678910:role/roleNumber9", "arn:aws:iam::012345678910:role/roleNumber10"])).all() assert len(ir) == 2 assert not ir[0].active assert not ir[1].active # Finally -- test with a slurp list exception (just checking that things don't blow up): def mock_slurp_list_with_exception(): import security_monkey.watchers.iam.iam_role security_monkey.watchers.iam.iam_role.list_roles = lambda **kwargs: 1 / 0 items, exception_map = original_slurp_list() assert len(exception_map) > 0 return items, exception_map watcher.slurp_list = mock_slurp_list_with_exception watcher.current_account = None # Need to reset the watcher find_changes([test_account.name], test_account.name) mock_iam().stop() mock_sts().stop()
def test_find_batch_changes(self): """ Runs through a full find job via the IAMRole watcher, as that supports batching. However, this is mostly testing the logic through each function call -- this is not going to do any boto work and that will instead be mocked out. :return: """ from security_monkey.scheduler import find_changes from security_monkey.monitors import Monitor from security_monkey.watchers.iam.iam_role import IAMRole from security_monkey.auditors.iam.iam_role import IAMRoleAuditor test_account = Account(name="TEST_ACCOUNT1") watcher = IAMRole(accounts=[test_account.name]) technology = Technology(name="iamrole") db.session.add(technology) db.session.commit() watcher.batched_size = 3 # should loop 4 times self.add_roles() # Set up the monitor: batched_monitor = Monitor(IAMRole, test_account) batched_monitor.watcher = watcher batched_monitor.auditors = [IAMRoleAuditor(accounts=[test_account.name])] import security_monkey.scheduler security_monkey.scheduler.get_monitors = lambda x, y, z: [batched_monitor] # Moto screws up the IAM Role ARN -- so we need to fix it: original_slurp_list = watcher.slurp_list original_slurp = watcher.slurp def mock_slurp_list(): exception_map = original_slurp_list() for item in watcher.total_list: item["Arn"] = "arn:aws:iam::012345678910:role/{}".format(item["RoleName"]) return exception_map def mock_slurp(): batched_items, exception_map = original_slurp() for item in batched_items: item.arn = "arn:aws:iam::012345678910:role/{}".format(item.name) item.config["Arn"] = item.arn item.config["RoleId"] = item.name # Need this to stay the same return batched_items, exception_map watcher.slurp_list = mock_slurp_list watcher.slurp = mock_slurp find_changes([test_account.name], test_account.name) # Check that all items were added to the DB: assert len(Item.query.all()) == 11 # Check that we have exactly 11 item revisions: assert len(ItemRevision.query.all()) == 11 # Check that there are audit issues for all 11 items: assert len(ItemAudit.query.all()) == 11 # Delete one of the items: # Moto lacks implementation for "delete_role" (and I'm too lazy to submit a PR :D) -- so need to create again... mock_iam().stop() mock_sts().stop() self.add_roles(initial=False) # Run the it again: watcher.current_account = None # Need to reset the watcher find_changes([test_account.name], test_account.name) # Check that nothing new was added: assert len(Item.query.all()) == 11 # There should be 2 less issues and 2 more revisions: assert len(ItemAudit.query.all()) == 9 assert len(ItemRevision.query.all()) == 13 # Check that the deleted roles show as being inactive: ir = ItemRevision.query.join((Item, ItemRevision.id == Item.latest_revision_id)) \ .filter(Item.arn.in_( ["arn:aws:iam::012345678910:role/roleNumber9", "arn:aws:iam::012345678910:role/roleNumber10"])).all() assert len(ir) == 2 assert not ir[0].active assert not ir[1].active # Finally -- test with a slurp list exception (just checking that things don't blow up): def mock_slurp_list_with_exception(): import security_monkey.watchers.iam.iam_role security_monkey.watchers.iam.iam_role.list_roles = lambda **kwargs: 1 / 0 exception_map = original_slurp_list() assert len(exception_map) > 0 return exception_map watcher.slurp_list = mock_slurp_list_with_exception watcher.current_account = None # Need to reset the watcher find_changes([test_account.name], test_account.name) mock_iam().stop() mock_sts().stop()