Exemple #1
0
def create_as_nat_gateway(subnets, public, awscfg, ngfw, queue):

    vpc = VpcConfiguration(subnets[0].vpc.id).load()
    ngfw = NGFWConfiguration(**ngfw)

    logger.info('Creating NGFW as a NAT Gateway in availability zone: {} with '
                'subnets: {}'.format(subnets[0].availability_zone, subnets))

    try:
        # Create public side network for interface 0 using the /28 network space
        vpc.create_network_interface(
            0,
            cidr_block=public,
            availability_zone=subnets[0].availability_zone,
            description='stonesoft-public')

        # Change route tables of any subnets specified to use NAT Gateway
        interface = [intf.get(0) for intf in vpc.network_interface][0]
        for subnet in subnets:
            vpc.assign_route_table(subnet, interface)
        ngfw_init = deploy(vpc, ngfw, awscfg)
        task_runner(ngfw_init, queue)

    except (botocore.exceptions.ClientError, CreateEngineFailed,
            NodeCommandFailed) as e:
        logger.error('Caught exception, rolling back: {}'.format(e))
        queue.put(('{}, {}:'.format(subnets[0].availability_zone,
                                    subnets), [str(e)]))
        rollback_existing_vpc(vpc, subnets)
        if ngfw.engine:
            del_fw_from_smc([ngfw.name])
Exemple #2
0
def create_vpc_and_ngfw(awscfg, ngfw):
    '''
    Use Case 1: Create entire VPC and deploy NGFW
    ---------------------------------------------
    This will fully create a VPC and associated requirements. 
    The following will occur:
    * A new VPC will be created in the AZ based on boto3 client region
    * Two network subnets are created in the VPC, one public and one private
    * Two network interfaces are created and assigned to the subnets
      eth0 = public, eth1 = private
    * An elastic IP is created and attached to the public network interface
    * An internet gateway is created and attached to the public network interface
    * A route is created in the default route table for the public interface to
      route 0.0.0.0/0 to the IGW
    * The default security group is modified to allow inbound access from 0.0.0.0/0
      to to the NGFW network interface
      :py:func:`VpcConfiguration.authorize_security_group_ingress`
    * A secondary route table is created with a default route to 0.0.0.0/0 with a next
      hop assigned to interface eth1 (NGFW). This is attached to the private subnet.
    * The NGFW is automatically created and UserData is obtained for AMI instance launch
    * AMI is launched using UserData to allow auto-connection to NGFW SMC Management
    * NGFW receives queued policy and becomes active
    '''
    vpc = VpcConfiguration.create(vpc_subnet=awscfg.vpc_subnet)
    ngfw = NGFWConfiguration(**ngfw)

    try:
        vpc.create_network_interface(0,
                                     awscfg.vpc_public,
                                     description='public-ngfw')
        vpc.create_network_interface(1,
                                     awscfg.vpc_private,
                                     description='private-ngfw')
        vpc.security_group = create_security_group(vpc.vpc, 'stonesoft-sg')
        authorize_security_group_ingress(vpc.security_group,
                                         '0.0.0.0/0',
                                         ip_protocol='-1')

        # If user wants a client AMI, launch in the background
        if awscfg.aws_client_ami:
            logger.info('Launching client AMI with id: {}'.format(
                awscfg.aws_client_ami))
            ngfw.aws_ami_ip = spin_up_host(awscfg.aws_keypair, vpc,
                                           awscfg.aws_client_ami)

        ngfw_init = deploy(vpc, ngfw, awscfg)
        return task_runner(ngfw_init)

    except (botocore.exceptions.ClientError, CreateEngineFailed,
            NodeCommandFailed) as e:
        logger.error('Caught exception, rolling back: {}'.format(e))
        rollback(vpc.vpc)
        if ngfw.engine:
            del_fw_from_smc([ngfw.name])
        return [('Failed deploying VPC', [str(e)])]
