def test_parse(self):
     schema = Schema(ScalarField("Key1"), ScalarField("Key2"))
     data = {"Key1": "Value1", "Key2": "Value2"}
     link_collection = schema.parse(data, {})
     expected_link_collection = LinkCollection(simple_links=(
         SimpleLink(pred="key1", obj="Value1"),
         SimpleLink(pred="key2", obj="Value2"),
     ))
     self.assertEqual(link_collection, expected_link_collection)
class CloudTrailTrailResourceSpec(CloudTrailResourceSpec):
    """Resource representing a CloudTrail Trail"""

    type_name = "trail"
    schema = Schema(
        ScalarField("Name"),
        ScalarField("S3BucketName"),
        ScalarField("IncludeGlobalServiceEvents"),
        ScalarField("IsMultiRegionTrail"),
    )

    @classmethod
    def list_from_aws(
        cls: Type["CloudTrailTrailResourceSpec"],
        client: BaseClient,
        account_id: str,
        region: str,
    ) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'trail_1_arn': {trail_1_dict},
             'trail_2_arn': {trail_2_dict},
             ...}

        Where the dicts represent results from describe_trails."""
        trails = {}
        resp = client.describe_trails(includeShadowTrails=False)
        for trail in resp.get("trailList", []):
            resource_arn = trail["TrailARN"]
            trails[resource_arn] = trail
        return ListFromAWSResult(resources=trails)
Пример #3
0
class SeverityLevelResourceSpec(SupportResourceSpec):
    """Resource representing an AWS Support severity level."""

    type_name = "severity-level"
    schema = Schema(ScalarField("code"))

    @classmethod
    def list_from_aws(cls: Type["SeverityLevelResourceSpec"],
                      client: BaseClient, account_id: str,
                      region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'severity_level_arn': {severity_level_dict},
             'severity_level_arn': {severity_level_dict},
             ...}

        Where the dicts represent results from describe_organization."""
        resp = client.describe_severity_levels()
        severity_levels_resp = resp["severityLevels"]
        severity_levels = {}
        for s_l in severity_levels_resp:
            code = s_l["code"]
            code_arn = cls.generate_arn(resource_id=code,
                                        account_id=account_id)
            severity_levels[code_arn] = {"code": code}
        return ListFromAWSResult(resources=severity_levels)
