Exemple #1
0
 def set_prometheus_endpoint(self):
     """
     Set a Managed Prometheus endpoint with full access and add it to
     private routes
     """
     sg_res = t_ec2.SecurityGroup(
         title=alphanum(f"{self.name}ApsVpcEndpointSG"),
         VpcId=Ref(self.vpc),
         GroupDescription="Used by Prometheus VPC Endpoint",
         SecurityGroupIngress=[
             t_ec2.SecurityGroupRule(IpProtocol="tcp",
                                     FromPort="443",
                                     ToPort="443",
                                     CidrIp="0.0.0.0/0")
         ],
     )
     self._r[sg_res.title] = sg_res
     res = t_ec2.VPCEndpoint(
         title=alphanum(f"{self.name}ApsVpcEndpoint"),
         VpcId=Ref(self.vpc),
         ServiceName=f"com.amazonaws.{self.region}.aps-workspaces",
         SubnetIds=[Ref(subnet) for subnet in self.gateway_subnets],
         SecurityGroupIds=[Ref(self._r[sg_res.title])],
         VpcEndpointType="Interface",
     )
     self._r[res.title] = res
Exemple #2
0
 def __init__(self, name: str, description: str = None):
     self.name = name
     self.clean_name = alphanum(name)
     self.description = description
     self.resources = dict()
     self.t_api = t_apigw2.Api(
         title=f"{self.clean_name}HTTPApi", ProtocolType="HTTP", Name=self.name,
     )
     if description is not None:
         self.t_api.Description = description
     self.resources[self.t_api.title] = self.t_api
Exemple #3
0
 def set_s3_endpoint(self):
     """Set an S3 endpoint with full access and add it to private routes"""
     res = t_ec2.VPCEndpoint(
         title=alphanum(f"{self.name}S3EndpointGateway"),
         VpcId=Ref(self.vpc),
         ServiceName=f"com.amazonaws.{self.region}.s3",
         RouteTableIds=[
             Ref(route_table) for route_table in self.natted_route_tables
         ],
     )
     if self.public_route_table is not None:
         res.RouteTableIds.append(Ref(self.public_route_table))
     self._r[res.title] = res
Exemple #4
0
def multiaz_subnets(
    name_prefix: str,
    cidr_block: str,
    region: str,
    vpc: object = None,
    vpc_id: str = None,
    no_of_subnets: int = 4,
    network_acl: object = None,
    network_acl_id: str = None,
    route_table: object = None,
    route_table_id: str = None,
) -> list:
    """Split given CIDR block into subnets over multiple AZs

    Either `vpc` or both `vpc_id` and `region`  are required.

    If a network ACL or route table are passed as parameters, they
    will be associated with the subnets.

    `vpc`, `network_acl` and `route_table` are expected to be
    Troposphere resource objects which can be passed to Ref and GetAtt
    functions. As an alternative, `vpc_id`, `region`, `network_acl_id`
    `route_table_id` can be passed directly. If both resource and *_id
    are specified, the *_id will take precedence.

    Returns a list of Troposphere resources that describes the subnets
    and can be attached to a Template object.

    Returned subnet objects have the following keys set in their
    Metadata attribute:
        az: full availability zone name ("eu-west-1a")
        az_index: uppercase AZ, without the region part ("A")
        suffix: the suffix that was added to the name to form a unique
            resource title. Probably a single digit.

    Args:
        name_prefix (str): Prefix each resource with this string. Use to
            assure unique name for the resource in the calling Template
        cidr_block (str): IP range to split into subnets
        region (str): AWS region
        vpc (object, optional): VPC Troposphere resource. One of vpc or
            vpc_id is required. Defaults to None.
        vpc_id (str, optional): VPC ID. One of vpc or vpc_id is
            required. Defaults to None.
        no_of_subnets (int, optional): Create this many subnets. must
            be a power of 2. Defaults to 4.
        network_acl (object, optional): Network ACL Troposphere
            resource. Defaults to None.
        network_acl_id (str, optional): Network ACL ID. Defaults to
            None.
        route_table (object, optional): Route table resource.
            Defaults to None.
        route_table_id (str, optional): Route table ID. Defaults to
            None.

    Raises:
        ValueError: If neither vpc nor vpc_id were specified.

    Returns:
        list: Troposphere resources to be added to Template.

    """
    if vpc is None and vpc_id is None:
        raise ValueError("One of vpc or vpc_id must be specified")
    if vpc_id is None:
        vpc_id = Ref(vpc)
    # Resource names only accept alphanumeric
    prefix = alphanum(name_prefix).lower().capitalize()
    net_split = split_net_across_zones(cidr_block, region, no_of_subnets)
    resources = list()
    for index, net_segment in enumerate(net_split):
        # set subnet
        az_index = net_segment["az"][-1:].upper()
        subnet = t_ec2.Subnet(
            title=f"{prefix}{index+1}",
            AvailabilityZone=net_segment["az"],
            CidrBlock=net_segment["cidr"],
            VpcId=vpc_id,
            Tags=[{
                "Key": "Name",
                "Value": f"{name_prefix} {az_index}"
            }],
        )
        subnet.Metadata = {}
        subnet.Metadata["az"] = net_segment["az"].lower()
        subnet.Metadata["az_index"] = az_index
        subnet.Metadata["suffix"] = index + 1
        resources.append(subnet)
        # associate network ACL with subnet
        if network_acl_id is None and network_acl is not None:
            network_acl_id = Ref(network_acl)
        if network_acl_id is not None:
            resources.append(
                t_ec2.SubnetNetworkAclAssociation(
                    title=f"{subnet.title}NaclAssociation",
                    SubnetId=Ref(subnet),
                    NetworkAclId=network_acl_id,
                ))
        if route_table_id is None and route_table is not None:
            route_table_id = Ref(route_table)
        if route_table_id is not None:
            resources.append(
                t_ec2.SubnetRouteTableAssociation(
                    title=f"{subnet.title}RouteAssociation",
                    SubnetId=Ref(subnet),
                    RouteTableId=route_table_id,
                ))
    return resources