Exemple #3
0
def rollback(vpc):
    """ 
    In case of failure, convenience to wrap in try/except and remove
    the VPC. If there is a running EC2 instance, this will terminate
    that instance, remove all other dependencies and delete the VPC.
    This will only rollback a VPC that has the stonesoft tag.
    
    :param ec2.Vpc vpc: vpc reference
    """
    try:
        if vpc.tags:
            has_tag = any(tag for tag in vpc.tags
                          if tag.get('Key') == 'stonesoft')
            if not has_tag:
                raise VpcConfigurationError
        else:
            raise VpcConfigurationError
    except VpcConfigurationError:
        raise VpcConfigurationError(
            'Stonesoft tag not found, cannot delete VPC.')

    instance_ids = []
    for instance in vpc.instances.filter(
            Filters=[{
                'Name': 'instance-state-name',
                'Values': ['running', 'pending', 'stopped']
            }]):
        logger.info("Terminating instance: {}".format(instance.instance_id))
        instance_ids.append(instance.instance_id)
        instance.terminate()
    waiter = ec2.meta.client.get_waiter('instance_terminated')
    waiter.wait(InstanceIds=instance_ids)
    # Network interfaces
    for intf in vpc.network_interfaces.all():
        intf.delete()
    # Subnets
    for subnet in vpc.subnets.all():
        subnet.delete()
    # Dump route tables
    for rt in vpc.route_tables.all():
        if not rt.associations_attribute:
            rt.delete()
        else:
            for current in rt.associations_attribute:
                if not current or current.get('Main') is False:
                    rt.delete()
    # Internet gateway
    for igw in vpc.internet_gateways.all():
        igw.detach_from_vpc(VpcId=vpc.vpc_id)
        igw.delete()
    # Delete security group
    try:
        grp = list(
            vpc.security_groups.filter(Filters=[{
                'Name': 'group-name',
                'Values': ['stonesoft-sg']
            }]))
        if grp:
            grp[0].delete()
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == 'InvalidGroup.NotFound':
            pass
        else:
            raise

    vpc.delete()
    logger.info("Deleted vpc: {}".format(vpc.vpc_id))
    del_fw_from_smc(instance_ids)
Exemple #4
0
def remove_ngfw_from_vpc(instances):
    """
    Remove only Stonesoft NGFW and related elements.
    Tags are used on subnets, route tables and instances to find stonesoft
    related components and stop in the right order. When route tables are 
    removed, existing subnets will revert to using the Main route table.
    
    :param list ec2.Instance: call from select_instance(list_tagged_instances)
    """
    if not instances: return

    vpc = instances[0].vpc

    logger.info('Remove instances: {}'.format(instances))

    # Subnet's are last to be removed
    removeables = []

    tagged_subnets = [tagged.id for tagged in list_tagged_subnets(vpc)]
    all_subnets = [untagged.id for untagged in list_all_subnets(vpc)]
    # Used to disassociate existing subnet route table
    untagged_subnets = list(set(all_subnets) - set(tagged_subnets))

    for instance in instances:

        for dependency in instance.network_interfaces:
            dependency.modify_attribute(
                Attachment={
                    'AttachmentId': dependency.attachment['AttachmentId'],
                    'DeleteOnTermination': True
                })

            subnet = dependency.subnet_id
            if subnet in tagged_subnets:
                removeables.append(subnet)

        logger.info('Terminating instance: {}'.format(instance.instance_id))
        instance.terminate()

    # Remove association of route tables created before deleting them. If an existing
    # subnet had a previous route table assigned, it will be reassigned.
    for rt in list_tagged_rtables(vpc):
        if rt.associations:
            for assoc in rt.associations.all():
                if assoc.subnet_id in untagged_subnets:
                    logger.info(
                        'Removing route tbl assoc: {} for subnet: {}'.format(
                            assoc.route_table_id, assoc.subnet_id))
                    assoc.delete()
                    # If stonesoft tag value exists with a previous route table
                    # association, re-map it
                    if rt.tags[0]['Value']:
                        logger.info(
                            'Reassociating subnet: {} with original route '
                            'table: {}'.format(assoc.subnet_id,
                                               rt.tags[0]['Value']))
                        try:
                            original_rt = ec2.RouteTable(rt.tags[0]['Value'])
                            original_rt.associate_with_subnet(
                                SubnetId=assoc.subnet_id)
                        except botocore.exceptions.ClientError as e:
                            logger.error(
                                'Error reassigning route table. Will default back '
                                'to main route table: {}'.format(e))
                    rt.delete()
        else:
            rt.delete()

    instance_ids = [ec2_instance.id for ec2_instance in instances]

    waiter = ec2.meta.client.get_waiter('instance_terminated')
    logger.info(
        'Waiting for instances to fully terminate...This can take a few minutes.'
    )
    waiter.wait(InstanceIds=instance_ids)
    # Remove after instance termination
    for subnet in removeables:
        ec2.Subnet(subnet).delete()

    del_fw_from_smc(instance_ids)

    logger.info('Completed successfully.')
