Example #1
0
class AwsInternetGateway(RouteTarget):
    def __init__(self, environment, physical_id, **kwargs):
        super().__init__("AWS::EC2::InternetGateway", environment, physical_id, **kwargs)

    @RouteTarget.capture_method
    def capture(self):
        ec2 = boto3.client("ec2")
        if self._source_data is None:
            source_data = ec2.describe_internet_gateways(InternetGatewayIds=[self._physical_id])["InternetGateways"][0]
        else:
            source_data = self._source_data
            self._source_data = None

        self._tags = TagSet({"CreatedBy": "CloudPrep"})
        self._tags.from_api_result(source_data["Tags"])
        vpc = self._route.route_table.vpc

        iga = AwsVpcGatewayAttachment(
            self._environment,
            vpc.physical_id + self.physical_id,
            vpc=vpc
        )
        iga.set_internet_gateway(self)
        VpcAttachmentRegistry.register_attachment(vpc, self, iga)

        self._environment.add_to_todo(iga)

        self.is_valid = True
Example #2
0
class AwsManagedPrefixList(AwsElement):
    def __init__(self, environment, physical_id, **kwargs):
        super().__init__(environment, "AWS::EC2::PrefixList", physical_id,
                         **kwargs)
        self._physical_id = physical_id
        self._tags = TagSet({"CreatedBy": "CloudPrep"})

    @AwsElement.capture_method
    def capture(self):
        ec2 = boto3.client("ec2")
        source_data = ec2.describe_managed_prefix_lists(
            PrefixListIds=[self._physical_id])["PrefixLists"][0]
        if source_data["OwnerId"] == "AWS":
            raise Exception("Prefix list " + self._physical_id +
                            " appears to be AWS-managed.")

        self.copy_if_exists("AddressFamily", source_data)
        self.copy_if_exists("MaxEntries", source_data)
        self.copy_if_exists("PrefixListName", source_data)
        self.copy_if_exists(
            "Entries",
            ec2.get_managed_prefix_list_entries(
                PrefixListId=self._physical_id))
        self._tags.from_api_result(source_data)

        self.is_valid = True
Example #3
0
 def __init__(self, environment, physical_id, **kwargs):
     super().__init__(environment, "AWS::EC2::Subnet", physical_id,
                      **kwargs)
     self.set_defaults({
         "AssignIpv6AddressOnCreation": False,
         "MapPublicIpOnLaunch": False
     })
     self._tags = TagSet({"CreatedBy": "CloudPrep"})
     self._route_table = None
Example #4
0
class AwsSubnet(AwsElement):
    def __init__(self, environment, physical_id, **kwargs):
        super().__init__(environment, "AWS::EC2::Subnet", physical_id,
                         **kwargs)
        self.set_defaults({
            "AssignIpv6AddressOnCreation": False,
            "MapPublicIpOnLaunch": False
        })
        self._tags = TagSet({"CreatedBy": "CloudPrep"})
        self._route_table = None

    @AwsElement.capture_method
    def capture(self):
        ec2 = boto3.client("ec2")
        if self._source_data is None:
            source_data = ec2.describe_subnets(
                SubnetIds=[self._physical_id])["Subnets"][0]
        else:
            source_data = self._source_data
            self._source_data = None

        self._element["AssignIpv6AddressOnCreation"] = source_data[
            "AssignIpv6AddressOnCreation"]
        self._element["AvailabilityZone"] = self.abstract_az(
            source_data["AvailabilityZone"])
        self._element["CidrBlock"] = source_data["CidrBlock"]
        self._element["MapPublicIpOnLaunch"] = source_data[
            "MapPublicIpOnLaunch"]

        if len(source_data["Ipv6CidrBlockAssociationSet"]) > 0:
            self._element["Ipv6CidrBlock"] = source_data[
                "Ipv6CidrBlockAssociationSet"][0]

        self.copy_if_exists("OutpostArn", source_data)

        self._element["VpcId"] = {
            "Ref":
            (self._environment.logical_from_physical(source_data["VpcId"]))
        }

        if "Tags" in source_data:
            self._tags.from_api_result(source_data["Tags"])

        self.is_valid = True

    def set_route_table(self, route_table):
        self._route_table = route_table

    def has_route_table(self):
        return self._route_table is not None

    @staticmethod
    def abstract_az(az_name):
        letter = az_name[-1]
        position = ord(letter) - ord('a')
        return {"Fn::Select": [position, {"Fn::GetAZs": ""}]}
