def add_egress(self, receiver, port): """ Add an egress rule to this SecurityEnabledObject evaluating if it is a Security group or CIDR tuple ([0] = title, [1] = ip) Creates a Troposphere SecurityGroupEgress object AWS Cloud Formation: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-security-group-egress.html Troposphere link: https://github.com/cloudtools/troposphere/blob/master/troposphere/ec2.py :param receiver: The SecurityEnabledObject that will be receiving traffic to this SecurityEnabledObject receiver[0] = title, receiver[1] = ip :param port: Port to send, and receive traffic on """ receiver_title = receiver.title if hasattr(receiver, 'title') else receiver['name'] if port == '-1': common = {'IpProtocol': 'tcp', 'FromPort': '0', 'ToPort': '65535', 'GroupId': self.security_group} name = self.title + 'AllTo' + receiver_title + 'All' else: common = {'IpProtocol': 'tcp', 'FromPort': port, 'ToPort': port, 'GroupId': self.security_group} name = self.title + port + 'To' + receiver_title + port egress = self.template.add_resource(ec2.SecurityGroupEgress(get_cf_friendly_name(name), **common)) if isinstance(receiver, SecurityEnabledObject): egress.DestinationSecurityGroupId = receiver.security_group else: egress.CidrIp = receiver['cidr'] self.egress.append(egress)
def create_simple_scaling_policy(self, scaling_policy_config): """ Simple scaling policy based upon ec2 metrics heavy-load cpu > 45 for 1 period of 300 seconds add two instances, 45 second cooldown light-load cpu <= 15 for 6 periods of 300 seconds remove one instance, 120 second cooldown medium-load cpu >= 25 for 1 period of 300 seconds add one instance, 45 second cooldown [name] [metric_name] [comparison_operator] [threshold] [evaluation_periods] [period] [scaling_adjustment] [cooldown] https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-alarm.html https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-policy.html :param scaling_policy_config: simple scaling policy config object """ cf_name = self.trop_asg.title + get_cf_friendly_name(scaling_policy_config.name) scaling_policy = self.template.add_resource(ScalingPolicy( title=cf_name + 'Sp', AdjustmentType='ChangeInCapacity', AutoScalingGroupName=Ref(self.trop_asg), Cooldown=scaling_policy_config.cooldown, ScalingAdjustment=scaling_policy_config.scaling_adjustment, )) self.scaling_polices.append(scaling_policy) self.cw_alarms.append(self.template.add_resource(Alarm( title=cf_name + 'Cwa', AlarmActions=[Ref(scaling_policy), self.network_config.sns_topic], AlarmDescription=scaling_policy_config.description, AlarmName=cf_name, ComparisonOperator=scaling_policy_config.comparison_operator, Dimensions=[MetricDimension( Name='AutoScalingGroupName', Value=Ref(self.trop_asg) )], EvaluationPeriods=scaling_policy_config.evaluation_periods, MetricName=scaling_policy_config.metric_name, Namespace='AWS/EC2', Period=scaling_policy_config.period, Statistic='Average', Threshold=scaling_policy_config.threshold, OKActions=[self.network_config.sns_topic] )))
def test_highly_available_nat_stack(): """ Test for nat gateway configuration""" stack = create_stack(nat_highly_available=True) assert_equals(stack.code_deploy_service_role, code_deploy_service_role) assert_equals(stack.keypair, keypair) assert_equals(stack.availability_zones, availability_zones) assert_equals(stack.vpc_cidr, vpc_cidr) [ assert_equals(stack.home_cidrs[num], home_cidrs[num]) for num in range(len(home_cidrs)) ] assert_equals(stack.public_cidr, {'name': 'PublicIp', 'cidr': '0.0.0.0/0'}) assert_equals(stack.internet_gateway.title, 'Ig') assert_is(type(stack.internet_gateway.Tags), Tags) assert_equals(stack.gateway_attachment.title, 'IgAtch') assert_is(type(stack.gateway_attachment.VpcId), Ref) assert_is(type(stack.gateway_attachment.InternetGatewayId), Ref) assert_equals(stack.public_route_table.title, 'PubRouteTable') assert_is(type(stack.public_route_table.VpcId), Ref) assert_is(type(stack.public_route_table.Tags), Tags) for az in availability_zones: assert_equals(stack.private_route_tables[az].title, get_cf_friendly_name(az) + 'PriRouteTable') assert_is(type(stack.private_route_tables[az].VpcId), Ref) assert_is(type(stack.private_route_tables[az].Tags), Tags) assert_equals(len(stack.nat_gateways), len(availability_zones)) assert_equals(stack.jump.single.SourceDestCheck, 'true') for num in range(len(availability_zones)): # For public subnets public_subnet = stack.public_subnets[num] assert_equals(public_subnet.CidrBlock, ''.join(['10.0.', str(num), '.0/24'])) # For private subnets private_subnet = stack.private_subnets[num] assert_equals(private_subnet.CidrBlock, ''.join(['10.0.', str(num + 100), '.0/24'])) assert_equals(len(stack.units), 7)
def test_tree(): """ Test stack structure """ tee = create_tree() assert_equals(tee.keypair, keypair) assert_equals(tee.availability_zones, availability_zones) assert_equals(tee.vpc_cidr, vpc_cidr) [ assert_equals(tee.home_cidrs[num], home_cidrs[num]) for num in range(len(home_cidrs)) ] assert_equals(tee.public_cidr, {'name': 'PublicIp', 'cidr': '0.0.0.0/0'}) assert_equals(tee.internet_gateway.title, 'Ig') assert_is(type(tee.internet_gateway.Tags), Tags) assert_equals(tee.gateway_attachment.title, 'IgAtch') assert_is(type(tee.gateway_attachment.VpcId), Ref) assert_is(type(tee.gateway_attachment.InternetGatewayId), Ref) assert_equals(tee.public_route_table.title, 'PubRouteTable') assert_is(type(tee.public_route_table.VpcId), Ref) assert_is(type(tee.public_route_table.Tags), Tags) for az in availability_zones: assert_equals(tee.private_route_tables[az].title, get_cf_friendly_name(az) + 'PriRouteTable') assert_is(type(tee.private_route_tables[az].VpcId), Ref) assert_is(type(tee.private_route_tables[az].Tags), Tags) assert_equals(tee.nat.single.SourceDestCheck, 'false') assert_equals(tee.jump.single.SourceDestCheck, 'true') for num in range(len(availability_zones)): # For public subnets public_subnet = tee.public_subnets[num] assert_equals(public_subnet.CidrBlock, ''.join(['10.0.', str(num), '.0/24'])) # For private subnets private_subnet = tee.private_subnets[num] assert_equals(private_subnet.CidrBlock, ''.join(['10.0.', str(num + 100), '.0/24']))
def test_highly_available_nat_stack(): """ Test for nat gateway configuration""" stack = create_stack(nat_highly_available=True) assert_equals(stack.code_deploy_service_role, code_deploy_service_role) assert_equals(stack.keypair, keypair) assert_equals(stack.availability_zones, availability_zones) assert_equals(stack.vpc_cidr, vpc_cidr) [assert_equals(stack.home_cidrs[num], home_cidrs[num]) for num in range(len(home_cidrs))] assert_equals(stack.public_cidr, {'name': 'PublicIp', 'cidr': '0.0.0.0/0'}) assert_equals(stack.internet_gateway.title, 'Ig') assert_is(type(stack.internet_gateway.Tags), Tags) assert_equals(stack.gateway_attachment.title, 'IgAtch') assert_is(type(stack.gateway_attachment.VpcId), Ref) assert_is(type(stack.gateway_attachment.InternetGatewayId), Ref) assert_equals(stack.public_route_table.title, 'PubRouteTable') assert_is(type(stack.public_route_table.VpcId), Ref) assert_is(type(stack.public_route_table.Tags), Tags) for az in availability_zones: assert_equals(stack.private_route_tables[az].title, get_cf_friendly_name(az) + 'PriRouteTable') assert_is(type(stack.private_route_tables[az].VpcId), Ref) assert_is(type(stack.private_route_tables[az].Tags), Tags) assert_equals(len(stack.nat_gateways), len(availability_zones)) assert_equals(stack.jump.single.SourceDestCheck, 'true') for num in range(len(availability_zones)): # For public subnets public_subnet = stack.public_subnets[num] assert_equals(public_subnet.CidrBlock, ''.join(['10.0.', str(num), '.0/24'])) # For private subnets private_subnet = stack.private_subnets[num] assert_equals(private_subnet.CidrBlock, ''.join(['10.0.', str(num + 100), '.0/24'])) assert_equals(len(stack.units), 7)
def test_tree(): """ Test stack structure """ tee = create_tree() assert_equals(tee.keypair, keypair) assert_equals(tee.availability_zones, availability_zones) assert_equals(tee.vpc_cidr, vpc_cidr) [assert_equals(tee.home_cidrs[num], home_cidrs[num]) for num in range(len(home_cidrs))] assert_equals(tee.public_cidr, {'name': 'PublicIp', 'cidr': '0.0.0.0/0'}) assert_equals(tee.internet_gateway.title, 'Ig') assert_is(type(tee.internet_gateway.Tags), Tags) assert_equals(tee.gateway_attachment.title, 'IgAtch') assert_is(type(tee.gateway_attachment.VpcId), Ref) assert_is(type(tee.gateway_attachment.InternetGatewayId), Ref) assert_equals(tee.public_route_table.title, 'PubRouteTable') assert_is(type(tee.public_route_table.VpcId), Ref) assert_is(type(tee.public_route_table.Tags), Tags) for az in availability_zones: assert_equals(tee.private_route_tables[az].title, get_cf_friendly_name(az) + 'PriRouteTable') assert_is(type(tee.private_route_tables[az].VpcId), Ref) assert_is(type(tee.private_route_tables[az].Tags), Tags) assert_equals(tee.nat.single.SourceDestCheck, 'false') assert_equals(tee.jump.single.SourceDestCheck, 'true') for num in range(len(availability_zones)): # For public subnets public_subnet = tee.public_subnets[num] assert_equals(public_subnet.CidrBlock, ''.join(['10.0.', str(num), '.0/24'])) # For private subnets private_subnet = tee.private_subnets[num] assert_equals(private_subnet.CidrBlock, ''.join(['10.0.', str(num + 100), '.0/24']))
def __init__(self, keypair, availability_zones, vpc_cidr, home_cidrs, public_cidr, jump_image_id, jump_instance_type, nat_image_id, nat_instance_type, public_hosted_zone_name, private_hosted_zone_name, iam_instance_profile_arn, owner_emails, nat_highly_available, ec2_scheduled_shutdown): """ Create a vpc, nat, jumphost, internet gateway, public/private route tables, public/private subnets and collection of Amazonia units AWS CloudFormation - http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html Troposphere - https://github.com/cloudtools/troposphere/blob/master/troposphere/ec2.py :param keypair: ssh keypair to be used throughout stack :param availability_zones: availability zones to use :param vpc_cidr: cidr pattern for vpc :param home_cidrs: a list of tuple objects of 'title'(0) and 'ip'(1) to be used to create ingress rules for ssh to jumpboxes from home/office/company premises :param public_cidr: a cidr to be treated as a public location. (eg 0.0.0.0/0) :param jump_image_id: AMI for jumphost :param jump_instance_type: instance type for jumphost :param nat_image_id: AMI for nat :param nat_instance_type: instance type for nat :param public_hosted_zone_name: A string containing the name of the Route 53 hosted zone to create public record sets in. :param private_hosted_zone_name: name of private hosted zone to create :param iam_instance_profile_arn: the ARN for an IAM instance profile that enables cloudtrail access for logging :param owner_emails: a list of emails for owners of this stack. Used for alerting. :param nat_highly_available: True/False for whether or not to use a series of NAT gateways or a single NAT :param ec2_scheduled_shutdown: True/False for whether to schedule shutdown for EC2 instances outside work hours """ super(Network, self).__init__() # set parameters self.keypair = keypair self.availability_zones = availability_zones self.vpc_cidr = vpc_cidr self.home_cidrs = home_cidrs self.public_cidr = public_cidr self.public_hosted_zone_name = public_hosted_zone_name self.private_hosted_zone_name = private_hosted_zone_name self.jump_image_id = jump_image_id self.jump_instance_type = jump_instance_type self.nat_image_id = nat_image_id self.nat_instance_type = nat_instance_type self.owner_emails = owner_emails if owner_emails else [] self.nat_highly_available = nat_highly_available self.iam_instance_profile_arn = iam_instance_profile_arn self.ec2_scheduled_shutdown = ec2_scheduled_shutdown # initialize object references self.template = Template() self.private_subnets = [] self.public_subnets = [] self.public_subnet_mapping = {} self.vpc = None self.private_hosted_zone = None self.internet_gateway = None self.gateway_attachment = None self.public_route_table = None self.private_route_tables = {} self.nat = None self.nat_gateways = [] self.jump = None self.private_route = None self.public_route = None self.sns_topic = None # Add VPC and Internet Gateway with Attachment vpc_name = 'Vpc' self.vpc = Ref( self.template.add_resource( ec2.VPC(vpc_name, CidrBlock=self.vpc_cidr['cidr'], EnableDnsSupport='true', EnableDnsHostnames='true', Tags=Tags(Name=Join( '', [Ref('AWS::StackName'), '-', vpc_name]))))) self.private_hosted_zone = HostedZone(self.template, self.private_hosted_zone_name, vpcs=[self.vpc]) ig_name = 'Ig' self.internet_gateway = self.template.add_resource( ec2.InternetGateway( ig_name, Tags=Tags( Name=Join('', [Ref('AWS::StackName'), '-', ig_name])), DependsOn=vpc_name)) self.gateway_attachment = self.template.add_resource( ec2.VPCGatewayAttachment(self.internet_gateway.title + 'Atch', VpcId=self.vpc, InternetGatewayId=Ref( self.internet_gateway), DependsOn=self.internet_gateway.title)) # Add Public Route Table public_rt_name = 'PubRouteTable' self.public_route_table = self.template.add_resource( ec2.RouteTable( public_rt_name, VpcId=self.vpc, Tags=Tags(Name=Join( '', [Ref('AWS::StackName'), '-', public_rt_name])))) # Add Public and Private Subnets and Private Route Table for az in self.availability_zones: private_rt_name = get_cf_friendly_name(az) + 'PriRouteTable' private_route_table = self.template.add_resource( ec2.RouteTable( private_rt_name, VpcId=self.vpc, Tags=Tags(Name=Join( '', [Ref('AWS::StackName'), '-', private_rt_name])))) self.private_route_tables[az] = private_route_table self.private_subnets.append( Subnet(template=self.template, route_table=private_route_table, az=az, vpc=self.vpc, is_public=False, cidr=self.generate_subnet_cidr( is_public=False)).trop_subnet) public_subnet = Subnet( template=self.template, route_table=self.public_route_table, az=az, vpc=self.vpc, is_public=True, cidr=self.generate_subnet_cidr(is_public=True)).trop_subnet self.public_subnets.append(public_subnet) self.public_subnet_mapping[az] = Ref(public_subnet) self.sns_topic = SNS(self.template) for email in self.owner_emails: self.sns_topic.add_subscription(email, 'email') jump_config = SingleInstanceConfig( keypair=self.keypair, si_image_id=self.jump_image_id, si_instance_type=self.jump_instance_type, subnet=self.public_subnet_mapping[availability_zones[0]], vpc=self.vpc, public_hosted_zone_name=self.public_hosted_zone_name, instance_dependencies=self.gateway_attachment.title, iam_instance_profile_arn=self.iam_instance_profile_arn, is_nat=False, sns_topic=self.sns_topic, availability_zone=availability_zones[0], ec2_scheduled_shutdown=self.ec2_scheduled_shutdown) # Add Jumpbox and NAT and associated security group ingress and egress rules self.jump = SingleInstance(title='Jump', template=self.template, single_instance_config=jump_config) [ self.jump.add_ingress(sender=home_cidr, port='22') for home_cidr in self.home_cidrs ] self.jump.add_egress(receiver=self.public_cidr, port='-1') if self.nat_highly_available: for public_subnet in self.public_subnets: az = public_subnet.AvailabilityZone ip_address = self.template.add_resource( EIP(get_cf_friendly_name(az) + 'NatGwEip', DependsOn=self.gateway_attachment.title, Domain='vpc')) nat_gateway = self.template.add_resource( NatGateway(get_cf_friendly_name(az) + 'NatGw', AllocationId=GetAtt(ip_address, 'AllocationId'), SubnetId=Ref(public_subnet), DependsOn=self.gateway_attachment.title)) self.nat_gateways.append(nat_gateway) self.template.add_resource( ec2.Route(get_cf_friendly_name(az) + 'PriRoute', NatGatewayId=Ref(nat_gateway), RouteTableId=Ref(self.private_route_tables[az]), DestinationCidrBlock=self.public_cidr['cidr'], DependsOn=self.gateway_attachment.title)) else: nat_config = SingleInstanceConfig( keypair=self.keypair, si_image_id=self.nat_image_id, si_instance_type=self.nat_instance_type, subnet=self.public_subnet_mapping[availability_zones[0]], vpc=self.vpc, is_nat=True, instance_dependencies=self.gateway_attachment.title, iam_instance_profile_arn=self.iam_instance_profile_arn, public_hosted_zone_name=None, sns_topic=self.sns_topic, availability_zone=availability_zones[0], ec2_scheduled_shutdown=self.ec2_scheduled_shutdown) self.nat = SingleInstance(title='Nat', template=self.template, single_instance_config=nat_config) self.nat.add_egress(receiver=self.public_cidr, port='-1') self.nat.add_ingress(sender=self.vpc_cidr, port='-1') for az in self.availability_zones: self.template.add_resource( ec2.Route(get_cf_friendly_name(az) + 'PriRoute', InstanceId=Ref(self.nat.single), RouteTableId=Ref(self.private_route_tables[az]), DestinationCidrBlock=self.public_cidr['cidr'], DependsOn=self.gateway_attachment.title)) # Add Public Route self.public_route = self.template.add_resource( ec2.Route('PubRoute', GatewayId=Ref(self.internet_gateway), RouteTableId=Ref(self.public_route_table), DestinationCidrBlock=self.public_cidr['cidr'], DependsOn=self.gateway_attachment.title))
def __init__(self, keypair, availability_zones, vpc_cidr, home_cidrs, public_cidr, jump_image_id, jump_instance_type, nat_image_id, nat_instance_type, public_hosted_zone_name, private_hosted_zone_name, iam_instance_profile_arn, owner_emails, nat_highly_available, ec2_scheduled_shutdown): """ Create a vpc, nat, jumphost, internet gateway, public/private route tables, public/private subnets and collection of Amazonia units AWS CloudFormation - http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html Troposphere - https://github.com/cloudtools/troposphere/blob/master/troposphere/ec2.py :param keypair: ssh keypair to be used throughout stack :param availability_zones: availability zones to use :param vpc_cidr: cidr pattern for vpc :param home_cidrs: a list of tuple objects of 'title'(0) and 'ip'(1) to be used to create ingress rules for ssh to jumpboxes from home/office/company premises :param public_cidr: a cidr to be treated as a public location. (eg 0.0.0.0/0) :param jump_image_id: AMI for jumphost :param jump_instance_type: instance type for jumphost :param nat_image_id: AMI for nat :param nat_instance_type: instance type for nat :param public_hosted_zone_name: A string containing the name of the Route 53 hosted zone to create public record sets in. :param private_hosted_zone_name: name of private hosted zone to create :param iam_instance_profile_arn: the ARN for an IAM instance profile that enables cloudtrail access for logging :param owner_emails: a list of emails for owners of this stack. Used for alerting. :param nat_highly_available: True/False for whether or not to use a series of NAT gateways or a single NAT :param ec2_scheduled_shutdown: True/False for whether to schedule shutdown for EC2 instances outside work hours """ super(Network, self).__init__() # set parameters self.keypair = keypair self.availability_zones = availability_zones self.vpc_cidr = vpc_cidr self.home_cidrs = home_cidrs self.public_cidr = public_cidr self.public_hosted_zone_name = public_hosted_zone_name self.private_hosted_zone_name = private_hosted_zone_name self.jump_image_id = jump_image_id self.jump_instance_type = jump_instance_type self.nat_image_id = nat_image_id self.nat_instance_type = nat_instance_type self.owner_emails = owner_emails if owner_emails else [] self.nat_highly_available = nat_highly_available self.iam_instance_profile_arn = iam_instance_profile_arn self.ec2_scheduled_shutdown = ec2_scheduled_shutdown # initialize object references self.template = Template() self.private_subnets = [] self.public_subnets = [] self.public_subnet_mapping = {} self.vpc = None self.private_hosted_zone = None self.internet_gateway = None self.gateway_attachment = None self.public_route_table = None self.private_route_tables = {} self.nat = None self.nat_gateways = [] self.jump = None self.private_route = None self.public_route = None self.sns_topic = None # Add VPC and Internet Gateway with Attachment vpc_name = 'Vpc' self.vpc = Ref(self.template.add_resource( ec2.VPC( vpc_name, CidrBlock=self.vpc_cidr['cidr'], EnableDnsSupport='true', EnableDnsHostnames='true', Tags=Tags( Name=Join('', [Ref('AWS::StackName'), '-', vpc_name]) ) ))) self.private_hosted_zone = HostedZone(self.template, self.private_hosted_zone_name, vpcs=[self.vpc]) ig_name = 'Ig' self.internet_gateway = self.template.add_resource( ec2.InternetGateway(ig_name, Tags=Tags(Name=Join('', [Ref('AWS::StackName'), '-', ig_name])), DependsOn=vpc_name)) self.gateway_attachment = self.template.add_resource( ec2.VPCGatewayAttachment(self.internet_gateway.title + 'Atch', VpcId=self.vpc, InternetGatewayId=Ref(self.internet_gateway), DependsOn=self.internet_gateway.title)) # Add Public Route Table public_rt_name = 'PubRouteTable' self.public_route_table = self.template.add_resource( ec2.RouteTable(public_rt_name, VpcId=self.vpc, Tags=Tags(Name=Join('', [Ref('AWS::StackName'), '-', public_rt_name])))) # Add Public and Private Subnets and Private Route Table for az in self.availability_zones: private_rt_name = get_cf_friendly_name(az) + 'PriRouteTable' private_route_table = self.template.add_resource( ec2.RouteTable(private_rt_name, VpcId=self.vpc, Tags=Tags(Name=Join('', [Ref('AWS::StackName'), '-', private_rt_name])))) self.private_route_tables[az] = private_route_table self.private_subnets.append(Subnet(template=self.template, route_table=private_route_table, az=az, vpc=self.vpc, is_public=False, cidr=self.generate_subnet_cidr(is_public=False)).trop_subnet) public_subnet = Subnet(template=self.template, route_table=self.public_route_table, az=az, vpc=self.vpc, is_public=True, cidr=self.generate_subnet_cidr(is_public=True)).trop_subnet self.public_subnets.append(public_subnet) self.public_subnet_mapping[az] = Ref(public_subnet) self.sns_topic = SNS(self.template) for email in self.owner_emails: self.sns_topic.add_subscription(email, 'email') jump_config = SingleInstanceConfig( keypair=self.keypair, si_image_id=self.jump_image_id, si_instance_type=self.jump_instance_type, subnet=self.public_subnet_mapping[availability_zones[0]], vpc=self.vpc, public_hosted_zone_name=self.public_hosted_zone_name, instance_dependencies=self.gateway_attachment.title, iam_instance_profile_arn=self.iam_instance_profile_arn, is_nat=False, sns_topic=self.sns_topic, availability_zone=availability_zones[0], ec2_scheduled_shutdown=self.ec2_scheduled_shutdown ) # Add Jumpbox and NAT and associated security group ingress and egress rules self.jump = SingleInstance( title='Jump', template=self.template, single_instance_config=jump_config ) [self.jump.add_ingress(sender=home_cidr, port='22') for home_cidr in self.home_cidrs] self.jump.add_egress(receiver=self.public_cidr, port='-1') if self.nat_highly_available: for public_subnet in self.public_subnets: az = public_subnet.AvailabilityZone ip_address = self.template.add_resource( EIP(get_cf_friendly_name(az) + 'NatGwEip', DependsOn=self.gateway_attachment.title, Domain='vpc' )) nat_gateway = self.template.add_resource(NatGateway(get_cf_friendly_name(az) + 'NatGw', AllocationId=GetAtt(ip_address, 'AllocationId'), SubnetId=Ref(public_subnet), DependsOn=self.gateway_attachment.title )) self.nat_gateways.append(nat_gateway) self.template.add_resource(ec2.Route(get_cf_friendly_name(az) + 'PriRoute', NatGatewayId=Ref(nat_gateway), RouteTableId=Ref(self.private_route_tables[az]), DestinationCidrBlock=self.public_cidr['cidr'], DependsOn=self.gateway_attachment.title)) else: nat_config = SingleInstanceConfig( keypair=self.keypair, si_image_id=self.nat_image_id, si_instance_type=self.nat_instance_type, subnet=self.public_subnet_mapping[availability_zones[0]], vpc=self.vpc, is_nat=True, instance_dependencies=self.gateway_attachment.title, iam_instance_profile_arn=self.iam_instance_profile_arn, public_hosted_zone_name=None, sns_topic=self.sns_topic, availability_zone=availability_zones[0], ec2_scheduled_shutdown=self.ec2_scheduled_shutdown ) self.nat = SingleInstance( title='Nat', template=self.template, single_instance_config=nat_config ) self.nat.add_egress(receiver=self.public_cidr, port='-1') self.nat.add_ingress(sender=self.vpc_cidr, port='-1') for az in self.availability_zones: self.template.add_resource(ec2.Route(get_cf_friendly_name(az) + 'PriRoute', InstanceId=Ref(self.nat.single), RouteTableId=Ref(self.private_route_tables[az]), DestinationCidrBlock=self.public_cidr['cidr'], DependsOn=self.gateway_attachment.title)) # Add Public Route self.public_route = self.template.add_resource(ec2.Route('PubRoute', GatewayId=Ref(self.internet_gateway), RouteTableId=Ref(self.public_route_table), DestinationCidrBlock=self.public_cidr['cidr'], DependsOn=self.gateway_attachment.title))