Exemple #5
0
    def peer_with_another_vpc(
        self,
        peer_vpc_id: str,
        peer_vpc_name: str,
        peer_role_arn: str = None,
        peer_owner_id: str = None,
        peer_region: str = None,
        peer_cidrs: list = [],
        add_route_to_private_tables: bool = True,
        add_route_to_public_table: bool = True,
    ):
        """Set VPC Peering

        Args:
            peer_vpc_id (str): The ID of the VPC with which you are
                creating the VPC peering connection
            peer_vpc_name (str): A name for the peer VPC, used in
                the Name tag for the peering connection
            peer_role_arn (str, optional): VPC peer role for the
                peering connection in another AWS account.
                Required if peering with a different AWS account.
                Defaults to None.
            peer_owner_id (str, optional): Owner of the other AWS
                account, if any.
                Defaults to None.
            peer_region (str, optional): The Region code for the
                accepter VPC. Defaults to the same region as requester
                VPC.
            peer_cidrs: (list, optional): List of CIDR blocks used
                by the peer VPC. If non-empty and any add_route_*
                argument is set to true, a route entry will be added
                to the respective table pointing that CIDR block to
                the peered connection.
                Defaults to an empty list.
            add_route_to_private_tables (bool,optional): If True,
                add the peered VPC to the private routing tables.
                Defaults to True.
            add_route_to_public_tables (bool,optional): If True,
                add the peered VPC to the public routing table.
                Defaults to True.

        Notes:
          - For the peered VPC to be added to the routing tables,
            they must already exist when this method is called. That
            means subnets should be created before setting up
            VPC Connection Peering.
          - As of Jan 2022 CloudFormation can't enable DNS resolution
        """
        res = t_ec2.VPCPeeringConnection(
            title=alphanum(
                f"Peer{peer_vpc_name.capitalize()}With{self.name.capitalize()}"
            ),
            VpcId=Ref(self.vpc),
            PeerVpcId=peer_vpc_id,
            Tags=[{
                "Key": "Name",
                "Value": f"{peer_vpc_name} - {self.name}"
            }],
        )
        if peer_region is not None:
            res.PeerRegion = peer_region
        if peer_owner_id is not None:
            res.PeerOwnerId = peer_owner_id
        if peer_role_arn is not None:
            res.PeerRoleArn = peer_role_arn
        self._r[res.title] = res
        if add_route_to_private_tables:
            self.add_vpc_peering_to_private_tables(peer_cidrs=peer_cidrs,
                                                   vpc_peering_id=Ref(res))
        if add_route_to_public_table:
            self.add_vpc_peering_to_public_table(peer_cidrs=peer_cidrs,
                                                 vpc_peering_id=Ref(res))
Exemple #6
0
 def add_stage(
     self,
     name: str,
     auto_deploy: bool = False,
     log_format: str = "none",
     stage_variables: dict = {},
     description: str = None,
 ):
     # TODO:
     #   - DefaultRouteSettings (??)
     if log_format.lower() in ["none", "clf", "json", "xml", "csv"]:
         pass
     elif "$context.requestId" in log_format:
         pass
     else:
         raise ValueError(f"{log_format} is not a valid log format")
     # Create Troposphere resource
     api_stage = t_apigw2.Stage(
         title=f"{alphanum(name)}Stage", ApiId=Ref(self.t_api), StageName=name
     )
     # Set logging
     if log_format.lower() != "none":
         api_stage_log = t_apigw2.AccessLogSettings(
             DestinationArn=Join(
                 ":",
                 [
                     "arn",
                     "aws",
                     "logs",
                     Region,
                     AccountId,
                     f"{self.clean_name}HttpApi",
                     alphanum(name),
                 ],
             )
         )
         if log_format.lower() == "clf":
             api_stage_log.Format = '$context.identity.sourceIp - - [$context.requestTime] "$context.httpMethod $context.routeKey $context.protocol" $context.status $context.responseLength $context.requestId'  # noqa: E501
         elif log_format.lower() == "json":
             api_stage_log.Format = json.dumps(
                 {
                     "requestId": "$context.requestId",
                     "ip": "$context.identity.sourceIp",
                     "requestTime": "$context.requestTime",
                     "httpMethod": "$context.httpMethod",
                     "routeKey": "$context.routeKey",
                     "status": "$context.status",
                     "protocol": "$context.protocol",
                     "responseLength": "$context.responseLength",
                 }
             )
         elif log_format.lower() == "xml":
             api_stage_log.Format = '<request id="$context.requestId"> <ip>$context.identity.sourceIp</ip> <requestTime>$context.requestTime</requestTime> <httpMethod>$context.httpMethod</httpMethod> <routeKey>$context.routeKey</routeKey> <status>$context.status</status> <protocol>$context.protocol</protocol> <responseLength>$context.responseLength</responseLength> </request>'  # noqa: E501
         elif log_format.lower() == "csv":
             api_stage_log.Format = "$context.identity.sourceIp,$context.requestTime,$context.httpMethod,$context.routeKey,$context.protocol,$context.status,$context.responseLength,$context.requestId"  # noqa: E501
     api_stage.AutoDeploy = auto_deploy
     if description is not None:
         api_stage.Description = description
     if len(stage_variables) > 0:
         api_stage.StageVariables = stage_variables
     self.resources[api_stage.title] = api_stage