Example #5
0
 def __init__(self, environment, physical_id, **kwargs):
     super().__init__(environment, "AWS::Lambda::Function", physical_id,
                      **kwargs)
     self.set_defaults({
         "Description": "",
         "MemorySize": 128,
         "ReservedConcurrentExecutions": 1000,
         "Timeout": 3
     })
     self._tags = TagSet({"CreatedBy": "CloudPrep"})
Example #6
0
 def __init__(self, environment, physical_id, **kwargs):
     super().__init__("AWS::EC2::TransitGateway", environment, physical_id, **kwargs)
     self.set_defaults({
         "AmazonSideAsn": 64512,
         "AutoAcceptSharedAttachments": "disable",
         "DefaultRouteTableAssociation": "enable",
         "DefaultRouteTablePropagation": "enable",
         "DnsSupport": "enable",
         "VpnEcmpSupport": "enable",
         "MulticastSupport": "disable"
     })
     self._tags = TagSet({"CreatedBy": "CloudPrep"})
Example #7
0
class AwsTransitGateway(RouteTarget):
    def __init__(self, environment, physical_id, **kwargs):
        super().__init__("AWS::EC2::TransitGateway", environment, physical_id, **kwargs)
        self.set_defaults({
            "AmazonSideAsn": 64512,
            "AutoAcceptSharedAttachments": "disable",
            "DefaultRouteTableAssociation": "enable",
            "DefaultRouteTablePropagation": "enable",
            "DnsSupport": "enable",
            "VpnEcmpSupport": "enable",
            "MulticastSupport": "disable"
        })
        self._tags = TagSet({"CreatedBy": "CloudPrep"})

    @RouteTarget.capture_method
    def capture(self):
        ec2 = boto3.client("ec2")
        source_data = ec2.describe_transit_gateways(TransitGatewayIds=[self._physical_id])["TransitGateways"][0]

        self.copy_if_exists("Description", source_data)
        self.copy_if_exists("AmazonSideAsn", source_data["Options"])
        self.copy_if_exists("AutoAcceptSharedAttachments", source_data["Options"])
        self.copy_if_exists("DefaultRouteTableAssociation", source_data["Options"])
        self.copy_if_exists("DefaultRouteTablePropagation", source_data["Options"])
        # TODO: If Multicast is true, capture the domain and the attachment (then spider!)
        self.copy_if_exists("MulticastSupport", source_data["Options"])
        self.copy_if_exists("VpnEcmpSupport", source_data["Options"])
        self.copy_if_exists("DnsSupport", source_data["Options"])

        self._tags.from_api_result(source_data)

        # TODO: Capture TGW Routes and Route Tables.

        attachments = ec2.describe_transit_gateway_vpc_attachments()["TransitGatewayVpcAttachments"]
        for attachment in [x for x in attachments if x["TransitGatewayId"] == self.physical_id]:
            tgva = AwsTransitGatewayVpcAttachment(
                self._environment,
                attachment["TransitGatewayAttachmentId"],
                source_data=attachment
            )
            self._environment.add_to_todo(tgva)

            VpcAttachmentRegistry.register_attachment(self._route.route_table.vpc, self, tgva)

        self.is_valid = True
Example #8
0
class AwsSecurityGroup(AwsElement):
    def __init__(self, environment, physical_id, **kwargs):
        super().__init__(environment, "AWS::EC2::SecurityGroup", physical_id,
                         **kwargs)
        self._physical_id = physical_id
        self._tags = TagSet({"CreatedBy": "CloudPrep"})

    @AwsElement.capture_method
    def capture(self):
        ec2 = boto3.client("ec2")
        if self._source_data is None:
            source_data = ec2.describe_security_groups(
                GroupIds=[self._physical_id])["SecurityGroups"][0]
        else:
            source_data = self._source_data
            self._source_data = None

        self._element["GroupDescription"] = source_data["Description"]
        self._element["VpcId"] = self._environment.find_by_physical_id(
            source_data["VpcId"]).make_reference()

        if source_data["GroupName"] == "default":
            self._element["GroupName"] = "was-default"
        else:
            self._element["GroupName"] = source_data["GroupName"]

        if "Tags" in source_data:
            self._tags.from_api_result(source_data)

        ingress_rules = IngressRuleset(self._environment, self)
        ingress_rules.process(source_data["OwnerId"],
                              source_data["IpPermissions"])
        self._element["SecurityGroupIngress"] = ingress_rules.data

        egress_rules = EgressRuleset(self._environment, self)
        egress_rules.process(source_data["OwnerId"],
                             source_data["IpPermissionsEgress"])
        self._element["SecurityGroupEgress"] = egress_rules.data

        self.is_valid = True
