def test_populate_na_requirement(self, get_cs_requirements, s3_stubber, special_account):
        """Test populate with requirement that doesn't apply to account"""
        cs_data = create_cloudsploit_data({}, [
            {
                'plugin': 'pluginNameOne',
                'category': 'S3',
                'title': 'Plugin Name One',
                'resource': 'arn:aws:s3:::aaa-aaa-aaa-aaa',
                'region': 'global',
                'status': 'FAIL',
                'statusNumber': 2,
                'message': 'sample text'
            },
        ])

        get_cs_requirements.return_value = [{
            'requirementId': '10',
            'weight': Decimal(100),
            'description': 'sample text',
            'source': 'cloudsploit',
            'severity': 'medium',
            'onlyAppliesTo': ['other-than-special'],
            'cloudsploit': {
                'finding': 'Plugin Name One'
            }
        }]
        s3_stubber.add_response('get_object', create_cloudsploit_s3_response(cs_data), {
            'Bucket': os.getenv('CLOUDSPLOIT_RESULT_BUCKET'),
            'Key': os.getenv('CLOUDSPLOIT_PREFIX') + '/' + special_account['accountId'] + '/latest.json',
        })
        scan_id = scans_table.create_new_scan_id()

        cloudsploit_populate({'scanId': scan_id, 'accountId': special_account['accountId']}, {})

        # check NCR record is created
        ncr_records_in_db = ncr_table.query_all(KeyConditionExpression=Key('scanId').eq(scan_id))

        assert ncr_records_in_db == []

        # check score record is created
        score_records_in_db = scores_table.query_all(KeyConditionExpression=Key('scanId').eq(scan_id))

        for record in score_records_in_db:
            assert record.pop('ttl')
        assert score_records_in_db == [
            scores_table.new_score(
                scan_id,
                special_account['accountId'],
                {
                    'requirementId': '10',
                    'severity': 'medium',
                    'weight': Decimal(100)
                },
                scores_table.NOT_APPLICABLE,
                scores_table.NOT_APPLICABLE,
            )
        ]
示例#2
0
def account_detailed_scores_handler(event, context):
    """
    :param event:
    :param context:
    :raises HttpInvalidException if missing 'scanId' or 'accountIds':
    :return account scores of all account_ids in event:
    """
    try:
        account_ids = event['pathParameters']['accountIds']
        scan_id = event['scanId']
    except KeyError:
        raise HttpInvalidException(
            'account ids or scan id not found in request')

    accounts = []
    account_ids = urllib.parse.unquote(account_ids).split(',')
    require_can_read_account(event['userRecord'], account_ids)

    for account_id in account_ids:
        try:
            account_name = accounts_table.get_account(account_id).get(
                'account_name', account_id)
        except KeyError:
            raise HttpNotFoundException(
                f'account record not found for {account_id}')

        if len(account_id) > 0:
            detailed_score = {
                'accountId': account_id,
                'accountName': account_name,
            }
            requirements = []
            to_parse = scores_table.query_all(
                KeyConditionExpression=Key('scanId').eq(scan_id)
                & Key('accntId_rqrmntId').begins_with(account_id), )
            for item in to_parse:
                requirements.append({
                    'requirementId': item['requirementId'],
                    'score': item['score']
                })

            detailed_score['requirementsScores'] = requirements
            accounts.append(detailed_score)

    return {'accounts': accounts}
示例#3
0
def load_scores(accounts: List) -> None:
    """
    Queries accounts' scores from database and stores in CACHE

    Parameters:
    accounts (list): the account to get the scores for.
    """
    scan_id = CACHED_SCAN['scanId']
    if 'account_detail_scores' not in CACHE:
        CACHE['account_detail_scores'] = defaultdict(lambda: defaultdict(dict))
    for account in accounts:
        account_id = account['accountId']
        if account_id not in CACHE['account_detail_scores']:
            logger.debug('Querying account scores')
            account_scores = scores_table.query_all(
                KeyConditionExpression=Key('scanId').eq(scan_id) & Key('accntId_rqrmntId').begins_with(account_id)
            )
            CACHE['account_detail_scores'][account_id] = defaultdict(dict, {
                score['requirementId']: score for score in account_scores
            })