class EBSSnapshotResourceSpec(EC2ResourceSpec):
    """Resource for EBSSnapshots"""

    type_name = "snapshot"
    schema = Schema(
        ScalarField("VolumeSize"),
        ScalarField("Encrypted"),
        TransientResourceLinkField("KmsKeyId",
                                   KMSKeyResourceSpec,
                                   optional=True,
                                   value_is_id=True),
        TransientResourceLinkField("VolumeId", EBSVolumeResourceSpec),
        TagsField(),
    )

    @classmethod
    def list_from_aws(cls: Type["EBSSnapshotResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'snapshot_1_arn': {snapshot_1_dict},
             'snapshot_2_arn': {snapshot_2_dict},
             ...}

        Where the dicts represent results from describe_snapshots."""
        snapshots = {}
        paginator = client.get_paginator("describe_snapshots")
        for resp in paginator.paginate(OwnerIds=["self"]):
            for snapshot in resp.get("Snapshots", []):
                resource_arn = cls.generate_arn(
                    account_id=account_id,
                    region=region,
                    resource_id=snapshot["SnapshotId"])
                snapshots[resource_arn] = snapshot
        return ListFromAWSResult(resources=snapshots)
Пример #5
0
class IAMSAMLProviderResourceSpec(IAMResourceSpec):
    """Resource for IAM SAML Providers"""

    type_name = "saml-provider"
    schema = Schema(
        ScalarField("Name"),
        ScalarField("ValidUntil"),
        ScalarField("CreateDate"),
        ScalarField("MetadataDocumentChecksum"),
    )

    @classmethod
    def list_from_aws(cls: Type["IAMSAMLProviderResourceSpec"],
                      client: BaseClient, account_id: str,
                      region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'saml_provider_1_arn': {saml_provider_1_dict},
             'saml_provider_2_arn': {saml_provider_2_dict},
             ...}

        Where the dicts represent results from list_saml_providers and additional info per
        saml_provider list_saml_providers. An additional 'Name' key is added."""
        saml_providers = {}
        resp = client.list_saml_providers()
        for saml_provider in resp.get("SAMLProviderList", []):
            resource_arn = saml_provider["Arn"]
            saml_provider["Name"] = "/".join(resource_arn.split("/")[1:])
            saml_provider_resp = client.get_saml_provider(
                SAMLProviderArn=resource_arn)
            saml_metadata_document = saml_provider_resp["SAMLMetadataDocument"]
            hash_object = hashlib.sha256(saml_metadata_document.encode())
            saml_provider["MetadataDocumentChecksum"] = hash_object.hexdigest()
            saml_providers[resource_arn] = saml_provider
        return ListFromAWSResult(resources=saml_providers)
Пример #6
0
class AccountResourceSpec(AWSResourceSpec):
    """Resource representing an AWS Account"""

    type_name = "account"
    service_name = "sts"
    scan_granularity = ScanGranularity.ACCOUNT
    schema = Schema(ScalarField("account_id"))
    allow_clobber: List[Type[ResourceSpec]] = [UnscannedAccountResourceSpec]

    @classmethod
    def get_full_type_name(cls: Type["AccountResourceSpec"]) -> str:
        return f"{cls.provider_name}:{cls.type_name}"

    @classmethod
    def list_from_aws(
        cls: Type["AccountResourceSpec"], client: BaseClient, account_id: str, region: str
    ) -> ListFromAWSResult:
        """This resource is somewhat synthetic, this method simply returns a dict of form
            {'account_arn': {account_dict}"""
        sts_account_id = client.get_caller_identity()["Account"]
        if sts_account_id != account_id:
            raise ValueError(f"BUG: sts detected account_id {sts_account_id} != {account_id}")
        accounts = {f"arn:aws::::account/{sts_account_id}": {"account_id": sts_account_id}}
        return ListFromAWSResult(resources=accounts)

    @classmethod
    def generate_arn(
        cls: Type["AccountResourceSpec"], account_id: str, region: str, resource_id: str
    ) -> str:
        """Generate an ARN for this resource"""
        return f"arn:aws::::account/{resource_id}"
Пример #7
0
class EC2ImageResourceSpec(EC2ResourceSpec):
    """Resource for EC2Images (AMIs)"""

    type_name = "image"
    schema = Schema(
        ScalarField("Name", optional=True),
        ScalarField("Description", optional=True),
        ScalarField("Public"),
        TagsField(),
    )

    @classmethod
    def list_from_aws(cls: Type["EC2ImageResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'image_1_arn': {image_1_dict},
             'image_2_arn': {image_2_dict},
             ...}

        Where the dicts represent results from describe_images."""
        images = {}
        resp = client.describe_images(Owners=["self"])
        for image in resp["Images"]:
            image_id = image["ImageId"]
            resource_arn = cls.generate_arn(account_id=account_id,
                                            region=region,
                                            resource_id=image_id)
            images[resource_arn] = image
        return ListFromAWSResult(resources=images)
Пример #8
0
class EC2RouteTableResourceSpec(EC2ResourceSpec):
    """Resource for Route Tables"""

    # type_name = "route-table"
    type_name = "route_table"

    schema = Schema(
        ScalarField("RouteTableId"),
        ResourceLinkField("VpcId", VPCResourceSpec),
        ScalarField("OwnerId", optional=True),
        AnonymousListField("PropagatingVgws",
                           ScalarField("GatewayId"),
                           optional=True),
        ListField(
            "Routes",
            EmbeddedDictField(
                ScalarField("DestinationCidrBlock", optional=True),
                ScalarField("DestinationIpv6CidrBlock", optional=True),
                ScalarField("DestinationPrefixListId", optional=True),
                ScalarField("EgressOnlyInternetGatewayId", optional=True),
                ScalarField("GatewayId", optional=True),
                ScalarField("InstanceId", optional=True),
                ScalarField("InstanceOwnerId", optional=True),
                ScalarField("NatGatewayId", optional=True),
                ScalarField("TransitGatewayId", optional=True),
                ScalarField("NetworkInterfaceId", optional=True),
                ScalarField("Origin", optional=True),
                ScalarField("State", optional=True),
                ScalarField("VpcPeeringConnectionId", optional=True),
            ),
            optional=True,
            alti_key="route",
        ),
        ListField(
            "Associations",
            EmbeddedDictField(
                ScalarField("Main", optional=True),
                ScalarField("RouteTableAssociationId", optional=True),
                ScalarField("RouteTableId", optional=True),
                ScalarField("SubnetId", optional=True),
            ),
            optional=True,
            alti_key="association",
        ),
    )

    @classmethod
    def list_from_aws(cls: Type["EC2RouteTableResourceSpec"],
                      client: BaseClient, account_id: str,
                      region: str) -> ListFromAWSResult:
        paginator = client.get_paginator("describe_route_tables")
        route_tables = {}
        for resp in paginator.paginate():
            for attachment in resp.get("RouteTables", []):
                resource_arn = cls.generate_arn(
                    account_id=account_id,
                    region=region,
                    resource_id=attachment["RouteTableId"])
                route_tables[resource_arn] = attachment
        return ListFromAWSResult(resources=route_tables)
class RegionResourceSpec(EC2ResourceSpec):
    """Resource representing an AWS Region"""

    type_name = "region"
    scan_granularity = ScanGranularity.ACCOUNT
    schema = Schema(ScalarField("RegionName", "name"),
                    ScalarField("OptInStatus"))

    @classmethod
    def get_full_type_name(cls: Type["RegionResourceSpec"]) -> str:
        return f"{cls.provider_name}:{cls.type_name}"

    @classmethod
    def list_from_aws(cls: Type["RegionResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'region_1_arn': {region_1_dict},
             'region_2_arn': {region_2_dict},
             ...}

        Where the dicts represent results from describe_regions."""
        regions = {}
        resp = client.describe_regions(AllRegions=True)
        for region_resp in resp["Regions"]:
            region_name = region_resp["RegionName"]
            region_arn = f"arn:aws:::{account_id}:region/{region_name}"
            regions[region_arn] = region_resp
        return ListFromAWSResult(resources=regions)
Пример #10
0
class IAMAWSManagedPolicyResourceSpec(IAMResourceSpec):
    """Resource for AWS-managed IAM Policies"""

    type_name = "policy"
    schema = Schema(ScalarField("PolicyName", "name"), ScalarField("PolicyId"))

    @classmethod
    def list_from_aws(
        cls: Type["IAMAWSManagedPolicyResourceSpec"],
        client: BaseClient,
        account_id: str,
        region: str,
    ) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'role_1_arn': {role_1_dict},
             'role_2_arn': {role_2_dict},
             ...}

        Where the dicts represent results from list_policies and additional info per role from
        list_targets_by_role."""
        policies = {}
        paginator = client.get_paginator("list_policies")

        for resp in paginator.paginate(Scope="AWS", OnlyAttached=True):
            for policy in resp.get("Policies", []):
                resource_arn = policy["Arn"]
                policies[resource_arn] = policy
        return ListFromAWSResult(resources=policies)
Пример #11
0
class VpcEndpointResourceSpec(EC2ResourceSpec):
    """Resource for VPC Endpoints"""

    type_name = "vpc-endpoint"
    schema = Schema(
        ScalarField("VpcEndpointType"),
        ScalarField("ServiceName"),
        ScalarField("State"),
        ResourceLinkField("VpcId", VPCResourceSpec),
        TagsField(),
    )

    @classmethod
    def list_from_aws(
        cls: Type["VpcEndpointResourceSpec"], client: BaseClient, account_id: str, region: str
    ) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'vpc_endpoint_1_arn': {vpc_endpoint_1_dict},
             'vpc_endpoint_1_arn': {vpc_endpoint_2_dict},
             ...}

        Where the dicts represent results from describe_vpc_endpoints."""
        endpoints = {}
        paginator = client.get_paginator("describe_vpc_endpoints")
        for resp in paginator.paginate():
            for endpoint in resp.get("VpcEndpoints", []):
                resource_arn = cls.generate_arn(account_id, region, endpoint["VpcEndpointId"])
                endpoints[resource_arn] = endpoint
        return ListFromAWSResult(resources=endpoints)
Пример #12
0
class SubnetResourceSpec(EC2ResourceSpec):
    """Resource for Subnets"""

    type_name = "subnet"
    schema = Schema(
        ScalarField("CidrBlock"),
        ScalarField("FirstIp"),
        ScalarField("LastIp"),
        ScalarField("State"),
        TagsField(),
        ResourceLinkField("VpcId", VPCResourceSpec),
    )

    @classmethod
    def list_from_aws(
        cls: Type["SubnetResourceSpec"], client: BaseClient, account_id: str, region: str
    ) -> ListFromAWSResult:
        subnets = {}
        resp = client.describe_subnets()
        for subnet in resp.get("Subnets", []):
            resource_arn = cls.generate_arn(
                account_id=account_id, region=region, resource_id=subnet["SubnetId"]
            )
            cidr = subnet["CidrBlock"]
            ipv4_network = ipaddress.IPv4Network(cidr, strict=False)
            first_ip, last_ip = int(ipv4_network[0]), int(ipv4_network[-1])
            subnet["FirstIp"] = first_ip
            subnet["LastIp"] = last_ip
            subnets[resource_arn] = subnet
        return ListFromAWSResult(resources=subnets)
Пример #13
0
class LambdaFunctionResourceSpec(LambdaResourceSpec):
    """Resource for Lambda Functions"""

    type_name = "function"
    schema = Schema(
        ScalarField("FunctionName"),
        ScalarField("Runtime", optional=True),
        AnonymousDictField(
            "VpcConfig",
            TransientResourceLinkField("VpcId", VPCResourceSpec,
                                       optional=True),
            optional=True,
        ),
    )

    @classmethod
    def list_from_aws(cls: Type["LambdaFunctionResourceSpec"],
                      client: BaseClient, account_id: str,
                      region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'function_1_arn': {function_1_dict},
             'function_2_arn': {function_2_dict},
             ...}

        Where the dicts represent results from list_functions."""
        functions = {}
        paginator = client.get_paginator("list_functions")
        for resp in paginator.paginate():
            for function in resp.get("Functions", []):
                resource_arn = function["FunctionArn"]
                functions[resource_arn] = function
        return ListFromAWSResult(resources=functions)
class TransitGatewayVpcAttachmentResourceSpec(EC2ResourceSpec):
    """Resource for Transit Gateway VPC Attachments"""

    type_name = "transit-gateway-vpc-attachment"
    schema = Schema(
        ScalarField("TransitGatewayAttachmentId"),
        ScalarField("TransitGatewayId"),
        ScalarField("VpcId"),
        ScalarField("VpcOwnerId"),
        ScalarField("State"),
        ScalarField("CreationTime"),
        ListField("SubnetIds", EmbeddedScalarField(), alti_key="subnet_id"),
        AnonymousDictField("Options", ScalarField("DnsSupport"),
                           ScalarField("Ipv6Support")),
    )

    @classmethod
    def list_from_aws(
        cls: Type["TransitGatewayVpcAttachmentResourceSpec"],
        client: BaseClient,
        account_id: str,
        region: str,
    ) -> ListFromAWSResult:
        paginator = client.get_paginator(
            "describe_transit_gateway_vpc_attachments")
        attachments = {}
        for resp in paginator.paginate():
            for attachment in resp.get("TransitGatewayVpcAttachments", []):
                resource_arn = cls.generate_arn(
                    account_id, region,
                    attachment["TransitGatewayAttachmentId"])
                attachments[resource_arn] = attachment
        return ListFromAWSResult(resources=attachments)
Пример #15
0
class EKSClusterResourceSpec(EKSResourceSpec):
    """Resource for Clusters"""

    type_name = "cluster"
    schema = Schema(ScalarField("Name"), )

    @classmethod
    def list_from_aws(cls: Type["EKSClusterResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'cluster_1_arn': {cluster_1_dict},
             'cluster_2_arn': {cluster_2_dict},
             ...}

        Where the dicts represent results from list_clusters."""
        clusters = {}
        try:
            paginator = client.get_paginator("list_clusters")
            for resp in paginator.paginate():
                for cluster_name in resp.get("clusters", []):
                    resource_arn = cls.generate_arn(account_id=account_id,
                                                    region=region,
                                                    resource_id=cluster_name)
                    clusters[resource_arn] = {"Name": cluster_name}
        except ClientError as c_e:
            response_error = getattr(c_e, "response", {}).get("Error", {})
            error_code = response_error.get("Code", "")
            if error_code != "AccessDeniedException":
                raise c_e
            error_msg = response_error.get("Message", "")
            if error_msg != f"Account {account_id} is not authorized to use this service":
                raise c_e
        return ListFromAWSResult(resources=clusters)
class VPCResourceSpec(EC2ResourceSpec):
    """Resource for VPCs"""

    type_name = "vpc"
    schema = Schema(ScalarField("IsDefault"), ScalarField("CidrBlock"),
                    ScalarField("State"), TagsField())

    @classmethod
    def list_from_aws(cls: Type["VPCResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'vpc_1_arn': {vpc_1_dict},
             'vpc_2_arn': {vpc_2_dict},
             ...}

        Where the dicts represent results from describe_vpcs."""
        vpcs = {}
        paginator = client.get_paginator("describe_vpcs")
        for resp in paginator.paginate():
            for vpc in resp.get("Vpcs", []):
                resource_arn = cls.generate_arn(account_id=account_id,
                                                region=region,
                                                resource_id=vpc["VpcId"])
                vpcs[resource_arn] = vpc
        return ListFromAWSResult(resources=vpcs)
class InstanceProfileResourceSpec(IAMResourceSpec):
    """Resource for Instance Profiles"""

    # type_name = "instance-profile"
    type_name = "instance_profile"
    schema = Schema(
        ScalarField("InstanceProfileName", alti_key="name"),
        AnonymousListField(
            "Roles",
            AnonymousEmbeddedDictField(
                ResourceLinkField("Arn",
                                  IAMRoleResourceSpec,
                                  value_is_id=True,
                                  alti_key="attached_role")),
        ),
    )

    @classmethod
    def list_from_aws(cls: Type["InstanceProfileResourceSpec"],
                      client: BaseClient, account_id: str,
                      region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'instance_profile_1_arn': {instance_profile_1_dict},
             'instance_profile_2_arn': {instance_profile_2_dict},
             ...}

        Where the dicts represent results from list_instance_profiles."""
        paginator = client.get_paginator("list_instance_profiles")
        instance_profiles = {}
        for resp in paginator.paginate():
            for instance_profile in resp.get("InstanceProfiles", []):
                resource_arn = instance_profile["Arn"]
                instance_profiles[resource_arn] = instance_profile
        return ListFromAWSResult(resources=instance_profiles)
Пример #18
0
class TargetGroupResourceSpec(ElasticLoadBalancingResourceSpec):
    """Resource for target group"""

    type_name = "targetgroup"
    schema = Schema(
        ScalarField("TargetGroupName"),
        ScalarField("Protocol", optional=True),
        ScalarField("Port", optional=True),
        TransientResourceLinkField("VpcId", VPCResourceSpec, optional=True),
        ScalarField("HealthCheckProtocol", optional=True),
        ScalarField("HealthCheckPort", optional=True),
        ScalarField("HealthCheckEnabled"),
        ListField(
            "LoadBalancerArns",
            EmbeddedResourceLinkField(LoadBalancerResourceSpec,
                                      value_is_id=True),
        ),
        ScalarField("TargetType"),
        ListField(
            "TargetHealthDescriptions",
            EmbeddedDictField(
                AnonymousDictField(
                    "Target",
                    ScalarField("Id", alti_key="target_id"),
                    ScalarField("Port", alti_key="target_port", optional=True),
                    ScalarField("AvailabilityZone",
                                alti_key="target_az",
                                optional=True),
                ),
                ScalarField("HealthCheckPort", optional=True),
                AnonymousDictField(
                    "TargetHealth",
                    ScalarField("State"),
                    ScalarField("Reason", optional=True),
                    ScalarField("Description", optional=True),
                    optional=True,
                ),
            ),
        ),
    )

    @classmethod
    def list_from_aws(cls: Type["TargetGroupResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'target_group_1_arn': {target_group_1_dict},
             'target_group_2_arn': {target_group_2_dict},
             ...}

        Where the dicts represent results from describe_target_groups."""
        paginator = client.get_paginator("describe_target_groups")
        resources = {}
        for resp in paginator.paginate():
            for resource in resp.get("TargetGroups", []):
                resource_arn = resource["TargetGroupArn"]
                resource["TargetHealthDescriptions"] = get_target_group_health(
                    client, resource_arn)
                resources[resource_arn] = resource
        return ListFromAWSResult(resources=resources)
Пример #19
0
class OrgResourceSpec(OrganizationsResourceSpec):
    """Resource representing an AWS Org."""

    type_name = "organization"
    schema = Schema(ScalarField("MasterAccountId"),
                    ScalarField("MasterAccountEmail"))

    @classmethod
    def get_full_type_name(cls: Type["OrgResourceSpec"]) -> str:
        return f"{cls.provider_name}:{cls.type_name}"

    @classmethod
    def list_from_aws(cls: Type["OrgResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'org_1_arn': {org_1_dict},
             'org_2_arn': {org_2_dict},
             ...}

        Where the dicts represent results from describe_organization."""
        resp = client.describe_organization()
        org = resp["Organization"]
        orgs = {org["Arn"]: org}
        return ListFromAWSResult(resources=orgs)
Пример #20
0
class OUResourceSpec(OrganizationsResourceSpec):
    """Resource representing an AWS OU."""

    type_name = "ou"
    schema = Schema(
        ScalarField("Path"),
        ResourceLinkField("OrganizationArn", OrgResourceSpec,
                          value_is_id=True))

    @classmethod
    def get_full_type_name(cls: Type["OUResourceSpec"]) -> str:
        return f"{cls.provider_name}:{cls.type_name}"

    @classmethod
    def list_from_aws(cls: Type["OUResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'ou_1_arn': {ou_1_dict},
             'ou_2_arn': {ou_2_dict},
             ...}

        Where the dicts represent results from list_organizational_units_for_parent
        with some additional info 'Path') tagged on."""
        org_resp = client.describe_organization()
        org_arn = org_resp["Organization"]["Arn"]
        ous = {}
        paginator = client.get_paginator("list_roots")
        for resp in paginator.paginate():
            for root in resp["Roots"]:
                root_id, root_arn = root["Id"], root["Arn"]
                root_path = f"/{root['Name']}"
                ous[root_arn] = root
                ous[root_arn]["OrganizationArn"] = org_arn
                ous[root_arn]["Path"] = root_path
                ou_details = cls._recursively_get_ou_details_for_parent(
                    client=client, parent_id=root_id, parent_path=root_path)
                for ou_detail in ou_details:
                    arn = ou_detail["Arn"]
                    ou_detail["OrganizationArn"] = org_arn
                    ous[arn] = ou_detail
        return ListFromAWSResult(resources=ous)

    @classmethod
    def _recursively_get_ou_details_for_parent(
            cls: Type["OUResourceSpec"], client: BaseClient, parent_id: str,
            parent_path: str) -> List[Dict[str, Any]]:
        ous = []
        paginator = client.get_paginator(
            "list_organizational_units_for_parent")
        for resp in paginator.paginate(ParentId=parent_id):
            for ou in resp["OrganizationalUnits"]:
                ou_id = ou["Id"]
                path = f"{parent_path}/{ou['Name']}"
                ou["Path"] = path
                ous.append(ou)
                ous += cls._recursively_get_ou_details_for_parent(
                    client=client, parent_id=ou_id, parent_path=path)
        return ous
Пример #21
0
class EC2InstanceResourceSpec(EC2ResourceSpec):
    """Resource for EC2Instances"""

    type_name = "instance"
    schema = Schema(
        ScalarField("Name", optional=True),
        TransientResourceLinkField("ImageId", EC2ImageResourceSpec),
        ScalarField("KeyName", optional=True),
        AnonymousDictField("Placement", ScalarField("AvailabilityZone"), ScalarField("Tenancy")),
        ScalarField("InstanceType"),
        ScalarField("LaunchTime"),
        AnonymousDictField("State", ScalarField("Name", "state")),
        ScalarField("Platform", optional=True),
        ScalarField("PrivateIpAddress", optional=True),
        ScalarField("PrivateDnsName", optional=True),
        ScalarField("PublicIpAddress", optional=True),
        ScalarField("PublicDnsName", optional=True),
        ResourceLinkField("VpcId", VPCResourceSpec, optional=True),
        ResourceLinkField("SubnetId", SubnetResourceSpec, optional=True),
        AnonymousListField(
            "SecurityGroups",
            AnonymousEmbeddedDictField(ResourceLinkField("GroupId", SecurityGroupResourceSpec)),
        ),
        AnonymousDictField(
            "IamInstanceProfile",
            TransientResourceLinkField(
                "Arn", InstanceProfileResourceSpec, alti_key="instance_profile", value_is_id=True
            ),
            optional=True,
        ),
        TagsField(),
    )

    @classmethod
    def list_from_aws(
        cls: Type["EC2InstanceResourceSpec"], client: BaseClient, account_id: str, region: str
    ) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'instance_1_arn': {instance_1_dict},
             'instance_2_arn': {instance_2_dict},
             ...}

        Where the dicts represent results from describe_instances."""
        paginator = client.get_paginator("describe_instances")
        instances = {}
        for resp in paginator.paginate():
            for reservation in resp.get("Reservations", []):
                for instance in reservation.get("Instances", []):
                    resource_arn = cls.generate_arn(
                        account_id=account_id, region=region, resource_id=instance["InstanceId"]
                    )
                    instances[resource_arn] = instance
                    for tag in instance.get("Tags", []):
                        if tag["Key"].lower() == "name":
                            instance["Name"] = tag["Value"]
                            break
        return ListFromAWSResult(resources=instances)
class IAMPolicyResourceSpec(IAMResourceSpec):
    """Resource for user-managed IAM Policies"""

    type_name = "policy"
    parallel_scan = True
    schema = Schema(
        ScalarField("PolicyName", "name"),
        ScalarField("PolicyId"),
        ScalarField("DefaultVersionId"),
        ScalarField("DefaultVersionPolicyDocumentText"),
    )

    @classmethod
    def list_from_aws(cls: Type["IAMPolicyResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'role_1_arn': {role_1_dict},
             'role_2_arn': {role_2_dict},
             ...}

        Where the dicts represent results from list_policies and additional info per role from
        list_targets_by_role."""
        policies = {}
        paginator = client.get_paginator("list_policies")

        for resp in paginator.paginate(Scope="Local"):
            for policy in resp.get("Policies", []):
                resource_arn = policy["Arn"]
                default_policy_version = policy["DefaultVersionId"]
                try:
                    default_policy_version_document_text = cls.get_policy_version_document_text(
                        client=client,
                        policy_arn=resource_arn,
                        policy_version=default_policy_version,
                    )
                    policy[
                        "DefaultVersionPolicyDocumentText"] = policy_doc_dict_to_sorted_str(
                            default_policy_version_document_text)
                    policies[resource_arn] = policy
                except ClientError as c_e:
                    error_code = getattr(c_e, "response",
                                         {}).get("Error", {}).get("Code", {})
                    if error_code != "NoSuchEntity":
                        raise c_e

        return ListFromAWSResult(resources=policies)

    @classmethod
    def get_policy_version_document_text(
        cls: Type["IAMPolicyResourceSpec"],
        client: BaseClient,
        policy_arn: str,
        policy_version: str,
    ) -> Dict[str, Any]:
        policy_version_resp = client.get_policy_version(
            PolicyArn=policy_arn, VersionId=policy_version)
        return policy_version_resp["PolicyVersion"]["Document"]
Пример #23
0
 def test_parse(self):
     schema = Schema(ScalarField("Key1"), ScalarField("Key2"))
     data = {"Key1": "Value1", "Key2": "Value2"}
     links = schema.parse(data, {})
     expected_link_data = [
         {
             "pred": "key1",
             "obj": "Value1",
             "type": "simple"
         },
         {
             "pred": "key2",
             "obj": "Value2",
             "type": "simple"
         },
     ]
     link_data = [link.to_dict() for link in links]
     self.assertEqual(expected_link_data, link_data)
Пример #24
0
class LoadBalancerResourceSpec(ElasticLoadBalancingResourceSpec):
    """Resource for load balancer"""

    type_name = "loadbalancer"
    schema = Schema(
        ScalarField("DNSName"),
        ScalarField("CreatedTime"),
        ScalarField("LoadBalancerName"),
        ScalarField("Scheme"),
        ResourceLinkField("VpcId", VPCResourceSpec, optional=True),
        AnonymousDictField("State",
                           ScalarField("Code",
                                       alti_key="load_balancer_state")),
        ScalarField("Type"),
        ListField(
            "AvailabilityZones",
            EmbeddedDictField(
                ScalarField("ZoneName"),
                ResourceLinkField("SubnetId",
                                  SubnetResourceSpec,
                                  optional=True),
                ListField(
                    "LoadBalancerAddresses",
                    EmbeddedDictField(
                        ScalarField("IpAddress", optional=True),
                        ScalarField("AllocationId", optional=True),
                    ),
                    optional=True,
                ),
            ),
        ),
        ListField("SecurityGroups",
                  EmbeddedResourceLinkField(SecurityGroupResourceSpec),
                  optional=True),
        ScalarField("IpAddressType"),
    )

    @classmethod
    def list_from_aws(cls: Type["LoadBalancerResourceSpec"],
                      client: BaseClient, account_id: str,
                      region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'lb_1_arn': {lb_1_dict},
             'lb_2_arn': {lb_2_dict},
             ...}

        Where the dicts represent results from describe_load_balancers."""
        paginator = client.get_paginator("describe_load_balancers")
        load_balancers = {}
        for resp in paginator.paginate():
            for lb in resp.get("LoadBalancers", []):
                resource_arn = lb["LoadBalancerArn"]
                load_balancers[resource_arn] = lb
        return ListFromAWSResult(resources=load_balancers)
Пример #25
0
class RDSSnapshotResourceSpec(RDSResourceSpec):
    """Resource for RDS Snapshot"""

    type_name = "snapshot"
    schema = Schema(
        ScalarField("DBSnapshotIdentifier"),
        ScalarField("SnapshotCreateTime", optional=True),
        ScalarField("Engine"),
        ScalarField("AllocatedStorage"),
        ScalarField("Status"),
        TransientResourceLinkField("VpcId", VPCResourceSpec, optional=True),
        ScalarField("InstanceCreateTime"),
        ScalarField("SnapshotType"),
        ScalarField("PercentProgress"),
        ScalarField("Region", optional=True),
        ScalarField("Encrypted"),
        TransientResourceLinkField("KmsKeyID", KMSKeyResourceSpec, optional=True),
        ScalarField("Timezone", optional=True),
        ScalarField("IAMDatabaseAuthenticationEnabled"),
        TransientResourceLinkField("DBInstanceArn", RDSInstanceResourceSpec, value_is_id=True),
    )

    @classmethod
    def generate_instance_arn(
        cls: Type["RDSSnapshotResourceSpec"], account_id: str, region: str, resource_id: str
    ) -> str:
        """Generate an ARN for this resource, e.g. arn:aws:rds:<region>:<account>:db:<name>
        """
        return ":".join(
            (
                "arn",
                cls.provider_name,
                cls.service_name,
                region,
                account_id,
                cls.type_name,
                resource_id,
            )
        )

    @classmethod
    def list_from_aws(
        cls: Type["RDSSnapshotResourceSpec"], client: BaseClient, account_id: str, region: str
    ) -> ListFromAWSResult:
        dbinstances = {}
        paginator = client.get_paginator("describe_db_snapshots")
        for resp in paginator.paginate():
            for db in resp.get("DBSnapshots", []):
                resource_arn = db["DBSnapshotArn"]
                db["DBInstanceArn"] = cls.generate_instance_arn(
                    account_id, region, db["DBInstanceIdentifier"]
                )
                dbinstances[resource_arn] = db
        return ListFromAWSResult(resources=dbinstances)
class TestResourceSpec(ResourceSpec):
    type_name = "test_type_name"
    schema = Schema()

    @classmethod
    def scan(cls, scan_accessor: Any) -> List[Resource]:
        return []

    @classmethod
    def get_full_type_name(cls) -> str:
        return cls.type_name
Пример #27
0
class EC2NetworkInterfaceResourceSpec(EC2ResourceSpec):
    """Resource for EC2NetworkInterfaces"""

    # type_name = "network-interface"
    type_name = "network_interface"
    schema = Schema(
        AnonymousDictField(
            "Association",
            ScalarField("PublicDnsName", optional=True),
            ScalarField("PublicIp", optional=True),
            optional=True,
        ),
        ScalarField("Description"),
        ScalarField("InterfaceType"),
        ScalarField("MacAddress"),
        ScalarField("PrivateDnsName", optional=True),
        ScalarField("PrivateIpAddress", optional=True),
        ScalarField("Status"),
        ResourceLinkField("SubnetId", SubnetResourceSpec, optional=True),
        ResourceLinkField("VpcId", VPCResourceSpec, optional=True),
        AnonymousListField(
            "Groups",
            AnonymousEmbeddedDictField(
                ResourceLinkField("GroupId", SecurityGroupResourceSpec)),
        ),
    )

    @classmethod
    def list_from_aws(
        cls: Type["EC2NetworkInterfaceResourceSpec"],
        client: BaseClient,
        account_id: str,
        region: str,
    ) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'network_interface_1_arn': {network_interface_1_dict},
             'network_interface_2_arn': {network_interface_2_dict},
             ...}

        Where the dicts represent results from describe_network_interfaces."""
        paginator = client.get_paginator("describe_network_interfaces")
        interfaces = {}
        for resp in paginator.paginate():
            for interface in resp.get("NetworkInterfaces", []):
                resource_arn = cls.generate_arn(
                    account_id=account_id,
                    region=region,
                    resource_id=interface["NetworkInterfaceId"],
                )
                interfaces[resource_arn] = interface
        return ListFromAWSResult(resources=interfaces)
Пример #28
0
class TestResourceSpec(ResourceSpec):
    type_name = "test_type_name"
    schema = Schema()

    @classmethod
    def scan(cls, scan_accessor: Any) -> ResourceScanResult:
        return ResourceScanResult(resources=[],
                                  stats=MultilevelCounter(),
                                  errors=[])

    @classmethod
    def get_full_type_name(cls) -> str:
        return cls.type_name
class TransitGatewayResourceSpec(EC2ResourceSpec):
    """Resource for TransitGateways"""

    # type_name = "transit-gateway"
    type_name = "transit_gateway"
    schema = Schema(
        ScalarField("OwnerId"),
        ScalarField("State"),
        ListField(
            "VPCAttachments",
            EmbeddedDictField(
                ScalarField("CreationTime"),
                ScalarField("State"),
                ResourceLinkField("ResourceId", VPCResourceSpec),
            ),
            optional=True,
            alti_key="vpc_attachment",
        ),
        TagsField(),
    )

    @classmethod
    def list_from_aws(
        cls: Type["TransitGatewayResourceSpec"], client: BaseClient, account_id: str, region: str
    ) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'tgw_1_arn': {tgw_1_dict},
             'tgw_2_arn': {tgw_2_dict},
             ...}

        Where the dicts represent results from describe_transit_gateways."""
        tgws = {}
        paginator = client.get_paginator("describe_transit_gateways")
        tgw_filters = [{"Name": "owner-id", "Values": [account_id]}]
        for resp in paginator.paginate(Filters=tgw_filters):
            for tgw in resp["TransitGateways"]:
                resource_arn = tgw["TransitGatewayArn"]
                vpc_attachments: List[Dict[str, Any]] = []
                vpc_attachments_paginator = client.get_paginator(
                    "describe_transit_gateway_attachments"
                )
                vpc_filters = [
                    {"Name": "transit-gateway-id", "Values": [tgw["TransitGatewayId"]]},
                    {"Name": "resource-type", "Values": ["vpc"]},
                ]
                for vpc_attachments_resp in vpc_attachments_paginator.paginate(Filters=vpc_filters):
                    vpc_attachments += vpc_attachments_resp["TransitGatewayAttachments"]
                tgw["VPCAttachments"] = vpc_attachments
                tgws[resource_arn] = tgw
        return ListFromAWSResult(resources=tgws)
Пример #30
0
class IAMGroupResourceSpec(IAMResourceSpec):
    """Resource for IAM Groups"""

    type_name = "group"
    schema = Schema(
        ScalarField("GroupName", "name"),
        ScalarField("GroupId"),
        ScalarField("CreateDate"),
        AnonymousListField(
            "Users",
            AnonymousEmbeddedDictField(
                ResourceLinkField("Arn",
                                  IAMUserResourceSpec,
                                  value_is_id=True,
                                  alti_key="user")),
        ),
    )

    @classmethod
    def list_from_aws(cls: Type["IAMGroupResourceSpec"], client: BaseClient,
                      account_id: str, region: str) -> ListFromAWSResult:
        """Return a dict of dicts of the format:

            {'group_1_arn': {group_1_dict},
             'group_2_arn': {group_2_dict},
             ...}

        Where the dicts represent results from list_groups."""
        groups = {}
        paginator = client.get_paginator("list_groups")
        for resp in paginator.paginate():
            for group in resp.get("Groups", []):
                resource_arn = group["Arn"]
                try:
                    group["Users"] = cls.get_group_users(
                        client=client, group_name=group["GroupName"])
                    groups[resource_arn] = group
                except ClientError as c_e:
                    error_code = getattr(c_e, "response",
                                         {}).get("Error", {}).get("Code", {})
                    if error_code != "NoSuchEntity":
                        raise c_e
        return ListFromAWSResult(resources=groups)

    @classmethod
    def get_group_users(cls: Type["IAMGroupResourceSpec"], client: BaseClient,
                        group_name: str) -> List[Dict[str, Any]]:
        group_resp = client.get_group(GroupName=group_name)
        return group_resp["Users"]