Exemple #5
0
def create_inline_ngfw(subnets, public, awscfg, ngfw, queue):
    '''
    Use Case 2: Deploy NGFW into existing VPC
    -----------------------------------------
    This assumes the following:
    * You have an existing VPC with one or more subnets
    * Available elastic IP per NGFW
    * Available /28 subnets in VPC network, one for each AZ NGFW
    
    When NGFW is injected into an existing VPC, the deployment strategy will
    obtain the defined network address space for the VPC. It will create a 
    'private' supernet using a /28 subnet on the uppermost side of the VPC
    network. For example, a VPC network of 172.16.0.0/16 will result in a 
    new subnet created 172.31.255.240/28. This will act as the 'public' side of
    the NGFW (creating a small subnet prevents wasted address space). This public
    side network will use the "Main" route table that should already use the
    AWS Internet Gateway as it's next hop, allowing internet connectivity.
    Next, each a network interface will be created in each subnet that exists in
    the VPC. AWS will assign an address during interface creation which will be 
    assigned to the NGFW on that subnet segment. In addition, a new route table 
    will be created for each subnet and direct 0.0.0.0/0 to the NGFW network 
    interface previously created. This results in each subnet having the NGFW as
    it's gateway for outbound traffic.
    
    .. note:: Each subnet must be in the same AZ, which is why it is necessary to
              create a unique /28 for each subnet if spread across AZ's.
              
    http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html
    
    :param list ec2.Subnet subnets: subnets to inject ngfw
    :param str public: public network for ngfw instance
    :param AWSConfig awscfg: aws config
    :param dict ngfw: ngfw configuration
    :param Queue queue: reference to result queue
    '''
    vpc = VpcConfiguration(subnets[0].vpc.id).load()
    ngfw = NGFWConfiguration(**ngfw)

    logger.info(
        'Creating NGFW as Inline Gateway in availability zone: {} with '
        'subnets: {}'.format(subnets[0].availability_zone, subnets))

    try:
        # Create public side network for interface 0 using the /28 network space
        vpc.create_network_interface(
            0,
            cidr_block=public,
            availability_zone=subnets[0].availability_zone,
            description='stonesoft-public')

        # Each ec2 Subnet gets it's own network interface and route table
        intf = 1
        for subnet in subnets:
            vpc.create_network_interface(intf,
                                         ec2_subnet=subnet,
                                         description='stonesoft-private')
            intf += 1

        ngfw_init = deploy(vpc, ngfw, awscfg)
        task_runner(ngfw_init, queue)

    except (botocore.exceptions.ClientError, CreateEngineFailed,
            NodeCommandFailed) as e:
        logger.error('Caught exception, rolling back: {}'.format(e))
        queue.put(('{}, {}:'.format(subnets[0].availability_zone,
                                    subnets), [str(e)]))
        rollback_existing_vpc(vpc, subnets)
        if ngfw.engine:
            del_fw_from_smc([ngfw.name])