def resources_from_two_regions() -> List[Resource]: yield [ Resource( "arn:aws:ec2:eu-central-1:111111111111:subnet/subnet-57ce0008", "subnet-57ce0008", "subnet", [], ), Resource( "arn:aws:ec2:eu-central-1:111111111111:subnet/subnet-57ce0009", "subnet-57ce0009", "subnet", [], ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d0", "sg-b501f6d0", "security-group", [], ), Resource( "arn:aws:ec2:eu-west-1:111111111111:network-acl/acl-abc", "acl-abc", "network-acl", [], ), Resource( "arn:aws:ec2:eu-west-1:111111111111:security-group/sg-b501f6d1", "sg-b501f6d1", "security-group", [], ), ]
def iam_roles() -> List[Resource]: yield [ Resource("arn:aws:iam::111111111111:role/some-role", "some-role", "role", []), Resource( "arn:aws:iam::111111111111:role/another-role", "another-role", "role", [] ), ]
def iam_user() -> List[Resource]: yield [ Resource("arn:aws:iam::111111111111:user/some-user", "some-user", "user", []), Resource( "arn:aws:iam::111111111111:user/another-user", "another-user", "user", [] ), ]
def test_global_scanner_with_config_set(self, mocker, account_and_profile_configured, global_scan): skew_scan = mocker.patch.object(scanner.global_scanner.skew, "scan") skew.scan.side_effect = global_scan actual = GlobalScanner().scan(GLOBAL_RES_TYPE_NOT_TAGGABLE) assert len(actual) == 3 assert (Resource( "arn:aws:cloudfront::111111111111:distribution/EMS6KR7IENMDE", "EMS6KR7IENMDE", "distribution", [], ) in actual) assert (Resource( "arn:aws:route53::111111111111:healthcheck/f665452c-bf56-4a43-8b5d-319c3b8d0a70", "f665452c-bf56-4a43-8b5d-319c3b8d0a70", "healthcheck", [], ) in actual) assert (Resource( "arn:aws:iam::111111111111:role/some-role", "some-role", "role", [], name="some-role", ) in actual) assert skew_scan.call_count == len(GLOBAL_SERVICES)
def test_report_command(self, mocker, tmpdir): expected_file_name = "report.html" expected_output_path = str(tmpdir) + "/" + expected_file_name resources_with_tag_diffs = [ ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags, ), diff_for_improperly_tagged_resource, ), ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq2", "someq2", "queue", [Tag("Project", "Super1")], ), diff_for_properly_tagged_resource, ), ResourceWithTagDiffs( Resource( "arn:aws:apigateway:eu-central-1::/apis/e5zcg2s231", "e5zcg2s231", "apigateway", tags, ), diff_for_properly_tagged_resource, ), ] some_config = Config([Tag("Owner", "Fritz"), Tag("Project", "CRM")], default_region="eu-west-1") mocker.patch( "taggercli.commands.report.scan_and_compare_resources", return_value=resources_with_tag_diffs, ) mocker.patch("taggercli.commands.report.init_config") mocker.patch("taggercli.commands.report.get_config", return_value=some_config) runner = CliRunner() actual = runner.invoke( cli, [ "report", "create", "--region", "eu-central-1", "--output-path", tmpdir ], ) assert not actual.exception assert actual.exit_code == 0 with open(expected_output_path, "r") as generated_report: assert generated_report.read()
def test_tag_all_with_detailed_list(self, mocker): scanned_resources = { "eu-central-1": [ Resource( "arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags, ), Resource( "arn:aws:sqs:eu-central-1:111111111111:someq2", "someq2", "queue", tags, ), ], "global": [ Resource( "arn:aws:cloudfront::111111111111:distribution/EMS6KR7IENMDE", "EMS6KR7IENMDE", "distribution", tags, ), Resource( "arn:aws:route53::111111111111:healthcheck/f665452c-bf56-4a43-8b5d-319c3b8d0a70", "f665452c-bf56-4a43-8b5d-319c3b8d0a70", "healthcheck", tags, ), ], } some_config = Config( [Tag("Owner", "Fritz"), Tag("Project", "CRM")], default_region="eu-central-1", ) runner = CliRunner() scan_mock = mocker.patch( "taggercli.commands.tag.scan_region_and_global", return_value=scanned_resources, ) mocker.patch("taggercli.commands.tag.init_config") mocker.patch("taggercli.commands.tag.get_config", return_value=some_config) actual = runner.invoke(cli, ["tag", "all"], input="y\n n\n") assert not actual.exception assert actual.exit_code == 0 assert actual.stdout.find("Scanning completed") assert actual.stdout.find( f"Found {len(scanned_resources['global'])} global resources") assert actual.stdout.find( f"Found {len(scanned_resources['eu-central-1'])} resources in region eu-central-1" ) scan_mock.assert_called_once_with("eu-central-1")
def regional_resources(tags) -> List[Resource]: yield [ Resource("arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags), Resource( "arn:aws:sqs:eu-central-1:111111111111:someq2", "someq2", "queue", tags ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d0", "sg-b501f6d0", "security-group", tags, ), ]
def test_metrics_for_dashboard(self): resources_by_service = { "sqs": [ ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags, ), diff_for_improperly_tagged_resource, ), ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq2", "someq2", "queue", [Tag("Project", "Super1")], ), diff_for_properly_tagged_resource, ), ], "apigateway": [ ResourceWithTagDiffs( Resource( "arn:aws:apigateway:eu-central-1::/apis/e5zcg2s231", "e5zcg2s231", "apigateway", tags, ), diff_for_properly_tagged_resource, ) ], } actual = metrics_for_dashboard_by_service(resources_by_service) assert actual == { "sqs": { "number_of_resources": 2, "number_of_resources_tagged_properly": 1, "ratio_tagged_properly": 0.5, }, "apigateway": { "number_of_resources": 1, "number_of_resources_tagged_properly": 1, "ratio_tagged_properly": 1, }, }
def global_resources(tags) -> List[Resource]: yield [ Resource( "arn:aws:cloudfront::111111111111:distribution/EMS6KR7IENMDE", "EMS6KR7IENMDE", "distribution", tags, ), Resource( "arn:aws:route53::111111111111:healthcheck/f665452c-bf56-4a43-8b5d-319c3b8d0a70", "f665452c-bf56-4a43-8b5d-319c3b8d0a70", "healthcheck", tags, ), ]
def test_resource_is_tagged_properly(self): resource_properly_tagged = ResourceWithTagDiffs( Resource("arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags), diff_for_properly_tagged_resource, ) assert resource_properly_tagged.properly_tagged is True
def create_resource(resource: Any) -> Resource: """Map a skew resource to a taggercore resource""" return Resource( arn=resource.arn, id=resource.id, resource_type=resource.resourcetype, current_tags=[Tag(key, value) for key, value in resource.tags.items()], name=resource.name, )
def test_resource_properties(self): resource = ResourceWithTagDiffs( Resource("arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags), diff_for_properly_tagged_resource, ) assert resource.region == "eu-central-1" assert resource.type == "queue" assert resource.service == "sqs" assert resource.arn == "arn:aws:sqs:eu-central-1:111111111111:someq"
def test_scan(self, mocker, account_and_profile_configured, region_scan): skew.set_config( {"accounts": { "111111111111": { "profile": "profile-1" } }}) number_of_supported_services = len( skew.ARN().service.choices()) - len(GLOBAL_SERVICES) skew_scan = mocker.patch.object(scanner.region_scanner.skew, "scan") skew.scan.side_effect = region_scan actual = RegionScanner("eu-central-1").scan( REG_RES_TYPE_NOT_SUPPORTED + REG_RES_TYPE_NOT_TAGGABLE) # cloudformation stack is in REG_RES_TYPE_NOT_SUPPORTED therefore length should only be 1 assert len(actual) == 1 assert actual[0] == Resource( "arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", []) assert skew_scan.call_count == number_of_supported_services
def manipulate_arn(resource: Resource) -> Resource: arn_manipulation = ( ArnManipulationStrategyFactory.manipulation_strategy_for_service( resource.service)) resource.arn = arn_manipulation.manipulate_arn(arn=resource.arn) return resource
def test_data_for_dashboard_template(self): creation_datetime = datetime(2020, 8, 7, 10, 5, 23, tzinfo=timezone.utc) resources_with_tag_diffs = [ ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags, ), diff_for_improperly_tagged_resource, ), ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq2", "someq2", "queue", [Tag("Project", "Super1")], ), diff_for_properly_tagged_resource, ), ResourceWithTagDiffs( Resource( "arn:aws:apigateway:eu-central-1::/apis/e5zcg2s231", "e5zcg2s231", "apigateway", tags, ), diff_for_properly_tagged_resource, ), ] actual = prepare_data_for_dashboard_template("111111111111", creation_datetime, resources_with_tag_diffs) assert actual == { "account_id": "111111111111", "creation_datetime": "Fri Aug 7 10:05:23 2020 (UTC)", "metrics_by_service": { "sqs": { "number_of_resources": 2, "number_of_resources_tagged_properly": 1, "ratio_tagged_properly": 0.5, }, "apigateway": { "number_of_resources": 1, "number_of_resources_tagged_properly": 1, "ratio_tagged_properly": 1, }, }, "resources_by_service": { "sqs": [ ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq", "someq", "queue", tags, ), diff_for_improperly_tagged_resource, ), ResourceWithTagDiffs( Resource( "arn:aws:sqs:eu-central-1:111111111111:someq2", "someq2", "queue", [Tag("Project", "Super1")], ), diff_for_properly_tagged_resource, ), ], "apigateway": [ ResourceWithTagDiffs( Resource( "arn:aws:apigateway:eu-central-1::/apis/e5zcg2s231", "e5zcg2s231", "apigateway", tags, ), diff_for_properly_tagged_resource, ) ], }, }
def too_many_resources_for_single_boto_call(tags) -> List[Resource]: yield [ Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d1", "sg-b501f6d1", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d2", "sg-b501f6d2", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d3", "sg-b501f6d3", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d4", "sg-b501f6d4", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d5", "sg-b501f6d5", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d6", "sg-b501f6d6", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d7", "sg-b501f6d7", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d8", "sg-b501f6d8", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d9", "sg-b501f6d9", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d10", "sg-b501f6d10", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d11", "sg-b501f6d11", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d12", "sg-b501f6d12", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d13", "sg-b501f6d13", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d14", "sg-b501f6d14", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d15", "sg-b501f6d15", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d16", "sg-b501f6d16", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d17", "sg-b501f6d17", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d18", "sg-b501f6d18", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d19", "sg-b501f6d19", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d20", "sg-b501f6d20", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d21", "sg-b501f6d21", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d22", "sg-b501f6d22", "security-group", tags, ), Resource( "arn:aws:ec2:eu-central-1:111111111111:security-group/sg-b501f6d23", "sg-b501f6d23", "security-group", tags, ), ]
def create_resource(resource: Any) -> Resource: """Map a skew resource to a taggercore resource""" # print(resource) # print(dir(resource)) # print(type(resource)) # print(f"name: {resource.name}") # print(f"id: {resource.id}") # print(f"arn: {resource.arn}") # print(inspect.getmro(type(resource))) try: tag_items = [Tag(key, value) for key, value in resource.tags.items()] except Exception as e: print('error encountered') print(f"arn: {resource.arn}") print(e) return None excluded_arns = [ ] excluded_roles = [ "CiscoBaselinePasswordPolicyRole", "CloudHealthIAMRole", "ContinuousSecurityBuddyLambdaRole", "CSIRT_Investigator_Role", "CustomStacksDeploymentRole", "engineer", "InfoSecAuditor", "network_api", "network_support", "OrganizationAccountAccessRole", "owner", "network_support", "SECOPS_Investigator_Role", "StreamlineIdPManagerIAMRole", ] excluded_tags = set([ Tag('ResourceOwner', 'CIE_SysEngComputeCore'), Tag('ApplicationName', 'Infosec Qualys'), Tag('ApplicationName', 'Rebox'), Tag('StreamlineAWSManaged', 'True') ]) if(resource.resourcetype == 'role' and resource.name in excluded_roles): print('EXCLUDED DUE TO MATCHING IAM ROLES') return None if(resource.arn in excluded_arns): print('EXCLUDED DUE TO MATCHING ARNS') return None if excluded_tags.intersection(tag_items): print('EXCLUDED DUE TO MATCHING TAGS') return None return Resource( arn=resource.arn, id=resource.id, resource_type=resource.resourcetype, current_tags=tag_items, name=resource.name, )