Example #9
0
class AwsLambdaFunction(AwsElement):
    def __init__(self, environment, physical_id, **kwargs):
        super().__init__(environment, "AWS::Lambda::Function", physical_id,
                         **kwargs)
        self.set_defaults({
            "Description": "",
            "MemorySize": 128,
            "ReservedConcurrentExecutions": 1000,
            "Timeout": 3
        })
        self._tags = TagSet({"CreatedBy": "CloudPrep"})

    @AwsElement.capture_method
    def capture(self):
        # {
        #   "Type" : "AWS::Lambda::Function",
        #   "Properties" : {
        #       *"Code" : Code,
        #       "CodeSigningConfigArn" : String,
        #       "DeadLetterConfig" : DeadLetterConfig,
        #       "FileSystemConfigs" : [ FileSystemConfig, ... ],
        #       "ImageConfig" : ImageConfig,
        #       "KmsKeyArn" : String,
        #       "Layers" : [ String, ... ],
        #       "PackageType" : String,
        #       "TracingConfig" : TracingConfig,
        #       "VpcConfig" : VpcConfig
        #     }
        # }
        lmb = boto3.client("lambda")
        source_data = lmb.get_function(FunctionName=self.physical_id)
        configuration = source_data["Configuration"]
        self._source_data = None

        self.copy_if_exists("Description", configuration)
        self.copy_if_exists("Environment", configuration)
        self.copy_if_exists("Handler", configuration)
        self.copy_if_exists("MemorySize", configuration)
        self.copy_if_exists("Runtime", configuration)
        self.copy_if_exists("Timeout", configuration)

        role = AwsRole(self._environment, AwsARN(configuration["Role"]))
        self._element["Role"] = role.make_getatt("Arn")
        self._environment.add_to_todo(role)

        self._tags.from_api_result(source_data)

        if "Concurrency" in source_data:
            self.copy_if_exists("ReservedConcurrentExecutions",
                                source_data["Concurrency"])

        # Code. This is complex.
        if source_data["Code"]["RepositoryType"] == "S3":
            self._code_s3(source_data["Code"])

        self.is_valid = True

    def create_from_arn(environment, arn: AwsARN, **kwargs):
        return AwsLambdaFunction(environment, arn.resource_id, **kwargs)

    def _code_s3(self, code_data):
        code_request = requests.get(code_data["Location"])
        if code_request.status_code != 200:
            raise Exception("Couldn't download code bundle from " +
                            code_data["Location"])

        afr = ArtefactRepository.get_repository()
        code_artefact = Artefact("lambda-" + self.logical_id + "-code.zip",
                                 code_request.content)
        afr.store_artefact(code_artefact)

        self._environment.add_parameter(
            Name="ArtefactBucket",
            Description="The bucket in which our artefacts are stored.")
        self._environment.add_parameter(Name=self.logical_id + "CodeKey",
                                        Description="The key for the " +
                                        self.logical_id +
                                        " lambda code package.",
                                        Default=code_artefact.name)
        self._element["Code"] = {
            "S3Bucket": {
                "Ref": "ArtefactBucket"
            },
            "S3Key": {
                "Ref": self.logical_id + "CodeKey"
            }
        }
Example #10
0
 def __init__(self, environment, physical_id, **kwargs):
     super().__init__(environment, "AWS::EC2::SimpleElement", physical_id,
                      kwargs)
     self.set_defaults({})
     self._tags = TagSet({"CreatedBy": "CloudPrep"})
