Example #1
0
    def test_find_changes_batch(self):
        """
        This will test the entry point via the find_changes() method vs. the find_changes_batch() method.

        This will also use the IAMRole watcher, since that already has batching support.
        :return:
        """
        from security_monkey.watchers.iam.iam_role import IAMRole

        self.setup_batch_db()

        watcher = IAMRole(accounts=[self.account.name])
        watcher.current_account = (self.account, 0)
        watcher.technology = self.technology

        items = []
        for x in range(0, 5):
            mod_conf = dict(ACTIVE_CONF)
            mod_conf["name"] = "SomeRole{}".format(x)
            mod_conf["Arn"] = "arn:aws:iam::012345678910:role/SomeRole{}".format(x)

            items.append(SomeTestItem().from_slurp(mod_conf, account_name=self.account.name))

        assert len(watcher.find_changes(items)) == 5

        # Try again -- audit_items should be 0 since nothing was changed:
        assert len(watcher.find_changes(items)) == 0
Example #2
0
    def test_empty_slurp_list(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])
        watcher.list_method = lambda **kwargs: []

        _, exceptions = watcher.slurp_list()
        assert len(exceptions) == 0
        assert len(watcher.total_list) == 0
        assert watcher.done_slurping
Example #3
0
    def test_slurp_list(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        _, exceptions = watcher.slurp_list()

        assert len(exceptions) == 0
        assert len(watcher.total_list) == self.total_roles
        assert not watcher.done_slurping
Example #4
0
    def test_slurp_list(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        _, exceptions = watcher.slurp_list()

        assert len(exceptions) == 0
        assert len(watcher.total_list) == self.total_roles
        assert not watcher.done_slurping

        mock_sts().stop()
Example #5
0
    def test_empty_slurp_list(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])
        watcher.list_method = lambda **kwargs: []

        _, exceptions = watcher.slurp_list()
        assert len(exceptions) == 0
        assert len(watcher.total_list) == 0
        assert watcher.done_slurping

        mock_sts().stop()
Example #6
0
    def test_slurp_list_exceptions(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        def raise_exception():
            raise Exception("LOL, HAY!")

        watcher.list_method = lambda **kwargs: raise_exception()

        _, exceptions = watcher.slurp_list()
        assert len(exceptions) == 1
        assert len(ExceptionLogs.query.all()) == 1
Example #7
0
    def test_slurp_list_exceptions(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        def raise_exception():
            raise Exception("LOL, HAY!")

        watcher.list_method = lambda **kwargs: raise_exception()

        _, exceptions = watcher.slurp_list()
        assert len(exceptions) == 1
        assert len(ExceptionLogs.query.all()) == 1

        mock_sts().stop()
Example #8
0
    def test_slurp_list_exceptions(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        def raise_exception():
            raise Exception("LOL, HAY!")

        import security_monkey.watchers.iam.iam_role
        security_monkey.watchers.iam.iam_role.list_roles = lambda **kwargs: raise_exception()

        exceptions = watcher.slurp_list()
        assert len(exceptions) == 1
        assert len(ExceptionLogs.query.all()) == 1

        mock_sts().stop()
Example #9
0
    def test_celery_beat(self, mock_expired_exceptions, mock_account_tech,
                         mock_purge, mock_setup):
        from security_monkey.task_scheduler.beat import setup_the_tasks
        from security_monkey.watchers.iam.iam_role import IAMRole
        from security_monkey.auditors.iam.iam_role import IAMRoleAuditor

        # Set up the monitor:
        test_account = Account.query.filter(
            Account.name == "TEST_ACCOUNT1").one()
        watcher = IAMRole(accounts=[test_account.name])
        batched_monitor = Monitor(IAMRole, test_account)
        batched_monitor.watcher = watcher
        batched_monitor.auditors = [
            IAMRoleAuditor(accounts=[test_account.name])
        ]

        import security_monkey.task_scheduler.tasks
        old_get_monitors = security_monkey.task_scheduler.tasks.get_monitors
        security_monkey.task_scheduler.tasks.get_monitors = lambda x, y, z: [
            batched_monitor
        ]

        setup_the_tasks(mock.Mock())

        assert mock_setup.called
        assert mock_purge.called

        # "apply_async" where the immediately scheduled tasks
        assert mock_account_tech.apply_async.called

        # The ".s" are the scheduled tasks. Too lazy to grab the intervals out.
        assert mock_account_tech.s.called
        assert mock_expired_exceptions.s.called
        #assert mock_task_audit.s.called

        # Build the expected mock results:
        scheduled_tech_result_list = []
        async_result_list = []
        # audit_result_list = []

        import security_monkey.watcher
        import security_monkey.auditor

        for account in Account.query.filter(
                Account.third_party == False).filter(
                    Account.active == True).all():  # noqa
            for w in security_monkey.watcher.watcher_registry.iterkeys():
                scheduled_tech_result_list.append(((account.name, w), ))
                async_result_list.append((((account.name, w), ), ))

            # It's just policy for IAM:
            # audit_result_list.append(((account.name, "policy"),))

        assert mock_account_tech.s.call_args_list == scheduled_tech_result_list
        assert async_result_list == mock_account_tech.apply_async.call_args_list
        # assert audit_result_list == mock_task_audit.s.call_args_list

        security_monkey.task_scheduler.tasks.get_monitors = old_get_monitors
Example #10
0
    def test_slurp_items_with_exceptions(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        # Or else this will take forever:
        watcher.batched_size = 10
        watcher.slurp_list()

        def raise_exception():
            raise Exception("LOL, HAY!")

        import security_monkey.watchers.iam.iam_role
        security_monkey.watchers.iam.iam_role.get_role = lambda **kwargs: raise_exception()

        items, exceptions = watcher.slurp()
        assert len(exceptions) == self.total_roles
        assert len(items) == 0

        mock_sts().stop()
    def test_find_changes_batch(self):
        """
        This will test the entry point via the find_changes() method vs. the find_changes_batch() method.

        This will also use the IAMRole watcher, since that already has batching support.
        :return:
        """
        from security_monkey.watchers.iam.iam_role import IAMRole

        self.setup_batch_db()

        watcher = IAMRole(accounts=[self.account.name])
        watcher.current_account = (self.account, 0)
        watcher.technology = self.technology

        items = []
        for x in range(0, 5):
            mod_conf = dict(ACTIVE_CONF)
            mod_conf["name"] = "SomeRole{}".format(x)
            mod_conf[
                "Arn"] = "arn:aws:iam::012345678910:role/SomeRole{}".format(x)

            items.append(SomeTestItem().from_slurp(
                mod_conf, account_name=self.account.name))

        assert len(watcher.find_changes(items)) == 5

        # Try again -- audit_items should be 0 since nothing was changed:
        assert len(watcher.find_changes(items)) == 0
Example #12
0
    def test_slurp_items_with_skipped(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        watcher.batched_size = 5
        watcher.slurp_list()

        watcher.ignore_list = [
            IgnoreListEntry(prefix="roleNumber0"),
            IgnoreListEntry(prefix="roleNumber1"),
            IgnoreListEntry(prefix="roleNumber6")
        ]

        first_batch, exceptions = watcher.slurp()
        item_sum = len(first_batch)
        assert len(exceptions) == 0
        assert watcher.batch_counter == 1

        batch_lookup = {}  # Ensure we aren't processing duplicates
        for r in first_batch:
            assert r.name not in watcher.ignore_list  # Ensure we properly ignore the things
            batch_lookup[r.name] = True

        # Slurp again:
        second_batch, exceptions = watcher.slurp()
        item_sum += len(second_batch)
        assert len(exceptions) == 0
        assert watcher.batch_counter == 2

        for r in second_batch:
            assert r.name not in watcher.ignore_list
            assert not batch_lookup.get(r.name)
            batch_lookup[r.name] = True

        # Sum of items should be total items - length of the ignored items:
        assert self.total_roles - len(
            watcher.ignore_list) == item_sum == len(batch_lookup)

        mock_sts().stop()
Example #13
0
    def test_slurp_items_with_exceptions(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        # Or else this will take forever:
        watcher.batched_size = 10
        watcher.slurp_list()

        def raise_exception():
            raise Exception("LOL, HAY!")

        watcher.get_method = lambda *args, **kwargs: raise_exception()

        items, exceptions = watcher.slurp()
        assert len(exceptions) == self.total_roles
        assert len(items) == 0

        mock_sts().stop()
Example #14
0
    def test_slurp_items(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        # Or else this will take forever:
        watcher.batched_size = 10
        watcher.slurp_list()

        items, exceptions = watcher.slurp()
        assert len(exceptions) == 0
        assert self.total_roles > len(items) == watcher.batched_size
        assert watcher.batch_counter == 1

        # Slurp again:
        items, exceptions = watcher.slurp()
        assert len(exceptions) == 0
        assert self.total_roles > len(items) == watcher.batched_size
        assert watcher.batch_counter == 2
Example #15
0
    def test_slurp_items_with_skipped(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        watcher.batched_size = 5
        watcher.slurp_list()

        watcher.ignore_list = [
            IgnoreListEntry(prefix="roleNumber0"),
            IgnoreListEntry(prefix="roleNumber1"),
            IgnoreListEntry(prefix="roleNumber6")
        ]

        first_batch, exceptions = watcher.slurp()
        item_sum = len(first_batch)
        assert len(exceptions) == 0
        assert watcher.batch_counter == 1

        batch_lookup = {}   # Ensure we aren't processing duplicates
        for r in first_batch:
            assert r.name not in watcher.ignore_list    # Ensure we properly ignore the things
            batch_lookup[r.name] = True

        # Slurp again:
        second_batch, exceptions = watcher.slurp()
        item_sum += len(second_batch)
        assert len(exceptions) == 0
        assert watcher.batch_counter == 2

        for r in second_batch:
            assert r.name not in watcher.ignore_list
            assert not batch_lookup.get(r.name)
            batch_lookup[r.name] = True

        # Sum of items should be total items - length of the ignored items:
        assert self.total_roles - len(watcher.ignore_list) == item_sum == len(batch_lookup)

        mock_sts().stop()
Example #16
0
    def test_slurp_items_with_exceptions(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        # Or else this will take forever:
        watcher.batched_size = 10
        watcher.slurp_list()

        def raise_exception():
            raise Exception("LOL, HAY!")

        watcher.get_method = lambda *args, **kwargs: raise_exception()

        items, exceptions = watcher.slurp()

        assert len(exceptions) == watcher.batched_size
        assert len(items) == 0
        assert watcher.batch_counter == 1

        mock_sts().stop()
Example #17
0
    def test_slurp_items(self):
        mock_sts().start()

        watcher = IAMRole(accounts=[self.account.name])

        # Or else this will take forever:
        watcher.batched_size = 10
        watcher.slurp_list()

        items, exceptions = watcher.slurp()
        assert len(exceptions) == 0
        assert self.total_roles > len(items) == watcher.batched_size
        assert watcher.batch_counter == 1

        # Slurp again:
        items, exceptions = watcher.slurp()
        assert len(exceptions) == 0
        assert self.total_roles > len(items) == watcher.batched_size
        assert watcher.batch_counter == 2

        mock_sts().stop()
Example #18
0
    def test_find_deleted_batch(self):
        """
        This will use the IAMRole watcher, since that already has batching support.
        :return:
        """
        from security_monkey.watchers.iam.iam_role import IAMRole

        self.setup_batch_db()

        # Set everything up:
        watcher = IAMRole(accounts=[self.account.name])
        watcher.current_account = (self.account, 0)
        watcher.technology = self.technology

        items = []
        for x in range(0, 5):
            mod_conf = dict(ACTIVE_CONF)
            mod_conf["name"] = "SomeRole{}".format(x)
            mod_conf["Arn"] = ARN_PREFIX + ":iam::012345678910:role/SomeRole{}".format(x)
            items.append(SomeTestItem().from_slurp(mod_conf, account_name=self.account.name))

            mod_aspd = dict(ASPD)
            mod_aspd["Arn"] = ARN_PREFIX + ":iam::012345678910:role/SomeRole{}".format(x)
            mod_aspd["RoleName"] = "SomeRole{}".format(x)
            watcher.total_list.append(mod_aspd)

        watcher.find_changes(items)

        # Check for deleted items:
        watcher.find_deleted_batch({})
        assert len(watcher.deleted_items) == 0

        # Check that nothing was deleted:
        for x in range(0, 5):
            item_revision = ItemRevision.query.join((Item, ItemRevision.id == Item.latest_revision_id)).filter(
                Item.arn == ARN_PREFIX + ":iam::012345678910:role/SomeRole{}".format(x),
            ).one()

            assert item_revision.active

            # Create some issues for testing purposes:
            db.session.add(ItemAudit(score=10,
                                     issue="IAM Role has full admin permissions.",
                                     notes=json.dumps(item_revision.config),
                                     item_id=item_revision.item_id))
            db.session.add(ItemAudit(score=9001, issue="Some test issue", notes="{}", item_id=item_revision.item_id))

        db.session.commit()
        assert len(ItemAudit.query.all()) == len(items) * 2

        # Remove the last two items:
        removed_arns = []
        removed_arns.append(watcher.total_list.pop()["Arn"])
        removed_arns.append(watcher.total_list.pop()["Arn"])

        # Check for deleted items again:
        watcher.find_deleted_batch({})
        assert len(watcher.deleted_items) == 2

        # Check that the last two items were deleted:
        for arn in removed_arns:
            item_revision = ItemRevision.query.join((Item, ItemRevision.id == Item.latest_revision_id)).filter(
                Item.arn == arn,
            ).one()

            assert not item_revision.active

        # Check that the current ones weren't deleted:
        for current_item in watcher.total_list:
            item_revision = ItemRevision.query.join((Item, ItemRevision.id == Item.latest_revision_id)).filter(
                Item.arn == current_item["Arn"],
            ).one()

            assert item_revision.active
            assert len(ItemAudit.query.filter(ItemAudit.item_id == item_revision.item_id).all()) == 2
Example #19
0
    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()
Example #20
0
    def test_find_batch_changes(self, mock_fix_orphaned):
        """
        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.task_scheduler.tasks import manual_run_change_finder
        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.task_scheduler.tasks
        old_get_monitors = security_monkey.task_scheduler.tasks.get_monitors
        security_monkey.task_scheduler.tasks.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_PREFIX + ":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_PREFIX + ":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

        manual_run_change_finder([test_account.name], [watcher.index])
        assert mock_fix_orphaned.called

        # 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
        manual_run_change_finder([test_account.name], [watcher.index])

        # 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_PREFIX + ":iam::012345678910:role/roleNumber9",
                 ARN_PREFIX + ":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):
        import security_monkey.watchers.iam.iam_role
        old_list_roles = security_monkey.watchers.iam.iam_role.list_roles

        def mock_slurp_list_with_exception():
            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
        manual_run_change_finder([test_account.name], [watcher.index])

        security_monkey.task_scheduler.tasks.get_monitors = old_get_monitors
        security_monkey.watchers.iam.iam_role.list_roles = old_list_roles

        mock_iam().stop()
        mock_sts().stop()
Example #21
0
    def test_ensure_item_has_latest_revision_id(self):
        """
        Test that items always have a proper current revision set.  Otherwise, the item needs to be deleted.
        :return:
        """
        from security_monkey.watchers.iam.iam_role import IAMRole
        from security_monkey.watcher import ensure_item_has_latest_revision_id
        from security_monkey.datastore import Datastore

        # Stop the watcher registry from stepping on everyone's toes:
        import security_monkey.watcher
        old_watcher_registry = security_monkey.watcher.watcher_registry
        security_monkey.watcher.watcher_registry = {IAMRole.index: IAMRole}

        # Set everything up:
        self.setup_batch_db()
        watcher = IAMRole(accounts=[self.account.name])
        watcher.current_account = (self.account, 0)
        watcher.technology = self.technology

        # Test case #1: Create an item in the DB that has no current revision ID:
        no_revision_item = Item(region="us-east-1", name="NOREVISION", account_id=self.account.id,
                                tech_id=self.technology.id)
        db.session.add(no_revision_item)
        db.session.commit()

        assert db.session.query(Item).filter(Item.name == no_revision_item.name).one()

        # Should delete the item from the DB:
        result = ensure_item_has_latest_revision_id(no_revision_item)
        assert not result
        assert not db.session.query(Item).filter(Item.name == no_revision_item.name).first()

        # Test case #2: Create two item revisions for the given item, but don't attach them to the item.
        #               After the fixer runs, it should return the item with proper hashes and a proper
        #               link to the latest version.
        ds = Datastore()
        no_revision_item = Item(region="us-east-1", name="NOREVISION", account_id=self.account.id,
                                tech_id=self.technology.id)
        db.session.add(no_revision_item)
        db.session.commit()

        ir_one = ItemRevision(config=ACTIVE_CONF, date_created=datetime.datetime.utcnow(),
                              item_id=no_revision_item.id)
        ir_two = ItemRevision(config=ACTIVE_CONF,
                              date_created=(datetime.datetime.utcnow() - timedelta(days=1)),
                              item_id=no_revision_item.id)

        db.session.add(ir_one)
        db.session.add(ir_two)
        db.session.commit()

        assert len(db.session.query(ItemRevision).filter(ItemRevision.item_id == no_revision_item.id).all()) == 2
        result = ensure_item_has_latest_revision_id(no_revision_item)
        assert result
        assert result.latest_revision_id == ir_one.id
        assert ds.hash_config(ACTIVE_CONF) == no_revision_item.latest_revision_complete_hash
        assert ds.durable_hash(ACTIVE_CONF, watcher.ephemeral_paths) == no_revision_item.latest_revision_durable_hash

        # Undo the mock:
        security_monkey.watcher.watcher_registry = old_watcher_registry
Example #22
0
    def test_report_batch_changes(self, mock_fix_orphaned):
        from security_monkey.task_scheduler.tasks import manual_run_change_reporter
        from security_monkey.datastore import Item, ItemRevision, ItemAudit
        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.query.filter(
            Account.name == "TEST_ACCOUNT1").one()

        watcher = IAMRole(accounts=[test_account.name])

        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])
        ]

        # Set up the Reporter:
        import security_monkey.reporter
        old_all_monitors = security_monkey.reporter.all_monitors
        security_monkey.reporter.all_monitors = lambda x, y: [batched_monitor]

        import security_monkey.task_scheduler.tasks
        old_get_monitors = security_monkey.task_scheduler.tasks.get_monitors
        security_monkey.task_scheduler.tasks.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_PREFIX + ":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_PREFIX + ":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

        manual_run_change_reporter([test_account.name])

        assert mock_fix_orphaned.called

        # 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

        mock_iam().stop()
        mock_sts().stop()

        security_monkey.reporter.all_monitors = old_all_monitors
        security_monkey.task_scheduler.tasks.get_monitors = old_get_monitors
    def test_ensure_item_has_latest_revision_id(self):
        """
        Test that items always have a proper current revision set.  Otherwise, the item needs to be deleted.
        :return:
        """
        from security_monkey.watchers.iam.iam_role import IAMRole
        from security_monkey.watcher import ensure_item_has_latest_revision_id
        from security_monkey.datastore import Datastore

        # Stop the watcher registry from stepping on everyone's toes:
        import security_monkey.watcher
        old_watcher_registry = security_monkey.watcher.watcher_registry
        security_monkey.watcher.watcher_registry = {IAMRole.index: IAMRole}

        # Set everything up:
        self.setup_batch_db()
        watcher = IAMRole(accounts=[self.account.name])
        watcher.current_account = (self.account, 0)
        watcher.technology = self.technology

        # Test case #1: Create an item in the DB that has no current revision ID:
        no_revision_item = Item(region="us-east-1",
                                name="NOREVISION",
                                account_id=self.account.id,
                                tech_id=self.technology.id)
        db.session.add(no_revision_item)
        db.session.commit()

        assert db.session.query(Item).filter(
            Item.name == no_revision_item.name).one()

        # Should delete the item from the DB:
        result = ensure_item_has_latest_revision_id(no_revision_item)
        assert not result
        assert not db.session.query(Item).filter(
            Item.name == no_revision_item.name).first()

        # Test case #2: Create two item revisions for the given item, but don't attach them to the item.
        #               After the fixer runs, it should return the item with proper hashes and a proper
        #               link to the latest version.
        ds = Datastore()
        no_revision_item = Item(region="us-east-1",
                                name="NOREVISION",
                                account_id=self.account.id,
                                tech_id=self.technology.id)
        db.session.add(no_revision_item)
        db.session.commit()

        ir_one = ItemRevision(config=ACTIVE_CONF,
                              date_created=datetime.datetime.utcnow(),
                              item_id=no_revision_item.id)
        ir_two = ItemRevision(config=ACTIVE_CONF,
                              date_created=(datetime.datetime.utcnow() -
                                            timedelta(days=1)),
                              item_id=no_revision_item.id)

        db.session.add(ir_one)
        db.session.add(ir_two)
        db.session.commit()

        assert len(
            db.session.query(ItemRevision).filter(
                ItemRevision.item_id == no_revision_item.id).all()) == 2
        result = ensure_item_has_latest_revision_id(no_revision_item)
        assert result
        assert result.latest_revision_id == ir_one.id
        assert ds.hash_config(
            ACTIVE_CONF) == no_revision_item.latest_revision_complete_hash
        assert ds.durable_hash(
            ACTIVE_CONF, watcher.ephemeral_paths
        ) == no_revision_item.latest_revision_durable_hash

        # Undo the mock:
        security_monkey.watcher.watcher_registry = old_watcher_registry
    def test_find_deleted_batch(self):
        """
        This will use the IAMRole watcher, since that already has batching support.
        :return:
        """
        from security_monkey.watchers.iam.iam_role import IAMRole

        self.setup_batch_db()

        # Set everything up:
        watcher = IAMRole(accounts=[self.account.name])
        watcher.current_account = (self.account, 0)
        watcher.technology = self.technology

        items = []
        for x in range(0, 5):
            mod_conf = dict(ACTIVE_CONF)
            mod_conf["name"] = "SomeRole{}".format(x)
            mod_conf[
                "Arn"] = ARN_PREFIX + ":iam::012345678910:role/SomeRole{}".format(
                    x)
            items.append(SomeTestItem().from_slurp(
                mod_conf, account_name=self.account.name))

            mod_aspd = dict(ASPD)
            mod_aspd[
                "Arn"] = ARN_PREFIX + ":iam::012345678910:role/SomeRole{}".format(
                    x)
            mod_aspd["RoleName"] = "SomeRole{}".format(x)
            watcher.total_list.append(mod_aspd)

        watcher.find_changes(items)

        # Check for deleted items:
        watcher.find_deleted_batch({})
        assert len(watcher.deleted_items) == 0

        # Check that nothing was deleted:
        for x in range(0, 5):
            item_revision = ItemRevision.query.join(
                (Item, ItemRevision.id == Item.latest_revision_id)).filter(
                    Item.arn == ARN_PREFIX +
                    ":iam::012345678910:role/SomeRole{}".format(x), ).one()

            assert item_revision.active

            # Create some issues for testing purposes:
            db.session.add(
                ItemAudit(score=10,
                          issue="IAM Role has full admin permissions.",
                          notes=json.dumps(item_revision.config),
                          item_id=item_revision.item_id))
            db.session.add(
                ItemAudit(score=9001,
                          issue="Some test issue",
                          notes="{}",
                          item_id=item_revision.item_id))

        db.session.commit()
        assert len(ItemAudit.query.all()) == len(items) * 2

        # Remove the last two items:
        removed_arns = []
        removed_arns.append(watcher.total_list.pop()["Arn"])
        removed_arns.append(watcher.total_list.pop()["Arn"])

        # Check for deleted items again:
        watcher.find_deleted_batch({})
        assert len(watcher.deleted_items) == 2

        # Check that the last two items were deleted:
        for arn in removed_arns:
            item_revision = ItemRevision.query.join(
                (Item, ItemRevision.id == Item.latest_revision_id)).filter(
                    Item.arn == arn, ).one()

            assert not item_revision.active

        # Check that the current ones weren't deleted:
        for current_item in watcher.total_list:
            item_revision = ItemRevision.query.join(
                (Item, ItemRevision.id == Item.latest_revision_id)).filter(
                    Item.arn == current_item["Arn"], ).one()

            assert item_revision.active
            assert len(
                ItemAudit.query.filter(
                    ItemAudit.item_id == item_revision.item_id).all()) == 2
Example #25
0
    def test_celery_ignore_tech(self, mock_store_exception,
                                mock_expired_exceptions, mock_account_tech,
                                mock_purge, mock_setup):
        import security_monkey.celeryconfig
        security_monkey.celeryconfig.security_monkey_watcher_ignore = {
            "policy"
        }

        from security_monkey.task_scheduler.beat import setup_the_tasks
        from security_monkey.watchers.iam.iam_role import IAMRole
        from security_monkey.watchers.iam.managed_policy import ManagedPolicy
        from security_monkey.auditors.iam.iam_role import IAMRoleAuditor
        from security_monkey.auditors.iam.iam_policy import IAMPolicyAuditor

        # Stop the watcher registry from stepping on everyone's toes:
        import security_monkey.watcher
        import security_monkey.monitors
        security_monkey.watcher.watcher_registry = {
            IAMRole.index: IAMRole,
            ManagedPolicy.index: ManagedPolicy
        }
        security_monkey.monitors.watcher_registry = security_monkey.watcher.watcher_registry

        # Set up the monitors:
        test_account = Account.query.filter(
            Account.name == "TEST_ACCOUNT1").one()
        role_watcher = IAMRole(accounts=[test_account.name])
        mp_watcher = ManagedPolicy(accounts=[test_account.name])
        batched_monitor = Monitor(IAMRole, test_account)
        batched_monitor.watcher = role_watcher
        batched_monitor.auditors = [
            IAMRoleAuditor(accounts=[test_account.name])
        ]
        normal_monitor = Monitor(ManagedPolicy, test_account)
        normal_monitor.watcher = mp_watcher
        normal_monitor.auditors = [
            IAMPolicyAuditor(accounts=[test_account.name])
        ]

        import security_monkey.task_scheduler.tasks
        old_get_monitors = security_monkey.task_scheduler.tasks.get_monitors
        security_monkey.task_scheduler.tasks.get_monitors = lambda x, y, z: [
            batched_monitor, normal_monitor
        ]

        setup_the_tasks(mock.Mock())

        assert mock_setup.called
        assert mock_purge.called
        assert not mock_store_exception.called

        # "apply_async" where the immediately scheduled tasks
        assert mock_account_tech.apply_async.called

        # The ".s" are the scheduled tasks. Too lazy to grab the intervals out.
        assert mock_account_tech.s.called
        assert mock_expired_exceptions.s.called
        assert mock_expired_exceptions.apply_async.called

        # Policy should not be called at all:
        for mocked_call in mock_account_tech.s.call_args_list:
            assert mocked_call[0][1] == "iamrole"

        for mocked_call in mock_account_tech.apply_async.call_args_list:
            assert mocked_call[0][0][1] == "iamrole"

        security_monkey.task_scheduler.tasks.get_monitors = old_get_monitors
Example #26
0
    def test_report_batch_changes(self):
        from security_monkey.alerter import Alerter
        from security_monkey.reporter import Reporter
        from security_monkey.datastore import Item, ItemRevision, ItemAudit
        from security_monkey.monitors import Monitor
        from security_monkey.watchers.iam.iam_role import IAMRole
        from security_monkey.auditors.iam.iam_role import IAMRoleAuditor

        account_type_result = AccountType.query.filter(
            AccountType.name == "AWS").one()
        db.session.add(account_type_result)
        db.session.commit()

        test_account = Account(identifier="012345678910",
                               name="TEST_ACCOUNT",
                               account_type_id=account_type_result.id,
                               notes="TEST_ACCOUNT1",
                               third_party=False,
                               active=True)
        watcher = IAMRole(accounts=[test_account.name])
        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])
        ]

        # Set up the Reporter:
        import security_monkey.reporter
        old_all_monitors = security_monkey.reporter.all_monitors
        security_monkey.reporter.all_monitors = lambda x, y: []

        test_reporter = Reporter()
        test_reporter.all_monitors = [batched_monitor]
        test_reporter.account_alerter = Alerter(
            watchers_auditors=test_reporter.all_monitors,
            account=test_account.name)

        import security_monkey.scheduler
        # import security_monkey.monitors
        # old_get_monitors = security_monkey.scheduler.get_monitors
        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

        test_reporter.run(account=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

        mock_iam().stop()
        mock_sts().stop()

        # Something isn't cleaning itself up properly and causing other core tests to fail.
        # This is the solution:
        security_monkey.reporter.all_monitors = old_all_monitors
        import monitor_mock
        security_monkey.scheduler.get_monitors = monitor_mock.mock_get_monitors
Example #27
0
    def test_find_batch_changes(self, mock_fix_orphaned):
        """
        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.task_scheduler.tasks import manual_run_change_finder
        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

        ## CREATE MOCK IAM ROLES ##
        client = boto3.client("iam")
        aspd = {
            "Version":
            "2012-10-17",
            "Statement": [{
                "Effect": "Allow",
                "Action": "sts:AssumeRole",
                "Principal": {
                    "Service": "ec2.amazonaws.com"
                }
            }]
        }
        for x in range(0, 11):
            # Create the IAM Role via Moto:
            aspd["Statement"][0][
                "Resource"] = ARN_PREFIX + ":iam:012345678910:role/roleNumber{}".format(
                    x)
            client.create_role(Path="/",
                               RoleName="roleNumber{}".format(x),
                               AssumeRolePolicyDocument=json.dumps(aspd,
                                                                   indent=4))
            client.put_role_policy(RoleName="roleNumber{}".format(x),
                                   PolicyName="testpolicy",
                                   PolicyDocument=json.dumps(OPEN_POLICY,
                                                             indent=4))

        # 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.task_scheduler.tasks
        old_get_monitors = security_monkey.task_scheduler.tasks.get_monitors
        security_monkey.task_scheduler.tasks.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_PREFIX + ":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_PREFIX + ":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

        manual_run_change_finder([test_account.name], [watcher.index])
        assert mock_fix_orphaned.called

        # 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 two of the items:
        managedPolicy = client.list_attached_role_policies(
            RoleName="roleNumber9")
        for each in managedPolicy['AttachedPolicies']:
            print("Detaching ", each)
            client.detach_role_policy(RoleName="roleNumber9",
                                      PolicyArn=each['PolicyArn'])

        inlinePolicy = client.list_role_policies(RoleName="roleNumber9")
        for each in inlinePolicy['PolicyNames']:
            print("Deleting ", each)
            client.delete_role_policy(RoleName="roleNumber9", PolicyName=each)

        instanceProfiles = client.list_instance_profiles_for_role(
            RoleName="roleNumber9")
        for each in instanceProfiles['InstanceProfiles']:
            print("Removing role from instance profile ", each)
            client.remove_role_from_instance_profile(
                RoleName="roleNumber9",
                InstanceProfileName=each['InstanceProfileName'])
        client.delete_role(RoleName="roleNumber9")

        managedPolicy = client.list_attached_role_policies(
            RoleName="roleNumber10")
        for each in managedPolicy['AttachedPolicies']:
            print("Detaching ", each)
            client.detach_role_policy(RoleName="roleNumber10",
                                      PolicyArn=each['PolicyArn'])

        inlinePolicy = client.list_role_policies(RoleName="roleNumber10")
        for each in inlinePolicy['PolicyNames']:
            print("Deleting ", each)
            client.delete_role_policy(RoleName="roleNumber10", PolicyName=each)

        instanceProfiles = client.list_instance_profiles_for_role(
            RoleName="roleNumber10")
        for each in instanceProfiles['InstanceProfiles']:
            print("Removing role from instance profile ", each)
            client.remove_role_from_instance_profile(
                RoleName="roleNumber10",
                InstanceProfileName=each['InstanceProfileName'])
        client.delete_role(RoleName="roleNumber10")

        # Run the it again:
        watcher.current_account = None  # Need to reset the watcher
        manual_run_change_finder([test_account.name], [watcher.index])

        # 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_PREFIX + ":iam::012345678910:role/roleNumber9",
                 ARN_PREFIX + ":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):
        import security_monkey.watchers.iam.iam_role
        old_list_roles = security_monkey.watchers.iam.iam_role.list_roles

        def mock_slurp_list_with_exception():
            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
        manual_run_change_finder([test_account.name], [watcher.index])

        security_monkey.task_scheduler.tasks.get_monitors = old_get_monitors
        security_monkey.watchers.iam.iam_role.list_roles = old_list_roles
Example #28
0
    def test_report_batch_changes(self):
        from security_monkey.alerter import Alerter
        from security_monkey.reporter import Reporter
        from security_monkey.datastore import Item, ItemRevision, ItemAudit
        from security_monkey.monitors import Monitor
        from security_monkey.watchers.iam.iam_role import IAMRole
        from security_monkey.auditors.iam.iam_role import IAMRoleAuditor

        account_type_result = AccountType.query.filter(AccountType.name == "AWS").one()
        db.session.add(account_type_result)
        db.session.commit()

        test_account = Account(name="TEST_ACCOUNT")
        watcher = IAMRole(accounts=[test_account.name])
        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])]

        # Set up the Reporter:
        import security_monkey.reporter
        old_all_monitors = security_monkey.reporter.all_monitors
        security_monkey.reporter.all_monitors = lambda x, y: []

        test_reporter = Reporter()
        test_reporter.all_monitors = [batched_monitor]
        test_reporter.account_alerter = Alerter(watchers_auditors=test_reporter.all_monitors, account=test_account.name)

        import security_monkey.scheduler
        # import security_monkey.monitors
        # old_get_monitors = security_monkey.scheduler.get_monitors
        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

        test_reporter.run(account=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

        mock_iam().stop()
        mock_sts().stop()

        # Something isn't cleaning itself up properly and causing other core tests to fail.
        # This is the solution:
        security_monkey.reporter.all_monitors = old_all_monitors
        import monitor_mock
        security_monkey.scheduler.get_monitors = monitor_mock.mock_get_monitors