def test_send_metrics(mocker): expected_response = { 'Solution': 'SO0111', 'UUID': '12345678-1234-1234-1234-123412341234', 'TimeStamp': mocker.ANY, 'Data': { 'generator_id': 'arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0/rule/1.3', 'type': '1.3 Ensure credentials unused for 90 days or greater are disabled', 'productArn': mocker.ANY, 'finding_triggered_by': 'unit-test', 'region': mocker.ANY }, 'Version': 'v1.2.0TEST' } os.environ['sendAnonymousMetrics'] = 'Yes' finding = utils.load_test_data(test_data + 'cis_1-3-iamuser1.json', my_region).get('detail').get('findings')[0] ssmc = boto3.client('ssm', region_name=my_region) ssmc_s = Stubber(ssmc) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_uuid) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_version) ssmc_s.activate() mocker.patch('lib.metrics.Metrics.connect_to_ssm', return_value=ssmc) metrics = Metrics({"detail-type": "unit-test"}) metrics_data = metrics.get_metrics_from_finding(finding) send_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) metrics.send_metrics(metrics_data) send_metrics.assert_called_with(expected_response)
def notify(finding, message, logger, cwlogs=False, sechub=True, sns=False): """ Consolidates several outputs to a single call. Attributes ---------- finding: finding object for which notification is to be done message: dict of notification data: { 'Account': string, 'AffectedOject': string, 'Remediation': string, 'State': string, 'Note': string } logger: logger object for logging to stdout cwlogs: boolean - log to application log group? sechub: boolean - update Security Hub notes on the finding? sns: boolean - send to sns topic? """ remediation_adj = '' if 'State' in message: if message['State'] == 'RESOLVED': remediation_adj = 'remediation was successful' elif message['State'] == 'INITIAL': remediation_adj = 'remediation started' elif message['State'] == 'FAILED': remediation_adj = 'remediation failed. Please remediate manually' if 'Note' not in message or not message['Note']: message['Note'] = '"' + message.get('Remediation', 'error missing remediation') +\ '" ' + remediation_adj else: message['State'] = 'INFO' if 'Note' not in message or not message['Note']: message['Note'] = 'error - missing note' #send metrics try: metrics_data = message['metrics_data'] metrics = Metrics({'detail-type': 'None'}) metrics_data['status'] = message['State'] metrics.send_metrics(metrics_data) except Exception as e: logger.error(e) logger.error('Failed to send metrics') # lambda logs - always logger.info( message.get('State', 'INFO') + ': ' + message.get('Note') +\ ', Account Id: ' + message.get('Account', 'error') + \ ', Resource: ' + message.get('AffectedObject', 'error') ) # log to application log if cwlogs: # to take advantage of buffering, the caller controls the # connection. cwlogs.add_message( message.get('State') + ': ' + message.get('Note') +\ ', Account Id: ' + message.get('Account', 'error') + \ ', Resource: ' + message.get('AffectedObject', 'error') ) if sechub: if message.get('State') == 'RESOLVED': finding.resolve(message.get('State') + ': ' + message.get('Note')) elif message.get('State') == 'INITIAL': finding.flag(message.get('State') + ': ' + message.get('Note')) else: finding.update_text( message.get('State', 'INFO') + ': ' + message.get('Note')) if sns: try: sns.postit('SO0111-SHARR_Topic', message, AWS_REGION) except Exception as e: logger.error(e) logger.error('Unable to send to sns')