示例#4
0
def score_calc_handler(event, context):
    """
    :param event: {
        scanId: string,
        accountIds: list of accountIds,
    }
    :param context: dict
    :return: None
    """
    scan_id = event['openScan']['scanId']
    account_ids = event['load']['accountIds']
    date = scan_id[0:10]
    all_scores_to_put = []
    all_account_scores = []

    for account_id in account_ids:
        account_name = accounts_table.get_account(account_id).get('account_name')
        scores_to_put = {
            record['requirementId']: record
            for record in scores_table.query_all(
                KeyConditionExpression=Key('scanId').eq(scan_id) & Key('accntId_rqrmntId').begins_with(account_id)
            )
        }
        existing_ncr_records = ncr_table.query_all(
            KeyConditionExpression=Key('scanId').eq(scan_id) & Key('accntId_rsrceId_rqrmntId').begins_with(account_id),
        )

        grouped_ncr_data = defaultdict(list)
        for ncr_object in existing_ncr_records:
            grouped_ncr_data[ncr_object['requirementId']].append(ncr_object)

        for requirement_object in all_requirements:
            severity = requirement_object['severity']
            record_to_edit = scores_to_put.get(requirement_object['requirementId'], False)
            if record_to_edit is False:
                continue  # data not collected for this account for this scan for this requirement, moving on
            score_object = record_to_edit['score'][severity]

            # check if score is DNC if so we skip counting failing resources
            if scores_table.DATA_NOT_COLLECTED in score_object.values():
                continue

            if score_object['numFailing'] is None:
                score_object['numFailing'] = Decimal(0)

            matching_ncrs = grouped_ncr_data.get(requirement_object['requirementId'], [])
            for ncr_record in matching_ncrs:
                is_excluded = ncr_record.get('exclusionApplied', False)
                # TODO handle hidden ncr's also (decrement numResources)
                if is_excluded:
                    continue
                else:
                    score_object['numFailing'] += 1
            all_scores_to_put.append(record_to_edit)

        account_score = {
            'accountId': account_id,
            'accountName': account_name,
            'date': date,
            'scanId': scan_id,
            'score': scores_table.weighted_score_aggregate_calc(scores_to_put.values())
        }
        all_account_scores.append(account_score)

    scores_table.batch_put_records(all_scores_to_put)
    account_scores_table.batch_put_records(all_account_scores)
    def test_populate(self, get_cs_requirements, s3_stubber, regular_account):
        cs_data = create_cloudsploit_data({}, [
            {
                'plugin': 'pluginNameOne',
                'category': 'S3',
                'title': 'Plugin Name One',
                'resource': 'arn:aws:s3:::aaa-aaa-aaa-aaa',
                'region': 'global',
                'status': 'FAIL',
                'statusNumber': 2,
                'message': 'sample text'
            },
            {
                'plugin': 'pluginNameOne',
                'category': 'S3',
                'title': 'Plugin Name Two',
                'resource': 'arn:aws:s3:::aaa-aaa-aaa-aaa',
                'region': 'global',
                'status': 'FAIL',
                'statusNumber': 2,
                'message': 'sample text'
            },
            {
                'plugin': 'pluginNameOne',
                'category': 'S3',
                'title': 'Plugin Name Two',
                'resource': 'arn:aws:s3:::aaa-aaa-aaa-aaa',
                'region': 'global',
                'status': 'FAIL',
                'statusNumber': 2,
                'message': 'sample text2'
            },
        ])

        get_cs_requirements.return_value = [{
            'requirementId': '10',
            'weight': Decimal(100),
            'description': 'sample text',
            'source': 'cloudsploit',
            'severity': 'medium',
            'service': 'organizations',
            'component': 'account',
            'cloudsploit': {
                'finding': [
                    'Plugin Name One',
                    'Plugin Name Two',
                ]
            }
        }]
        s3_stubber.add_response('get_object', create_cloudsploit_s3_response(cs_data), {
            'Bucket': os.getenv('CLOUDSPLOIT_RESULT_BUCKET'),
            'Key': os.getenv('CLOUDSPLOIT_PREFIX') + '/' + regular_account['accountId'] + '/latest.json',
        })
        scan_id = scans_table.create_new_scan_id()

        cloudsploit_populate({'scanId': scan_id, 'accountId': regular_account['accountId']}, {})

        # check NCR record is created
        ncr_records_in_db = ncr_table.query_all(KeyConditionExpression=Key('scanId').eq(scan_id))

        for record in ncr_records_in_db:
            assert record.pop('ttl')
        assert ncr_records_in_db == [
            ncr_table.new_ncr_record({
                'accountId': regular_account['accountId'],
                'accountName': regular_account['account_name'],
                'cloudsploitStatus': 'FAIL',
                'requirementId': '10',
                'resourceId': 'aaa-aaa-aaa-aaa',
                'resourceType': 'organizations-account',
                'region': 'global',
                'reason': 'sample text\nsample text2',
            }, scan_id)
        ]

        # check score record is created
        score_records_in_db = scores_table.query_all(KeyConditionExpression=Key('scanId').eq(scan_id))

        for record in score_records_in_db:
            assert record.pop('ttl')
        assert score_records_in_db == [
            scores_table.new_score(
                scan_id,
                regular_account['accountId'],
                {
                    'requirementId': '10',
                    'severity': 'medium',
                    'weight': Decimal(100)
                },
                Decimal(3)
            )
        ]