def test_disappearing_access_key_race_condition(self):
        account_id = "123456789012"
        user_name = "foo"
        region_name = "us-east-1"

        session = boto3.Session()
        client = session.client("iam")
        client.create_user(UserName=user_name)
        client.create_access_key(UserName=user_name)

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.iam.user.IAMUserResourceSpec.get_access_key_last_used"
        ) as mock_get_group_users:
            mock_get_group_users.side_effect = ClientError(
                operation_name="GetAccessKeyLastUsed",
                error_response={
                    "Error": {
                        "Code": "AccessDenied",
                        "Message": "",
                    }
                },
            )
            resources = IAMUserResourceSpec.scan(scan_accessor=scan_accessor)
            self.assertEqual(len(resources), 1)
            self.assertEqual(resources[0].resource_id,
                             "arn:aws:iam::123456789012:user/foo")
    def test_disappearing_policy_race_condition(self):
        account_id = "123456789012"
        policy_name = "foo"
        region_name = "us-east-1"

        session = boto3.Session()

        client = session.client("iam")

        policy_json = {
            "Version": "2012-10-17",
            "Statement": [{"Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "*"}],
        }
        policy_resp = client.create_policy(
            PolicyName=policy_name, PolicyDocument=json.dumps(policy_json),
        )
        policy_arn = policy_resp["Policy"]["Arn"]

        scan_accessor = AWSAccessor(session=session, account_id=account_id, region_name=region_name)
        with patch(
            "altimeter.aws.resource.iam.policy.IAMPolicyResourceSpec.get_policy_version_document_text"
        ) as mock_get_policy_version_document_text:
            mock_get_policy_version_document_text.side_effect = ClientError(
                operation_name="GetPolicyVersion",
                error_response={
                    "Error": {
                        "Code": "NoSuchEntity",
                        "Message": f"Policy {policy_arn} version v1 does not exist or is not attachable.",
                    }
                },
            )
            resources = IAMPolicyResourceSpec.scan(scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
    def test_disappearing_user_race_condition_get_user_mfa_devices(self):
        account_id = "123456789012"
        user_name = "foo"
        region_name = "us-east-1"

        session = boto3.Session()
        client = session.client("iam")
        client.create_user(UserName=user_name)

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.iam.user.IAMUserResourceSpec.get_user_mfa_devices"
        ) as mock_get_group_users:
            mock_get_group_users.side_effect = ClientError(
                operation_name="ListMFADevices",
                error_response={
                    "Error": {
                        "Code":
                        "NoSuchEntity",
                        "Message":
                        f"The user with name {user_name} cannot be found.",
                    }
                },
            )
            resources = IAMUserResourceSpec.scan(scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
    def test_disappearing_rule_race_condition(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        rule_name = "test_rule"

        session = boto3.Session()
        client = session.client("events", region_name=region_name)
        client.put_rule(
            Name=rule_name,
            Description="Capture all events and forward them to 012345678901",
            EventPattern=f"""{{"account":["012345678901"]}}""",
            State="ENABLED",
        )

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.events.cloudwatchevents_rule.list_targets_by_rule"
        ) as mock_list_targets_by_rule:
            mock_list_targets_by_rule.side_effect = ClientError(
                operation_name="ListTargetsByRule",
                error_response={
                    "Error": {
                        "Code":
                        "ResourceNotFoundException",
                        "Message":
                        f"Rule {rule_name} does not exist on EventBus default.",
                    }
                },
            )
            resources = EventsRuleResourceSpec.scan(
                scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
예제 #5
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()
        scan_accessor = AWSAccessor(session=session, account_id=account_id, region_name=region_name)
        resources = AccountResourceSpec.scan(scan_accessor=scan_accessor)

        expected_resources = [
            {
                "type": "aws:account",
                "links": [{"pred": "account_id", "obj": "123456789012", "type": "simple"}],
            }
        ]
        expected_api_call_stats = {
            "count": 1,
            "123456789012": {
                "count": 1,
                "us-east-1": {
                    "count": 1,
                    "sts": {"count": 1, "GetCallerIdentity": {"count": 1}},
                },
            },
        }
        self.assertListEqual([resource.to_dict() for resource in resources], expected_resources)
        self.assertDictEqual(scan_accessor.api_call_stats.to_dict(), expected_api_call_stats)
예제 #6
0
    def test_disappearing_role_race_condition(self):
        account_id = "123456789012"
        role_name = "foo"
        region_name = "us-east-1"

        session = boto3.Session()
        client = session.client("iam")
        client.create_role(RoleName=role_name, AssumeRolePolicyDocument="{}")

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch("altimeter.aws.resource.iam.role.get_attached_role_policies"
                   ) as mock_get_group_users:
            mock_get_group_users.side_effect = ClientError(
                operation_name="ListAttachedRolePolicies",
                error_response={
                    "Error": {
                        "Code":
                        "NoSuchEntity",
                        "Message":
                        f"The role with name {role_name} cannot be found.",
                    }
                },
            )
            resources = IAMRoleResourceSpec.scan(scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
    def test_disappearing_table_get_continuous_backup_table_data_race_condition(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        table_name = "foo"

        session = boto3.Session()
        client = session.client("dynamodb", region_name=region_name)

        client.create_table(
            AttributeDefinitions=[{"AttributeName": "string", "AttributeType": "S",},],
            KeySchema=[{"AttributeName": "string", "KeyType": "HASH",},],
            TableName=table_name,
        )

        scan_accessor = AWSAccessor(session=session, account_id=account_id, region_name=region_name)
        with patch(
            "altimeter.aws.resource.dynamodb.dynamodb_table.get_continuous_backup_table_data"
        ) as mock_get_continuous_backup_table_data:
            mock_get_continuous_backup_table_data.side_effect = ClientError(
                operation_name="DescribeContinuousBackups",
                error_response={
                    "Error": {
                        "Code": "TableNotFoundException",
                        "Message": f"Table not found: {table_name}",
                    }
                },
            )
            resources = DynamoDbTableResourceSpec.scan(scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
    def test_disappearing_target_group_race_condition(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        tg_name = "foo"

        session = boto3.Session()

        client = session.client("elbv2", region_name=region_name)

        resp = client.create_target_group(Name=tg_name, Port=443)
        tg_arn = resp["TargetGroups"][0]["TargetGroupArn"]

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.elbv2.target_group.get_target_group_health"
        ) as mock_get_target_group_health:
            mock_get_target_group_health.side_effect = ClientError(
                operation_name="DescribeTargetHealth",
                error_response={
                    "Error": {
                        "Code": "TargetGroupNotFound",
                        "Message": f"Target groups '{tg_arn}' not found",
                    }
                },
            )
            resources = TargetGroupResourceSpec.scan(
                scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
예제 #9
0
    def test_disappearing_saml_provider_race_condition(self):
        account_id = "123456789012"
        saml_provider_name = "foo"
        region_name = "us-east-1"

        session = boto3.Session()

        client = session.client("iam")

        saml_provider_resp = client.create_saml_provider(
            Name=saml_provider_name, SAMLMetadataDocument="a" * 1024)
        saml_provider_arn = saml_provider_resp["SAMLProviderArn"]

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.iam.iam_saml_provider.IAMSAMLProviderResourceSpec.get_saml_provider_metadata_doc"
        ) as mock_get_saml_provider_metadata_doc:
            mock_get_saml_provider_metadata_doc.side_effect = ClientError(
                operation_name="GetSAMLProvider",
                error_response={
                    "Error": {
                        "Code":
                        "NoSuchEntity",
                        "Message":
                        f"GetSAMLProvider operation: Manifest not found for arn {saml_provider_arn}",
                    }
                },
            )
            resources = IAMSAMLProviderResourceSpec.scan(
                scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
예제 #10
0
def scan_services(
    graph_name: str,
    graph_version: str,
    account_id: str,
    region: str,
    service: str,
    access_key: str,
    secret_key: str,
    token: str,
    resource_spec_classes: Tuple[Type[AWSResourceSpec], ...],
) -> Dict[str, Any]:
    logger = Logger()
    with logger.bind(region=region, service=service):
        logger.info(event=AWSLogEvents.ScanAWSAccountServiceStart)
        session = boto3.Session(
            aws_access_key_id=access_key,
            aws_secret_access_key=secret_key,
            aws_session_token=token,
            region_name=region,
        )
        aws_accessor = AWSAccessor(session=session,
                                   account_id=account_id,
                                   region_name=region)
        graph_spec = GraphSpec(
            name=graph_name,
            version=graph_version,
            resource_spec_classes=resource_spec_classes,
            scan_accessor=aws_accessor,
        )
        graph_set = graph_spec.scan()
        graph_set_dict = graph_set.to_dict()
        logger.info(event=AWSLogEvents.ScanAWSAccountServiceEnd)
        return graph_set_dict
예제 #11
0
    def test_detect_account_id_session_mismatch(self):
        account_id = "234567890121"
        region_name = "us-east-1"

        session = boto3.Session()
        scan_accessor = AWSAccessor(session=session, account_id=account_id, region_name=region_name)
        with self.assertRaises(ValueError):
            AccountResourceSpec.scan(scan_accessor=scan_accessor)
예제 #12
0
def scan_scan_unit(scan_unit: ScanUnit) -> Tuple[str, Dict[str, Any]]:
    logger = Logger()
    with logger.bind(
            account_id=scan_unit.account_id,
            region=scan_unit.region_name,
            service=scan_unit.service,
            resource_classes=sorted([
                resource_spec_class.__name__
                for resource_spec_class in scan_unit.resource_spec_classes
            ]),
    ):
        start_t = time.time()
        logger.info(event=AWSLogEvents.ScanAWSAccountServiceStart)
        session = boto3.Session(
            aws_access_key_id=scan_unit.access_key,
            aws_secret_access_key=scan_unit.secret_key,
            aws_session_token=scan_unit.token,
            region_name=scan_unit.region_name,
        )
        scan_accessor = AWSAccessor(session=session,
                                    account_id=scan_unit.account_id,
                                    region_name=scan_unit.region_name)
        graph_spec = GraphSpec(
            name=scan_unit.graph_name,
            version=scan_unit.graph_version,
            resource_spec_classes=scan_unit.resource_spec_classes,
            scan_accessor=scan_accessor,
        )
        start_time = int(time.time())
        resources: List[Resource] = []
        errors = []
        try:
            resources = graph_spec.scan()
        except Exception as ex:
            error_str = str(ex)
            trace_back = traceback.format_exc()
            logger.error(event=AWSLogEvents.ScanAWSAccountError,
                         error=error_str,
                         trace_back=trace_back)
            error = f"{str(ex)}\n{trace_back}"
            errors.append(error)
        end_time = int(time.time())
        graph_set = GraphSet(
            name=scan_unit.graph_name,
            version=scan_unit.graph_version,
            start_time=start_time,
            end_time=end_time,
            resources=resources,
            errors=errors,
            stats=scan_accessor.api_call_stats,
        )
        end_t = time.time()
        elapsed_sec = end_t - start_t
        logger.info(event=AWSLogEvents.ScanAWSAccountServiceEnd,
                    elapsed_sec=elapsed_sec)
        return (scan_unit.account_id, graph_set.to_dict())
예제 #13
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        session = boto3.Session()
        client = session.client("iam")

        oidc_url = "https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E"
        oidc_client_ids = ["sts.amazonaws.com"]
        oidc_thumbprints = ["9999999999999999999999999999999999999999"]

        _ = client.create_open_id_connect_provider(
            Url=oidc_url,
            ClientIDList=oidc_client_ids,
            ThumbprintList=oidc_thumbprints,
        )

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        resources = IAMOIDCProviderResourceSpec.scan(
            scan_accessor=scan_accessor)

        expected_resources = [
            Resource(
                resource_id=
                "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E",
                type="aws:iam:oidc-provider",
                link_collection=LinkCollection(
                    simple_links=(
                        SimpleLink(
                            pred="url",
                            obj=
                            "oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E",
                        ),
                        SimpleLink(
                            pred="create_date",
                            obj=resources[0].link_collection.simple_links[1].
                            obj,
                        ),
                        SimpleLink(pred="client_id", obj="sts.amazonaws.com"),
                        SimpleLink(
                            pred="thumbprint",
                            obj="9999999999999999999999999999999999999999"),
                    ),
                    multi_links=None,
                    tag_links=None,
                    resource_links=(ResourceLink(
                        pred="account",
                        obj="arn:aws::::account/123456789012"), ),
                    transient_resource_links=None,
                ),
            )
        ]

        self.assertEqual(resources, expected_resources)
예제 #14
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()

        ec2_client = session.client("ec2", region_name=region_name)
        list_resp = ec2_client.describe_vpcs()
        present_vpcs = list_resp["Vpcs"]
        self.assertEqual(len(present_vpcs), 1)
        present_vpc_id = present_vpcs[0]["VpcId"]
        present_vpc_arn = f"arn:aws:ec2:us-east-1:123456789012:vpc/{present_vpc_id}"

        create_resp = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")
        created_vpc_id = create_resp["Vpc"]["VpcId"]
        created_vpc_arn = f"arn:aws:ec2:us-east-1:123456789012:vpc/{created_vpc_id}"

        scan_accessor = AWSAccessor(session=session, account_id=account_id, region_name=region_name)
        resources = VPCResourceSpec.scan(scan_accessor=scan_accessor)

        expected_resources = [
            Resource(
                resource_id=present_vpc_arn,
                type="aws:ec2:vpc",
                link_collection=LinkCollection(
                    simple_links=(
                        SimpleLink(pred="is_default", obj=True),
                        SimpleLink(pred="cidr_block", obj="172.31.0.0/16"),
                        SimpleLink(pred="state", obj="available"),
                    ),
                    resource_links=(
                        ResourceLink(pred="account", obj="arn:aws::::account/123456789012"),
                        ResourceLink(pred="region", obj="arn:aws:::123456789012:region/us-east-1"),
                    ),
                ),
            ),
            Resource(
                resource_id=created_vpc_arn,
                type="aws:ec2:vpc",
                link_collection=LinkCollection(
                    simple_links=(
                        SimpleLink(pred="is_default", obj=False),
                        SimpleLink(pred="cidr_block", obj="10.0.0.0/16"),
                        SimpleLink(pred="state", obj="available"),
                    ),
                    resource_links=(
                        ResourceLink(pred="account", obj="arn:aws::::account/123456789012"),
                        ResourceLink(pred="region", obj="arn:aws:::123456789012:region/us-east-1"),
                    ),
                ),
            ),
        ]
        self.assertEqual(resources, expected_resources)
예제 #15
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()

        ec2_client = session.client("ec2", region_name=region_name)
        resp = ec2_client.create_volume(Size=1, AvailabilityZone="us-east-1a")
        create_time = resp["CreateTime"]

        scan_accessor = AWSAccessor(session=session, account_id=account_id, region_name=region_name)
        scan_result = EBSVolumeResourceSpec.scan(scan_accessor=scan_accessor)
        scan_result_dict = scan_result.to_dict()

        expected_scan_result_dict = {
            "resources": [
                {
                    "type": "aws:ec2:volume",
                    "links": [
                        {"pred": "availability_zone", "obj": "us-east-1a", "type": "simple"},
                        {"pred": "create_time", "obj": create_time, "type": "simple"},
                        {"pred": "size", "obj": 1, "type": "simple"},
                        {"pred": "state", "obj": "available", "type": "simple"},
                        {"pred": "volume_type", "obj": "standard", "type": "simple"},
                        {"pred": "encrypted", "obj": False, "type": "simple"},
                        {
                            "pred": "account",
                            "obj": "arn:aws::::account/123456789012",
                            "type": "resource_link",
                        },
                        {
                            "pred": "region",
                            "obj": "arn:aws:::123456789012:region/us-east-1",
                            "type": "resource_link",
                        },
                    ],
                }
            ],
            "stats": {
                "count": 1,
                "123456789012": {
                    "count": 1,
                    "us-east-1": {"count": 1, "ec2": {"count": 1, "DescribeVolumes": {"count": 1}}},
                },
            },
            "errors": [],
        }

        self.assertDictEqual(scan_result_dict, expected_scan_result_dict)
예제 #16
0
def main(argv: Optional[List[str]] = None) -> int:
    import argparse

    if argv is None:
        argv = sys.argv[1:]
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "resource_spec_class",
        type=str,
        help=
        "Name of class in altimeter.aws.scan.settings.RESOURCE_SPEC_CLASSES to scan",
    )
    parser.add_argument("region", type=str, help="AWS region name to scan")

    args_ns = parser.parse_args(argv)
    resource_spec_class_name = args_ns.resource_spec_class
    region = args_ns.region

    resource_spec_class: Optional[Type[AWSResourceSpec]] = None
    for cls in RESOURCE_SPEC_CLASSES:
        if cls.__name__ == resource_spec_class_name:
            resource_spec_class = cls
            break
    if resource_spec_class is None:
        print((
            f"Unable to find a class named {resource_spec_class_name} in "
            f"altimeter.aws.scan.settings.RESOURCE_SPEC_CLASSES: {RESOURCE_SPEC_CLASSES}."
        ))
        return 1

    session = boto3.Session(region_name=region)
    sts_client = session.client("sts")
    account_id = sts_client.get_caller_identity()["Account"]
    aws_accessor = AWSAccessor(session=session,
                               account_id=account_id,
                               region_name=region)
    resource_scan_result = resource_spec_class.scan(aws_accessor)
    resource_dicts = []
    for resource in resource_scan_result:
        resource_dicts.append(resource.to_dict())
    resource_scan_result_json = json.dumps(resource_dicts,
                                           indent=2,
                                           default=json_encoder)
    print(resource_scan_result_json)
    return 0
예제 #17
0
 def _list_from_aws(cls: Type["AWSResourceSpec"],
                    scan_accessor: AWSAccessor) -> ListFromAWSResult:
     try:
         resource_client = scan_accessor.client(cls.get_client_name())
         if cls.skip_resource_scan(
                 client=resource_client,
                 account_id=scan_accessor.account_id,
                 region=scan_accessor.region,
         ):
             return ListFromAWSResult(resources={})
         return cls.list_from_aws(resource_client, scan_accessor.account_id,
                                  scan_accessor.region)
     except ClientError as c_e:
         response_error = getattr(c_e, "response", {}).get("Error", {})
         error_code = response_error.get("Code", "")
         if error_code not in AWS_API_IGNORE_ERRORS:
             raise c_e
         return ListFromAWSResult(resources={})
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()
        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        resources = AccountResourceSpec.scan(scan_accessor=scan_accessor)

        expected_resources = [
            Resource(
                resource_id="arn:aws::::account/123456789012",
                type="aws:account",
                link_collection=LinkCollection(simple_links=(SimpleLink(
                    pred="account_id", obj="123456789012"), ), ),
            )
        ]

        self.assertEqual(resources, expected_resources)
예제 #19
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()

        ec2_client = session.client("ec2", region_name=region_name)
        resp = ec2_client.create_volume(Size=1, AvailabilityZone="us-east-1a")
        create_time = resp["CreateTime"]
        created_volume_id = resp["VolumeId"]
        created_volume_arn = f"arn:aws:ec2:us-east-1:123456789012:volume/{created_volume_id}"

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        resources = EBSVolumeResourceSpec.scan(scan_accessor=scan_accessor)

        expected_resources = [
            Resource(
                resource_id=created_volume_arn,
                type="aws:ec2:volume",
                link_collection=LinkCollection(
                    simple_links=(
                        SimpleLink(pred="availability_zone", obj="us-east-1a"),
                        SimpleLink(pred="create_time", obj=create_time),
                        SimpleLink(pred="size", obj=True),
                        SimpleLink(pred="state", obj="available"),
                        SimpleLink(pred="volume_type", obj="standard"),
                        SimpleLink(pred="encrypted", obj=False),
                    ),
                    resource_links=(
                        ResourceLink(pred="account",
                                     obj="arn:aws::::account/123456789012"),
                        ResourceLink(
                            pred="region",
                            obj="arn:aws:::123456789012:region/us-east-1"),
                    ),
                ),
            )
        ]
        self.assertEqual(resources, expected_resources)
    def test_disappearing_elb_race_condition(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        lb_name = "foo"

        session = boto3.Session()
        client = session.client("elb", region_name=region_name)

        client.create_load_balancer(
            LoadBalancerName=lb_name,
            Listeners=[{
                "Protocol": "HTTP",
                "LoadBalancerPort": 80,
                "InstancePort": 80
            }],
            Tags=[{
                "Key": "Name",
                "Value": lb_name
            }],
        )

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.elbv1.load_balancer.ClassicLoadBalancerResourceSpec.get_lb_attrs"
        ) as mock_get_lb_attrs:
            mock_get_lb_attrs.side_effect = ClientError(
                operation_name="DescribeLoadBalancerAttributes",
                error_response={
                    "Error": {
                        "Code":
                        "LoadBalancerNotFound",
                        "Message":
                        f"There is no ACTIVE Load Balancer named '{lb_name}'",
                    }
                },
            )
            resources = ClassicLoadBalancerResourceSpec.scan(
                scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
예제 #21
0
    def test_disappearing_instance_race_condition(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        instance_name = "foo"

        session = boto3.Session()
        client = session.client("rds", region_name=region_name)

        client.create_db_instance(
            DBInstanceIdentifier=instance_name,
            Engine="postgres",
            DBName=instance_name,
            DBInstanceClass="db.m1.small",
            MasterUsername="******",
            MasterUserPassword="******",
        )

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.rds.instance.RDSInstanceResourceSpec.get_instance_tags"
        ) as mock_get_instance_tags:
            with patch(
                    "altimeter.aws.resource.rds.instance.RDSInstanceResourceSpec.set_automated_backups"
            ) as mock_set_automated_backups:
                mock_set_automated_backups.return_value = None
                mock_get_instance_tags.side_effect = ClientError(
                    operation_name="ListTagsForResource",
                    error_response={
                        "Error": {
                            "Code":
                            "DBInstanceNotFound",
                            "Message":
                            f"Could not find a DB Instance matching the resource name: '{instance_name}'",
                        }
                    },
                )
                resources = RDSInstanceResourceSpec.scan(
                    scan_accessor=scan_accessor)
                self.assertEqual(resources, [])
예제 #22
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()
        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        scan_result = AccountResourceSpec.scan(scan_accessor=scan_accessor)
        scan_result_dict = scan_result.to_dict()

        expected_scan_result_dict = {
            "resources": [{
                "type":
                "aws:account",
                "links": [{
                    "pred": "account_id",
                    "obj": "123456789012",
                    "type": "simple"
                }],
            }],
            "stats": {
                "count": 1,
                "123456789012": {
                    "count": 1,
                    "us-east-1": {
                        "count": 1,
                        "sts": {
                            "count": 1,
                            "GetCallerIdentity": {
                                "count": 1
                            }
                        },
                    },
                },
            },
            "errors": [],
        }

        self.assertDictEqual(scan_result_dict, expected_scan_result_dict)
예제 #23
0
    def test_disappearing_oidc_provider_race_condition(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        oidc_url = "https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E"
        oidc_client_ids = ["sts.amazonaws.com"]
        oidc_thumbprints = ["9999999999999999999999999999999999999999"]

        session = boto3.Session()

        client = session.client("iam")

        oidc_provider_resp = client.create_open_id_connect_provider(
            Url=oidc_url,
            ClientIDList=oidc_client_ids,
            ThumbprintList=oidc_thumbprints,
        )
        oidc_provider_arn = oidc_provider_resp["OpenIDConnectProviderArn"]

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.iam.iam_oidc_provider.IAMOIDCProviderResourceSpec"
                ".get_oidc_provider_details"
        ) as mock_get_oidc_provider_details:
            mock_get_oidc_provider_details.side_effect = ClientError(
                operation_name="GetOIDCProvider",
                error_response={
                    "Error": {
                        "Code":
                        "NoSuchEntity",
                        "Message":
                        f"OpenIDConnect Provider not found for arn {oidc_provider_arn}",
                    }
                },
            )
            resources = IAMOIDCProviderResourceSpec.scan(
                scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
    def test_disappearing_elb_race_condition(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        lb_name = "foo"

        session = boto3.Session()
        ec2_client = session.client("ec2", region_name=region_name)
        moto_subnets = [
            subnet["SubnetId"]
            for subnet in ec2_client.describe_subnets()["Subnets"]
        ]

        client = session.client("elbv2", region_name=region_name)

        resp = client.create_load_balancer(
            Name=lb_name,
            Subnets=moto_subnets[:2],
        )
        lb_arn = resp["LoadBalancers"][0]["LoadBalancerArn"]

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        with patch(
                "altimeter.aws.resource.elbv2.load_balancer.LoadBalancerResourceSpec.get_lb_attrs"
        ) as mock_get_lb_attrs:
            mock_get_lb_attrs.side_effect = ClientError(
                operation_name="DescribeLoadBalancerAttributes",
                error_response={
                    "Error": {
                        "Code": "LoadBalancerNotFound",
                        "Message": f"Load balancer '{lb_arn}' not found",
                    }
                },
            )
            resources = LoadBalancerResourceSpec.scan(
                scan_accessor=scan_accessor)
            self.assertEqual(resources, [])
예제 #25
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()

        ec2_client = session.client("ec2", region_name=region_name)
        ec2_client.create_vpc(CidrBlock="10.0.0.0/16")

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        resources = VPCResourceSpec.scan(scan_accessor=scan_accessor)

        expected_resources = [
            {
                "type":
                "aws:ec2:vpc",
                "links": [
                    {
                        "pred": "is_default",
                        "obj": True,
                        "type": "simple"
                    },
                    {
                        "pred": "cidr_block",
                        "obj": "172.31.0.0/16",
                        "type": "simple",
                    },  # from moto
                    {
                        "pred": "state",
                        "obj": "available",
                        "type": "simple"
                    },
                    {
                        "pred": "account",
                        "obj": "arn:aws::::account/123456789012",
                        "type": "resource_link",
                    },
                    {
                        "pred": "region",
                        "obj": "arn:aws:::123456789012:region/us-east-1",
                        "type": "resource_link",
                    },
                ],
            },
            {
                "type":
                "aws:ec2:vpc",
                "links": [
                    {
                        "pred": "is_default",
                        "obj": False,
                        "type": "simple"
                    },
                    {
                        "pred": "cidr_block",
                        "obj": "10.0.0.0/16",
                        "type": "simple"
                    },
                    {
                        "pred": "state",
                        "obj": "available",
                        "type": "simple"
                    },
                    {
                        "pred": "account",
                        "obj": "arn:aws::::account/123456789012",
                        "type": "resource_link",
                    },
                    {
                        "pred": "region",
                        "obj": "arn:aws:::123456789012:region/us-east-1",
                        "type": "resource_link",
                    },
                ],
            },
        ]
        expected_api_call_stats = {
            "count": 1,
            "123456789012": {
                "count": 1,
                "us-east-1": {
                    "count": 1,
                    "ec2": {
                        "count": 1,
                        "DescribeVpcs": {
                            "count": 1
                        }
                    }
                },
            },
        }
        self.assertListEqual([resource.to_dict() for resource in resources],
                             expected_resources)
        self.assertDictEqual(scan_accessor.api_call_stats.to_dict(),
                             expected_api_call_stats)
예제 #26
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()
        iam_client = session.client("iam")
        test_assume_role_policy_doc = {
            "Version":
            "2012-10-17",
            "Statement": [{
                "Sid": "abc",
                "Effect": "Allow",
                "Principal": {
                    "Service": "lambda.amazonaws.com"
                },
                "Action": "sts:AssumeRole",
            }],
        }
        iam_role_resp = iam_client.create_role(
            RoleName="testrole",
            AssumeRolePolicyDocument=json.dumps(test_assume_role_policy_doc),
        )
        iam_role_arn = iam_role_resp["Role"]["Arn"]

        lambda_client = session.client("lambda", region_name=region_name)
        lambda_client.create_function(
            FunctionName="func_name",
            Runtime="python3.7",
            Role=iam_role_arn,
            Handler="testhandler",
            Description="testdescr",
            Timeout=90,
            MemorySize=128,
            Code={"ZipFile": b"1234"},
            Publish=False,
            VpcConfig={
                "SubnetIds": ["subnet-123"],
                "SecurityGroupIds": ["sg-123"]
            },
            DeadLetterConfig={"TargetArn": "test_dl_config"},
            Environment={"Variables": {
                "TEST_VAR": "test_val"
            }},
            KMSKeyArn="test_kms_arn",
            TracingConfig={"Mode": "Active"},
            Tags={
                "tagkey1": "tagval1",
                "tagkey2": "tagval2"
            },
        )

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        resources = LambdaFunctionResourceSpec.scan(
            scan_accessor=scan_accessor)
        expected_resources = [
            Resource(
                resource_id=
                "arn:aws:lambda:us-east-1:123456789012:function:func_name",
                type="aws:lambda:function",
                link_collection=LinkCollection(
                    simple_links=(
                        SimpleLink(pred="function_name", obj="func_name"),
                        SimpleLink(pred="runtime", obj="python3.7"),
                    ),
                    resource_links=(
                        ResourceLink(pred="account",
                                     obj="arn:aws::::account/123456789012"),
                        ResourceLink(
                            pred="region",
                            obj="arn:aws:::123456789012:region/us-east-1"),
                    ),
                    transient_resource_links=(
                        TransientResourceLink(
                            pred="vpc",
                            obj=
                            "arn:aws:ec2:us-east-1:123456789012:vpc/vpc-123abc"
                        ),
                        TransientResourceLink(
                            pred="role",
                            obj="arn:aws:iam::123456789012:role/testrole"),
                    ),
                ),
            )
        ]
        self.maxDiff = None
        self.assertEqual(resources, expected_resources)
예제 #27
0
    def test_get_embedded_policy(self):
        account_id = "123456789012"
        region_name = "us-east-1"
        role_name = "foo"

        role_policy = "foo_policy"
        policy_document = """{
            "Statement": [
                {
                    "Action": ["sts:assumeRole"],
                    "Effect": "Allow", "Resource": ["*"]
                }
            ],
            "Version": "2012-10-17"
        }"""

        role_policy2 = "foo_policy2"
        policy_document2 = """{
            "Statement": [
                {
                    "Action": ["sqs:queue"],
                    "Effect": "Allow", "Resource": ["*"]
                }
            ],
            "Version": "2012-10-17"
        }"""

        assume_role_policy_document = """{
            "Version": "2012-10-17",
            "Statement": [
                {
                "Effect": "Allow",
                "Principal": {
                    "Service": "lambda.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
                }
            ]
        }"""
        session = boto3.Session()
        client = session.client("iam")
        client.create_role(
            RoleName=role_name,
            AssumeRolePolicyDocument=assume_role_policy_document)
        iam = boto3.resource("iam")
        policy = iam.RolePolicy(role_name, role_policy)
        policy.put(PolicyDocument=policy_document)
        policy = iam.RolePolicy(role_name, role_policy2)
        policy.put(PolicyDocument=policy_document2)

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        resources = IAMRoleResourceSpec.scan(scan_accessor=scan_accessor)
        embedded_resources_links = [
            link for link in resources[0].link_collection.multi_links
            if link.pred == "embedded_policy"
        ]
        self.assertEqual(len(embedded_resources_links), 2)
        # First policy.
        embedded_resources_link = embedded_resources_links[0]
        self.assertTrue(
            compare_embedded_policy(embedded_resources_link, role_policy,
                                    policy_document))
        # Second policy.
        embedded_resources_link = embedded_resources_links[1]
        self.assertTrue(
            compare_embedded_policy(embedded_resources_link, role_policy2,
                                    policy_document2))
예제 #28
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()

        lambda_client = session.client("lambda", region_name=region_name)
        lambda_client.create_function(
            FunctionName="func_name",
            Runtime="python3.7",
            Role="testrole",
            Handler="testhandler",
            Description="testdescr",
            Timeout=90,
            MemorySize=128,
            Code={"ZipFile": b"1234"},
            Publish=False,
            VpcConfig={
                "SubnetIds": ["subnet-123"],
                "SecurityGroupIds": ["sg-123"]
            },
            DeadLetterConfig={"TargetArn": "test_dl_config"},
            Environment={"Variables": {
                "TEST_VAR": "test_val"
            }},
            KMSKeyArn="test_kms_arn",
            TracingConfig={"Mode": "Active"},
            Tags={
                "tagkey1": "tagval1",
                "tagkey2": "tagval2"
            },
            Layers=["test_layer1"],
        )

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        scan_result = LambdaFunctionResourceSpec.scan(
            scan_accessor=scan_accessor)
        scan_result_dict = scan_result.to_dict()

        self.maxDiff = None
        expected_scan_result_dict = {
            "resources": [{
                "type":
                "aws:lambda:function",
                "links": [
                    {
                        "pred": "function_name",
                        "obj": "func_name",
                        "type": "simple"
                    },
                    {
                        "pred": "runtime",
                        "obj": "python3.7",
                        "type": "simple",
                    },
                    {
                        "pred": "vpc",
                        "obj":
                        f"arn:aws:ec2:{region_name}:{account_id}:vpc/vpc-123abc",
                        "type": "transient_resource_link",
                    },
                    {
                        "pred": "account",
                        "obj": f"arn:aws::::account/{account_id}",
                        "type": "resource_link",
                    },
                    {
                        "pred": "region",
                        "obj": f"arn:aws:::{account_id}:region/{region_name}",
                        "type": "resource_link",
                    },
                ],
            }],
            "stats": {
                "count": 1,
                account_id: {
                    "count": 1,
                    region_name: {
                        "count": 1,
                        "lambda": {
                            "count": 1,
                            "ListFunctions": {
                                "count": 1
                            }
                        },
                    },
                },
            },
            "errors": [],
        }
        self.assertDictEqual(scan_result_dict, expected_scan_result_dict)
예제 #29
0
    def test_scan(self):
        account_id = "123456789012"
        region_name = "us-east-1"

        session = boto3.Session()
        iam_client = session.client("iam")
        test_assume_role_policy_doc = {
            "Version":
            "2012-10-17",
            "Statement": [{
                "Sid": "abc",
                "Effect": "Allow",
                "Principal": {
                    "Service": "lambda.amazonaws.com"
                },
                "Action": "sts:AssumeRole",
            }],
        }
        iam_role_resp = iam_client.create_role(
            RoleName="testrole",
            AssumeRolePolicyDocument=json.dumps(test_assume_role_policy_doc),
        )
        iam_role_arn = iam_role_resp["Role"]["Arn"]

        lambda_client = session.client("lambda", region_name=region_name)
        lambda_client.create_function(
            FunctionName="func_name",
            Runtime="python3.7",
            Role=iam_role_arn,
            Handler="testhandler",
            Description="testdescr",
            Timeout=90,
            MemorySize=128,
            Code={"ZipFile": b"1234"},
            Publish=False,
            VpcConfig={
                "SubnetIds": ["subnet-123"],
                "SecurityGroupIds": ["sg-123"]
            },
            DeadLetterConfig={"TargetArn": "test_dl_config"},
            Environment={"Variables": {
                "TEST_VAR": "test_val"
            }},
            KMSKeyArn="test_kms_arn",
            TracingConfig={"Mode": "Active"},
            Tags={
                "tagkey1": "tagval1",
                "tagkey2": "tagval2"
            },
            Layers=["test_layer1"],
        )

        scan_accessor = AWSAccessor(session=session,
                                    account_id=account_id,
                                    region_name=region_name)
        resources = LambdaFunctionResourceSpec.scan(
            scan_accessor=scan_accessor)

        self.maxDiff = None
        expected_resources = [{
            "type":
            "aws:lambda:function",
            "links": [
                {
                    "pred": "function_name",
                    "obj": "func_name",
                    "type": "simple"
                },
                {
                    "pred": "runtime",
                    "obj": "python3.7",
                    "type": "simple",
                },
                {
                    "pred": "vpc",
                    "obj":
                    f"arn:aws:ec2:{region_name}:{account_id}:vpc/vpc-123abc",
                    "type": "transient_resource_link",
                },
                {
                    "pred": "account",
                    "obj": f"arn:aws::::account/{account_id}",
                    "type": "resource_link",
                },
                {
                    "pred": "region",
                    "obj": f"arn:aws:::{account_id}:region/{region_name}",
                    "type": "resource_link",
                },
            ],
        }]

        expected_api_call_stats = {
            "count": 1,
            account_id: {
                "count": 1,
                region_name: {
                    "count": 1,
                    "lambda": {
                        "count": 1,
                        "ListFunctions": {
                            "count": 1
                        }
                    },
                },
            },
        }
        self.assertListEqual([resource.to_dict() for resource in resources],
                             expected_resources)
        self.assertDictEqual(scan_accessor.api_call_stats.to_dict(),
                             expected_api_call_stats)