def test_single_event_good(mocker): # Read test data event = utils.load_test_data(test_data + 'CIS_1-6-single-select.json', my_region) 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.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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) # create client directly through boto3 and stub it iamc = boto3.client('iam') iamc_s = Stubber(iamc) iamc_s.add_response('update_account_password_policy', {}) iamc_s.activate() mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=iamc) mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) cis15111.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Set IAM Password Policy" remediation started') resolve.assert_called_once_with( 'RESOLVED: "Set IAM Password Policy" remediation was successful')
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 test_handler(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis24.json', my_region) 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.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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) remediate = mocker.patch('cis24.remediate', return_value=None) mocker.patch('lib.applogger.LogHandler.flush', return_value=None) cis24.lambda_handler(event, None) remediate.assert_called_once()
def test_event_bad(mocker): # Read test data event = utils.load_test_data(test_data + 'cis_1-3.json', my_region) iam_keys = { "AccessKeyMetadata": [ { "UserName": "******", "AccessKeyId": "AKIAADFHWEREFGFHSDDF", "Status": "Active", "CreateDate": "2015-05-22T14:43:16+00:00" }, { "UserName": "******", "AccessKeyId": "AKIAGHJGJFGHJFGETHFG", "Status": "Active", "CreateDate": "2020-05-15T15:20:04+00:00" } ] } # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) # create client and resource directly through boto3 iamc = boto3.client('iam', region_name=my_region) iamr = boto3.resource('iam', region_name=my_region) # stub the client iamc_s = Stubber(iamc) iamr_s = Stubber(iamr.meta.client) iamc_s.add_response( 'list_access_keys', iam_keys ) iam_keys['AccessKeyMetadata'][0]['Status'] = 'Inactive' iamc_s.add_response( 'list_access_keys', iam_keys ) iamc_s.activate() iamr_s.activate() # Mock the client and resource to return the clients we created mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=iamc) mocker.patch('lib.awsapi_helpers.BotoSession.resource', return_value=iamr) mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock flush so we don't mocker.patch('lib.applogger.LogHandler.flush', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') update = mocker.patch('lib.sechub_findings.Finding.update_text') cis1314.lambda_handler(event, None) init.assert_called_with( 'INITIAL: "Deactivate unused keys over 90 days old" remediation started' ) update.assert_called_once_with( 'FAILED: "Deactivate unused keys over 90 days old" remediation failed. Please remediate manually' )
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis29.json', my_region) sns_message = { 'Note': '"Enable VPC flow logging in all VPCs" remediation was successful', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Enable VPC flow logging in all VPCs', 'AffectedObject': 'VPC Flow Logs for VPC: vpc-d1a07fba', 'metrics_data': mocker.ANY } os.environ['AWS_SESSION_TOKEN'] = 'FAKETOKEN' os.environ['FLOW_LOG_ROLE_ARN'] = 'FAKELOGROLEARN' post_metrics_expected_parms = { '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/2.9', 'type': '2.9 Ensure VPC flow logging is enabled in all VPCs', 'productArn': mocker.ANY, 'finding_triggered_by': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'RESOLVED' }, 'Version': 'v1.2.0TEST' } 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.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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) awsc = [boto3.client('logs'), boto3.client('ec2')] def mock_select(thing1, thing2): if thing2 == 'logs': return awsc[0] else: return awsc[1] # Mock the boto clients and replace the BotoSession client with our stub awsc_s = Stubber(awsc[0]) awsc_s.add_response('create_log_group', {}) awsc_s.activate() aws2c_s = Stubber(awsc[1]) aws2c_s.add_response('create_flow_logs', {}) aws2c_s.add_response('describe_flow_logs', {'FlowLogs': [{ 'FlowLogStatus': 'ACTIVE' }]}) aws2c_s.activate() sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # redirect to mock_select above to return the proper stub mocker.patch('lib.awsapi_helpers.BotoSession.client', new=mock_select) # Mock notifications init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis29.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Enable VPC flow logging in all VPCs" remediation started') resolve.assert_called_once_with( 'RESOLVED: "Enable VPC flow logging in all VPCs" remediation was successful' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region) post_metrics.assert_called_with(post_metrics_expected_parms)
def test_not_remediated(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis29.json', my_region) post_metrics_expected_parms = { '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/2.9', 'type': '2.9 Ensure VPC flow logging is enabled in all VPCs', 'productArn': mocker.ANY, 'finding_triggered_by': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'FAILED' }, 'Version': 'v1.2.0TEST' } os.environ['AWS_SESSION_TOKEN'] = 'FAKETOKEN' os.environ['FLOW_LOG_ROLE_ARN'] = 'FAKELOGROLEARN' 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.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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) awsc = [boto3.client('logs'), boto3.client('ec2')] def mock_select(thing1, thing2): if thing2 == 'logs': return awsc[0] else: return awsc[1] awsc_s = Stubber(awsc[0]) awsc_s.add_response('create_log_group', {}) awsc_s.activate() aws2c_s = Stubber(awsc[1]) aws2c_s.add_response('create_flow_logs', {}) aws2c_s.add_response('describe_flow_logs', {'FlowLogs': []}) aws2c_s.activate() # redirect to mock_select above to return the proper stub mocker.patch('lib.awsapi_helpers.BotoSession.client', new=mock_select) # Mock notifications init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') update = mocker.patch('lib.sechub_findings.Finding.update_text') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis29.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Enable VPC flow logging in all VPCs" remediation started') update.assert_called_once_with( 'FAILED: "Enable VPC flow logging in all VPCs" remediation failed. Please remediate manually', status='FAILED') resolve.assert_not_called() post_metrics.assert_called_with(post_metrics_expected_parms)
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis43.json', my_region) sns_message = { 'Note': '"Remove all rules from the default security group" remediation was successful', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Remove all rules from the default security group', 'AffectedObject': 'Security Group: sg-02cfbecbc814a3c24', 'metrics_data': mocker.ANY } desc_sg = { "SecurityGroups": [{ "Description": "Default SG", "GroupName": "SC-111111111111-pp-gz465ubujkfrs-SandboxSecurityGroup-175ZDF23V5MGX", "IpPermissions": [{ "FromPort": 80, "IpProtocol": "tcp", "IpRanges": [{ "CidrIp": "0.0.0.0/0" }], "Ipv6Ranges": [], "PrefixListIds": [], "ToPort": 80, "UserIdGroupPairs": [] }, { "FromPort": 9000, "IpProtocol": "tcp", "IpRanges": [{ "CidrIp": "72.21.198.65/32" }], "Ipv6Ranges": [], "PrefixListIds": [], "ToPort": 9000, "UserIdGroupPairs": [] }, { "FromPort": 22, "IpProtocol": "tcp", "IpRanges": [{ "CidrIp": "0.0.0.0/0" }], "Ipv6Ranges": [], "PrefixListIds": [], "ToPort": 22, "UserIdGroupPairs": [] }], "OwnerId": "123412341234", "GroupId": "sg-006bf520b9581b2d9", "IpPermissionsEgress": [{ "IpProtocol": "-1", "IpRanges": [{ "CidrIp": "0.0.0.0/0" }], "Ipv6Ranges": [], "PrefixListIds": [], "UserIdGroupPairs": [] }], "Tags": [], "VpcId": "vpc-11111113" }] } post_metrics_expected_parms = { '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/4.3', 'type': '4.3 Ensure the default security group of every VPC restricts all traffic', 'productArn': mocker.ANY, 'finding_triggered_by': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'RESOLVED' }, 'Version': 'v1.2.0TEST' } 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.add_response('get_parameter', mock_ssm_get_parameter_uuid) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_version) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_uuid) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_version) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_uuid) ssmc_s.activate() mocker.patch('lib.metrics.Metrics.connect_to_ssm', return_value=ssmc) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) # Mock the boto client and replace the BotoSession client with our stub awsc = boto3.resource('ec2') awsc_s = Stubber(awsc.meta.client) awsc_s.add_response('describe_security_groups', desc_sg) awsc_s.add_response('revoke_security_group_ingress', {}) awsc_s.add_response('revoke_security_group_egress', {}) awsc_s.activate() mocker.patch('lib.awsapi_helpers.BotoSession.resource', return_value=awsc) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') # Prevent flushing to logs mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis43.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Remove all rules from the default security group" remediation started' ) resolve.assert_called_once_with( 'RESOLVED: "Remove all rules from the default security group" remediation was successful' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region) post_metrics.assert_called_with(post_metrics_expected_parms)
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis26.json', my_region) sns_message = { 'Note': '"Enable Access Logging on CloudTrail logs bucket" remediation was successfully invoked via AWS Systems Manager', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Enable Access Logging on CloudTrail logs bucket', 'AffectedObject': 'CloudTrail: cloudtrail-awslogs-111111111111-cv5ddz5l-isengard-do-not-delete', 'metrics_data': mocker.ANY } post_metrics_expected_parms = { '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/2.6', 'type': '2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket', 'productArn': mocker.ANY, 'finding_triggered_by': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'RESOLVED' }, 'Version': 'v1.2.0TEST' } 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.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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) awsc = [boto3.client('ssm'), boto3.client('s3')] def mock_select(thing1, thing2): if thing2 == 'ssm': return awsc[0] elif thing2 == 's3': return awsc[1] else: return # Mock the boto client and replace the BotoSession client with our stub awsc_s = Stubber(awsc[0]) awsc_s.add_response('start_automation_execution', {}) awsc_s.activate() awss3_s = Stubber(awsc[1]) awss3_s.add_response('create_bucket', {}) awss3_s.add_response('put_bucket_encryption', {}) awss3_s.activate() mocker.patch('lib.awsapi_helpers.BotoSession.client', new=mock_select) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') # Prevent flushing to logs mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis26.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Enable Access Logging on CloudTrail logs bucket" remediation started' ) resolve.assert_called_once_with( 'RESOLVED: "Enable Access Logging on CloudTrail logs bucket" remediation was successfully invoked via AWS Systems Manager' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region) post_metrics.assert_called_with(post_metrics_expected_parms)
def test_event_bad(mocker): # Read test data event = utils.load_test_data(test_data + 'cis_1-3.json', my_region) iam_keys = { "AccessKeyMetadata": [{ "UserName": "******", "AccessKeyId": "AKIAADFHWEREFGFHSDDF", "Status": "Active", "CreateDate": "2015-05-22T14:43:16+00:00" }, { "UserName": "******", "AccessKeyId": "AKIAGHJGJFGHJFGETHFG", "Status": "Active", "CreateDate": "2020-05-15T15:20:04+00:00" }] } post_metrics_expected_parms = { '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': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'FAILED' }, 'Version': 'v1.2.0TEST' } 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.add_response('get_parameter', mock_ssm_get_parameter_uuid) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_version) 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) # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) # create client and resource directly through boto3 iamc = boto3.client('iam', region_name=my_region) iamr = boto3.resource('iam', region_name=my_region) # stub the client iamc_s = Stubber(iamc) iamr_s = Stubber(iamr.meta.client) iamc_s.add_response('list_access_keys', iam_keys) iamc_s.add_response('update_access_key', {}) iam_keys['AccessKeyMetadata'][0]['Status'] = 'Inactive' iamc_s.add_response('list_access_keys', iam_keys) iamc_s.add_response('update_access_key', {}) # iam_keys['AccessKeyMetadata'][0]['Status'] = 'Inactive' iamc_s.add_response('list_access_keys', iam_keys) iamc_s.activate() iamr_s.activate() # Mock the client and resource to return the clients we created mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=iamc) mocker.patch('lib.awsapi_helpers.BotoSession.resource', return_value=iamr) mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock flush so we don't mocker.patch('lib.applogger.LogHandler.flush', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') update = mocker.patch('lib.sechub_findings.Finding.update_text') cis1314.lambda_handler(event, None) init.assert_called_with( 'INITIAL: "Deactivate unused keys over 90 days old" remediation started' ) update.assert_called_once_with( 'FAILED: "Deactivate unused keys over 90 days old" remediation failed. Please remediate manually', status='FAILED') post_metrics.assert_called_with(post_metrics_expected_parms)
def test_multi_event_good(mocker): # Read test data event = utils.load_test_data(test_data + 'CIS_1-6-multi-select.json', my_region) sns_message = { 'Note': '"Set IAM Password Policy" remediation was successful', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Set IAM Password Policy', 'AffectedObject': 'IAM Password Policy', 'metrics_data': mocker.ANY } post_metrics_expected_parms = { '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.6', 'type': '1.6 Ensure IAM password policy requires at least one lowercase letter', 'productArn': mocker.ANY, 'finding_triggered_by': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'RESOLVED' }, 'Version': 'v1.2.0TEST' } 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.add_response('get_parameter', mock_ssm_get_parameter_uuid) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_version) 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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) # create client directly through boto3 and stub it iamc = boto3.client('iam') iamc_s = Stubber(iamc) # set up responses for the lambda. One for each call. # We expect 2 - one for each finding in this test data iamc_s.add_response('update_account_password_policy', {}) iamc_s.add_response('update_account_password_policy', {}) # Activate the stubber iamc_s.activate() # mock methods that we don't want to go through mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=iamc) # Mock Notifier's call to resolve so we can examine the parameters init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit') # Mock flush so it doesn't execute mocker.patch('lib.applogger.LogHandler.flush', return_value=None) cis15111.lambda_handler(event, None) init.assert_called_with( 'INITIAL: "Set IAM Password Policy" remediation started') resolve.assert_called_with( 'RESOLVED: "Set IAM Password Policy" remediation was successful') sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region) post_metrics.assert_called_with(post_metrics_expected_parms)
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis29.json', my_region) sns_message = { 'Note': '"Enable VPC flow logging in all VPCs" remediation was successful', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Enable VPC flow logging in all VPCs', 'AffectedObject': 'VPC Flow Logs for VPC: vpc-d1a07fba', 'metrics_data': {'status': 'RESOLVED'} } os.environ['AWS_SESSION_TOKEN'] = 'FAKETOKEN' os.environ['FLOW_LOG_ROLE_ARN'] = 'FAKELOGROLEARN' #-------------------------- # Mock/stub # # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) awsc = [ boto3.client('logs'), boto3.client('ec2') ] def mock_select(thing1, thing2): if thing2 == 'logs': return awsc[0] else: return awsc[1] # Mock the boto clients and replace the BotoSession client with our stub awsc_s = Stubber(awsc[0]) awsc_s.add_response( 'create_log_group', {} ) awsc_s.activate() aws2c_s = Stubber(awsc[1]) aws2c_s.add_response( 'create_flow_logs', {} ) aws2c_s.add_response( 'describe_flow_logs', { 'FlowLogs': [ { 'FlowLogStatus': 'ACTIVE' } ] } ) aws2c_s.activate() sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # redirect to mock_select above to return the proper stub mocker.patch('lib.awsapi_helpers.BotoSession.client', new=mock_select) # Mock notifications init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis29.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Enable VPC flow logging in all VPCs" remediation started' ) resolve.assert_called_once_with( 'RESOLVED: "Enable VPC flow logging in all VPCs" remediation was successful' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region)
def test_not_remediated(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis29.json', my_region) os.environ['AWS_SESSION_TOKEN'] = 'FAKETOKEN' os.environ['FLOW_LOG_ROLE_ARN'] = 'FAKELOGROLEARN' #-------------------------- # Mock/stub # # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) awsc = [ boto3.client('logs'), boto3.client('ec2') ] def mock_select(thing1, thing2): if thing2 == 'logs': return awsc[0] else: return awsc[1] awsc_s = Stubber(awsc[0]) awsc_s.add_response( 'create_log_group', {} ) awsc_s.activate() aws2c_s = Stubber(awsc[1]) aws2c_s.add_response( 'create_flow_logs', {} ) aws2c_s.add_response( 'describe_flow_logs', { 'FlowLogs': [ ] } ) aws2c_s.activate() # redirect to mock_select above to return the proper stub mocker.patch('lib.awsapi_helpers.BotoSession.client', new=mock_select) # Mock notifications init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') update = mocker.patch('lib.sechub_findings.Finding.update_text') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis29.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Enable VPC flow logging in all VPCs" remediation started' ) update.assert_called_once_with( 'FAILED: "Enable VPC flow logging in all VPCs" remediation failed. Please remediate manually' ) resolve.assert_not_called()
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis23.json', my_region) sns_message = { 'Note': '"Disable S3 public access" remediation was successfully completed', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Disable S3 public access', 'AffectedObject': 'S3 Bucket: cloudtrail-awslogs-111111111111-kjfskljdfl', 'metrics_data': mocker.ANY } #-------------------------- # Mock/stub # ssm_uuid = { "Parameter": { "Name": "/Solutions/SO0111/anonymous_metrics_uuid", "Type": "String", "Value": "12345678-1234-1234-1234-123412341234", "Version": 1, "LastModifiedDate": "2021-02-25T12:58:50.591000-05:00", "ARN": "arn:aws:ssm:us-east-1:1111111111111111:parameter/Solutions/SO0111/anonymous_metrics_uuid", "DataType": "text" } } post_metrics_expected_parms = { '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/2.3', 'type': '2.3 Ensure the S3 bucket used to store CloudTrail logs is not publicly accessible', 'productArn': mocker.ANY, 'finding_triggered_by': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'RESOLVED' }, 'Version': 'v1.2.0TEST' } 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.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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) # Mock the boto client and replace the BotoSession client with our stub awsc = boto3.client('s3') awsc_s = Stubber(awsc) awsc_s.add_response('put_public_access_block', {}) awsc_s.activate() mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=awsc) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') # Prevent flushing to logs mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis23.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Disable S3 public access" remediation started') resolve.assert_called_once_with( 'RESOLVED: "Disable S3 public access" remediation was successfully completed' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region) post_metrics.assert_called_with(post_metrics_expected_parms)
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis26.json', my_region) sns_message = { 'Note': '"Enable Access Logging on CloudTrail logs bucket" remediation was successfully invoked via AWS Systems Manager', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Enable Access Logging on CloudTrail logs bucket', 'AffectedObject': 'CloudTrail: cloudtrail-awslogs-111111111111-cv5ddz5l-isengard-do-not-delete', 'metrics_data': { 'status': 'RESOLVED' } } #-------------------------- # Mock/stub # mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) awsc = [boto3.client('ssm'), boto3.client('s3')] def mock_select(thing1, thing2): if thing2 == 'ssm': return awsc[0] elif thing2 == 's3': return awsc[1] else: return # Mock the boto client and replace the BotoSession client with our stub awsc_s = Stubber(awsc[0]) awsc_s.add_response('start_automation_execution', {}) awsc_s.activate() awss3_s = Stubber(awsc[1]) awss3_s.add_response('create_bucket', {}) awss3_s.add_response('put_bucket_encryption', {}) awss3_s.activate() mocker.patch('lib.awsapi_helpers.BotoSession.client', new=mock_select) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') # Prevent flushing to logs mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis26.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Enable Access Logging on CloudTrail logs bucket" remediation started' ) resolve.assert_called_once_with( 'RESOLVED: "Enable Access Logging on CloudTrail logs bucket" remediation was successfully invoked via AWS Systems Manager' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region)
def test_event_good(mocker): # Read test data event = utils.load_test_data(test_data + 'cis_1-3-iamuser1.json', my_region) sns_message = { 'Note': 'Access key over 90 days old found: AKIAGHJGJFGHJFGETHFG', 'State': 'INFO', 'Account': '111111111111', 'Remediation': 'Deactivate unused keys over 90 days old', 'metrics_data': mocker.ANY, 'AffectedObject': 'Access Key: AKIAGHJGJFGHJFGETHFG' } iam_keys = { "AccessKeyMetadata": [{ "UserName": "******", "AccessKeyId": "AKIAADFHWEREFGFHSDDF", "Status": "Active", "CreateDate": "2015-05-22T14:43:16+00:00" }, { "UserName": "******", "AccessKeyId": "AKIAGHJGJFGHJFGETHFG", "Status": "Active", "CreateDate": "2020-05-15T15:20:04+00:00" }] } post_metrics_expected_parms = { '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': 'Security Hub Findings - Custom Action', 'region': mocker.ANY, 'status': 'RESOLVED' }, 'Version': 'v1.2.0TEST' } 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.add_response('get_parameter', mock_ssm_get_parameter_uuid) ssmc_s.add_response('get_parameter', mock_ssm_get_parameter_version) 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) # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) # sess = BotoSession() iamc = boto3.client('iam', region_name=my_region) iamr = boto3.resource('iam', region_name=my_region) iamc_s = Stubber(iamc) iamr_s = Stubber(iamr.meta.client) iamc_s.add_response('list_access_keys', iam_keys) iamr_s.add_response('update_access_key', {}) iam_keys['AccessKeyMetadata'][0]['Status'] = 'Inactive' iamc_s.add_response('list_access_keys', iam_keys) iamr_s.add_response('update_access_key', {}) iam_keys['AccessKeyMetadata'][0]['Status'] = 'Inactive' iamc_s.add_response('list_access_keys', iam_keys) iamc_s.activate() iamr_s.activate() # Replace BotoSession client/resource with our stub mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=iamc) mocker.patch('lib.awsapi_helpers.BotoSession.resource', return_value=iamr) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier resolve = mocker.patch('lib.sechub_findings.Finding.resolve') flag = mocker.patch('lib.sechub_findings.Finding.flag') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) cis1314.lambda_handler(event, None) flag.assert_called_once_with( 'INITIAL: "Deactivate unused keys over 90 days old" remediation started' ) resolve.assert_called_once_with( 'RESOLVED: Remediation completed successfully, create new access keys using IAM console.' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region) post_metrics.assert_called_with(post_metrics_expected_parms)
def test_event_good(mocker): # Read test data event = utils.load_test_data(test_data + 'cis_1-3-iamuser1.json', my_region) sns_message = { 'Note': 'Access key over 90 days old found: AKIAGHJGJFGHJFGETHFG', 'State': 'INFO', 'Account': '111111111111', 'Remediation': 'Deactivate unused keys over 90 days old', 'AffectedObject': 'Access Key: AKIAGHJGJFGHJFGETHFG', 'metrics_data': {'status': 'INFO'}, } iam_keys = { "AccessKeyMetadata": [ { "UserName": "******", "AccessKeyId": "AKIAADFHWEREFGFHSDDF", "Status": "Active", "CreateDate": "2015-05-22T14:43:16+00:00" }, { "UserName": "******", "AccessKeyId": "AKIAGHJGJFGHJFGETHFG", "Status": "Active", "CreateDate": "2020-05-15T15:20:04+00:00" } ] } # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) # sess = BotoSession() iamc = boto3.client('iam', region_name=my_region) iamr = boto3.resource('iam', region_name=my_region) iamc_s = Stubber(iamc) iamr_s = Stubber(iamr.meta.client) iamc_s.add_response( 'list_access_keys', iam_keys ) iamr_s.add_response( 'update_access_key', {} ) iam_keys['AccessKeyMetadata'][0]['Status'] = 'Inactive' iamc_s.add_response( 'list_access_keys', iam_keys ) iamr_s.add_response( 'update_access_key', {} ) iam_keys['AccessKeyMetadata'][0]['Status'] = 'Inactive' iamc_s.add_response( 'list_access_keys', iam_keys ) iamc_s.activate() iamr_s.activate() # Replace BotoSession client/resource with our stub mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=iamc) mocker.patch('lib.awsapi_helpers.BotoSession.resource', return_value=iamr) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier resolve = mocker.patch('lib.sechub_findings.Finding.resolve') flag = mocker.patch('lib.sechub_findings.Finding.flag') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) cis1314.lambda_handler(event, None) flag.assert_called_once_with( 'INITIAL: "Deactivate unused keys over 90 days old" remediation started' ) resolve.assert_called_once_with( 'RESOLVED: Remediation completed successfully, create new access keys using IAM console.' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region)
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis43.json', my_region) sns_message = { 'Note': '"Remove all rules from the default security group" remediation was successful', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Remove all rules from the default security group', 'AffectedObject': 'Security Group: sg-02cfbecbc814a3c24', 'metrics_data': { 'status': 'RESOLVED' } } desc_sg = { "SecurityGroups": [{ "Description": "Default SG", "GroupName": "SC-111111111111-pp-gz465ubujkfrs-SandboxSecurityGroup-175ZDF23V5MGX", "IpPermissions": [{ "FromPort": 80, "IpProtocol": "tcp", "IpRanges": [{ "CidrIp": "0.0.0.0/0" }], "Ipv6Ranges": [], "PrefixListIds": [], "ToPort": 80, "UserIdGroupPairs": [] }, { "FromPort": 9000, "IpProtocol": "tcp", "IpRanges": [{ "CidrIp": "72.21.198.65/32" }], "Ipv6Ranges": [], "PrefixListIds": [], "ToPort": 9000, "UserIdGroupPairs": [] }, { "FromPort": 22, "IpProtocol": "tcp", "IpRanges": [{ "CidrIp": "0.0.0.0/0" }], "Ipv6Ranges": [], "PrefixListIds": [], "ToPort": 22, "UserIdGroupPairs": [] }], "OwnerId": "123412341234", "GroupId": "sg-006bf520b9581b2d9", "IpPermissionsEgress": [{ "IpProtocol": "-1", "IpRanges": [{ "CidrIp": "0.0.0.0/0" }], "Ipv6Ranges": [], "PrefixListIds": [], "UserIdGroupPairs": [] }], "Tags": [], "VpcId": "vpc-11111113" }] } #-------------------------- # Mock/stub # mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) # Mock the boto client and replace the BotoSession client with our stub awsc = boto3.resource('ec2') awsc_s = Stubber(awsc.meta.client) awsc_s.add_response('describe_security_groups', desc_sg) awsc_s.add_response('revoke_security_group_ingress', {}) awsc_s.add_response('revoke_security_group_egress', {}) awsc_s.activate() mocker.patch('lib.awsapi_helpers.BotoSession.resource', return_value=awsc) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') # Prevent flushing to logs mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis43.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Remove all rules from the default security group" remediation started' ) resolve.assert_called_once_with( 'RESOLVED: "Remove all rules from the default security group" remediation was successful' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region)
def test_event_good(mocker): #-------------------------- # Test data # event = utils.load_test_data(test_data + 'cis22.json', my_region) sns_message = { 'Note': '"Enable CloudTrail log file validation" remediation was successful', 'State': 'RESOLVED', 'Account': '111111111111', 'Remediation': 'Enable CloudTrail log file validation', 'AffectedObject': 'CloudTrail: ExampleTrail', 'metrics_data': mocker.ANY } post_metrics_expected_parms = { "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/2.2", "type": "2.2 Ensure CloudTrail log file validation is enabled", "productArn": mocker.ANY, "finding_triggered_by": "Security Hub Findings - Custom Action", "region": mocker.ANY, "status": "RESOLVED" }, "Version": "v1.2.0TEST" } 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.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) post_metrics = mocker.patch('lib.metrics.Metrics.post_metrics_to_api', return_value=None) # Mock the constructor. We don't need the session created mocker.patch('lib.awsapi_helpers.BotoSession.__init__', return_value=None) mocker.patch('lib.awsapi_helpers.AWSClient.connect', return_value=None) # Mock the boto client and replace the BotoSession client with our stub awsc = boto3.client('cloudtrail') awsc_s = Stubber(awsc) awsc_s.add_response('update_trail', {}) awsc_s.activate() mocker.patch('lib.awsapi_helpers.BotoSession.client', return_value=awsc) sns = mocker.patch('lib.awsapi_helpers.AWSClient.postit', return_value=None) # Mock Notifier init = mocker.patch('lib.sechub_findings.Finding.flag') resolve = mocker.patch('lib.sechub_findings.Finding.resolve') mocker.patch('lib.applogger.LogHandler.flush', return_value=None) #-------------------------- # Run the lambda # cis22.lambda_handler(event, None) init.assert_called_once_with( 'INITIAL: "Enable CloudTrail log file validation" remediation started') resolve.assert_called_once_with( 'RESOLVED: "Enable CloudTrail log file validation" remediation was successful' ) sns.assert_called_with('SO0111-SHARR_Topic', sns_message, my_region) post_metrics.assert_called_with(post_metrics_expected_parms)