Example #11
0
 def __init__(self, environment, physical_id, **kwargs):
     super().__init__(environment, "AWS::EC2::RouteTable", physical_id, **kwargs)
     self._tags = TagSet({"CreatedBy": "CloudPrep"})
     self._vpc = kwargs["vpc"]
     self._has_associations = False
     self._routes = []
Example #12
0
class AwsRouteTable(AwsElement):
    def __init__(self, environment, physical_id, **kwargs):
        super().__init__(environment, "AWS::EC2::RouteTable", physical_id, **kwargs)
        self._tags = TagSet({"CreatedBy": "CloudPrep"})
        self._vpc = kwargs["vpc"]
        self._has_associations = False
        self._routes = []

    @AwsElement.capture_method
    def capture(self):
        ec2 = boto3.client("ec2")
        self._source_data = None
        if self._source_data is None:
            source_data = ec2.describe_route_tables(RouteTableIds=[self._physical_id])["RouteTables"][0]
        else:
            source_data = self._source_data
            self._source_data = None

        self._element["VpcId"] = self.vpc.make_reference()
        self._tags.from_api_result(source_data)

        # All the subnets!
        for association in source_data["Associations"]:
            # Is this the Main route table?
            if association["Main"]:
                self._vpc.set_main_route_table(self)
                self._tags.add_tag("cloudprep:wasMain", "True")
            else:
                self.associate_with_subnet(association["SubnetId"])

        for i, route in zip(range(len(source_data["Routes"])), source_data["Routes"]):
            rt = AwsRoute(self._environment, self._physical_id + "-route" + str(i), source_data=route, route_table=self)
            self._routes.append(rt)
            self._environment.add_to_todo(rt)

        self.is_valid = True

    @property
    def vpc(self):
        return self._vpc

    def associate_with_subnet(self, subnet_id):
        assoc = AwsSubnetRouteTableAssociation(
            self._environment,
            self._physical_id + "-" + subnet_id,
            self,
            subnet_id
        )
        self._environment.add_to_todo(assoc)
        self._has_associations = True

    @AwsElement.finalise_method
    def finalise(self):
        more_work = False

        # If we have no associations, we might not need to be here =)
        if not self._has_associations and str(self._tags.get_tag("cloudprep:forceCapture")).upper() != "TRUE":
            self.is_valid = False

            for route in self._routes:
                route.is_valid = False

            return

        # Find those that depend on a TGW and add the explicit dependency
        # vpc_id = self.vpc.logical_id
        # for route in self._routes:
        #     if "TransitGatewayId" in route.properties:
        #         tga = VpcAttachmentRegistry.get_attachment(
        #             vpc_logical_id=vpc_id,
        #             subject_logical_id=route.properties["TransitGatewayId"]["Ref"]
        #         )
        #
        #         if tga is None:
        #             # We get here because we have multiple VPCs pointing at a single TGW.  One of those probably
        #             # caused the TGW to be made, but it hasn't yet been linked everywhere.
        #
        #             tgw = self._environment.find_by_logical_id(route.properties["TransitGatewayId"]["Ref"])
        #             tga = AwsTransitGatewayVpcAttachment(self._environment, tgw.physical_id + "attach" + vpc_id, route=route)
        #             print("VPC Logical ID =", vpc_id,file=sys.stderr)
        #             print("TGW Logical ID =", tgw.logical_id,file=sys.stderr)
        #             print("TGA Logical ID =", tga.logical_id,file=sys.stderr)
        #             self._environment.add_to_todo(tga)
        #
        #             VpcAttachmentRegistry.register_attachment(self.vpc, tgw, tga)
        #
        #             more_work = True
        #         else:
        #             route.add_dependency(tga.logical_id)

        return more_work
 def __init__(self, environment, physical_id, **kwargs):
     super().__init__(environment, "AWS::EC2::TransitGatewayAttachment",
                      physical_id, **kwargs)
     self.set_defaults({})
     self._tags = TagSet({"CreatedBy": "CloudPrep"})
Example #14
0
 def __init__(self, environment, physical_id, **kwargs):
     super().__init__(environment, "AWS::EC2::PrefixList", physical_id,
                      **kwargs)
     self._physical_id = physical_id
     self._tags = TagSet({"CreatedBy": "CloudPrep"})