예제 #1
0
파일: trop.py 프로젝트: swipswaps/builder
    def entry(hostname, i):
        if _is_domain_2nd_level(hostname):
            hostedzone = hostname + "."
            ip_addresses = context['fastly']['dns']['a']
            return route53.RecordSetType(
                R53_FASTLY_TITLE % (
                    i + 1
                ),  # expecting more than one entry (aliases), so numbering them immediately
                HostedZoneName=hostedzone,
                Name=hostname,
                Type="A",
                TTL="60",
                ResourceRecords=ip_addresses,
            )
            raise ConfigurationError(
                "2nd-level domains aliases are not supported yet by builder. See https://docs.fastly.com/guides/basic-configuration/using-fastly-with-apex-domains"
            )

        hostedzone = context['domain'] + "."
        cname = context['fastly']['dns']['cname']
        return route53.RecordSetType(
            R53_FASTLY_TITLE % (
                i + 1
            ),  # expecting more than one entry (aliases), so numbering them immediately
            HostedZoneName=hostedzone,
            Name=hostname,
            Type="CNAME",
            TTL="60",
            ResourceRecords=[cname],
        )
예제 #2
0
 def entry(hostname, i):
     if _is_domain_2nd_level(hostname):
         # must be an alias as it is a 2nd-level domain like elifesciences.net
         hostedzone = hostname + "."
         ensure(context['elb'],
                "2nd-level domains aliases are only supported for ELBs")
         return route53.RecordSetType(R53_CNAME_TITLE % (i + 1),
                                      HostedZoneName=hostedzone,
                                      Name=hostname,
                                      Type="A",
                                      AliasTarget=route53.AliasTarget(
                                          GetAtt(
                                              ELB_TITLE,
                                              "CanonicalHostedZoneNameID"),
                                          GetAtt(ELB_TITLE, "DNSName")))
     else:
         hostedzone = context['domain'] + "."
         return route53.RecordSetType(
             R53_CNAME_TITLE % (i + 1),
             HostedZoneName=hostedzone,
             Name=hostname,
             Type="CNAME",
             TTL="60",
             ResourceRecords=[context['full_hostname']],
         )
예제 #3
0
파일: trop.py 프로젝트: swipswaps/builder
def render_ec2_dns(context, template):
    # single ec2 node may get an external hostname
    if context['full_hostname'] and not context['elb']:
        ensure(
            context['ec2']['cluster-size'] <= 1,
            "If there is no load balancer, multiple EC2 instances cannot be assigned a single DNS entry"
        )

        if context['ec2']['cluster-size'] == 1:
            template.add_resource(external_dns_ec2_single(context))
            [template.add_resource(cname) for cname in cnames(context)]

    # single ec2 node may get an internal hostname
    if context['int_full_hostname'] and not context['elb']:
        ensure(
            context['ec2']['cluster-size'] == 1,
            "If there is no load balancer, only a single EC2 instance can be assigned a DNS entry"
        )
        template.add_resource(internal_dns_ec2_single(context))

    # ec2 nodes in a cluster may get a different internal hostname each
    if context['ec2']['dns-internal']:
        for node in range(1, context['ec2']['cluster-size'] + 1):
            hostedzone = context['int_domain'] + "."
            dns_record = route53.RecordSetType(
                R53_INT_TITLE_NODE % node,
                HostedZoneName=hostedzone,
                Comment="Internal DNS record for EC2 node %s" % node,
                Name=context['int_node_hostname'] % node,
                Type="A",
                TTL="60",
                ResourceRecords=[GetAtt(EC2_TITLE_NODE % node, "PrivateIp")],
            )
            template.add_resource(dns_record)

    # primary ec2 node in a cluster may get an external hostname
    if context['domain'] and context['ec2']['dns-external-primary']:
        hostedzone = context['domain'] + "."
        primary = 1
        dns_record = route53.RecordSetType(
            R53_EXT_TITLE_NODE % primary,
            HostedZoneName=hostedzone,
            Comment="External DNS record for EC2 primary",
            Name=context['ext_node_hostname'] % primary,
            Type="A",
            TTL="60",
            ResourceRecords=[GetAtt(EC2_TITLE_NODE % primary, "PublicIp")],
        )
        template.add_resource(dns_record)
예제 #4
0
파일: __init__.py 프로젝트: pierretr/e3-aws
    def resources(self, stack: Stack) -> list[AWSObject]:
        """Return list of AWSObject associated with the construct."""
        # Add bucket policy granting read access to te cloudfront distribution
        self.add_oai_access_to_bucket()

        result = [
            *self.bucket.resources(stack),
            self.cache_policy,
            self.distribution,
            self.origin_access_identity,
        ]

        # Add a lambda invalidating cloudfront cache when bucket objects are modified
        result.extend(self.add_cache_invalidation(stack))

        # Add route53 records if needed
        if self.r53_route_from:
            for zone_id, domain in self.r53_route_from:
                result.append(
                    route53.RecordSetType(
                        name_to_id(f"{self.name}-{domain}-r53-rset"),
                        AliasTarget=route53.AliasTarget(
                            DNSName=self.domain_name,
                            # Z2FDTNDATAQYW2 is always the hosted zone ID when you
                            # create an alias record that routes traffic to a
                            # CloudFront distribution
                            HostedZoneId="Z2FDTNDATAQYW2",
                        ),
                        Name=domain,
                        HostedZoneId=zone_id,
                        Type="A",
                    ))
        return result
예제 #5
0
    def declare_domain(self, domain_name: str, hosted_zone_id: str,
                       stage_name: str) -> list[AWSObject]:
        """Declare a custom domain for one of the API stage.

        Note that when a custom domain is created then a certificate is automatically
        created for that domain.

        :param domain_name: domain name
        :param hosted_zone_id: hosted zone in which the domain belongs to
        :param stage_name: stage that should be associated with that domain
        :return: a list of AWSObject
        """
        result = []
        certificate_id = name_to_id(self.name + domain_name + "Certificate")
        certificate = Certificate(
            certificate_id,
            DomainName=domain_name,
            DomainValidationOptions=[
                DomainValidationOption(DomainName=domain_name,
                                       HostedZoneId=hosted_zone_id)
            ],
            ValidationMethod="DNS",
        )
        result.append(certificate)
        domain = apigatewayv2.DomainName(
            name_to_id(self.name + domain_name + "Domain"),
            DomainName=domain_name,
            DomainNameConfigurations=[
                apigatewayv2.DomainNameConfiguration(
                    CertificateArn=certificate.ref())
            ],
        )
        result.append(domain)
        result.append(
            apigatewayv2.ApiMapping(
                name_to_id(self.name + domain_name + "ApiMapping"),
                DomainName=domain.ref(),
                ApiId=self.ref,
                Stage=self.stage_ref(stage_name),
            ))
        result.append(
            route53.RecordSetType(
                name_to_id(self.name + domain_name + "DNS"),
                Name=domain_name,
                Type="A",
                HostedZoneId=hosted_zone_id,
                AliasTarget=route53.AliasTarget(
                    DNSName=GetAtt(
                        name_to_id(self.name + domain_name + "Domain"),
                        "RegionalDomainName",
                    ),
                    HostedZoneId=GetAtt(
                        name_to_id(self.name + domain_name + "Domain"),
                        "RegionalHostedZoneId",
                    ),
                    EvaluateTargetHealth=False,
                ),
            ))
        return result
예제 #6
0
 def public_record_set(self, index):
     return route53.RecordSetType(
         'PilosaPublicRecordSet{}'.format(index),
         HostedZoneName='{domain}.'.format(domain=self.domain),
         Name=Join('', ['node{}.'.format(index), Ref(self.cluster_name), '.{domain}.'.format(domain=self.domain)]),
         Type="A",
         TTL="300",
         ResourceRecords=[GetAtt("PilosaInstance{}".format(index), "PublicIp")],
     )
예제 #7
0
 def agent_private_record_set(self, index):
     return route53.RecordSetType(
         'AgentPrivateRecordSet{}'.format(index),
         HostedZoneId=Ref(self.hosted_zone),
         Name=Join('', ['agent{}.'.format(index), Ref(self.cluster_name), '.{domain}.'.format(domain=self.domain)]),
         Type="A",
         TTL="300",
         ResourceRecords=[GetAtt("PilosaAgentInstance{}".format(index), "PrivateIp")],
     )
예제 #8
0
def simple2resource(record, zone_name):
    name = get_resource_name(record)
    resource = route53.RecordSetType(name)
    resource.HostedZoneName = zone_name.ref()
    resource.Name = record['Name']
    resource.TTL = record['TTL']
    resource.ResourceRecords = [l['Value'] for l in record['ResourceRecords']]
    resource.Type = record['Type']
    return resource
예제 #9
0
 def add_route53(self, stack_name, template, provision_refs):
     template.add_resource(
         route53.RecordSetType(
             "NetworkDNSRecord",
             HostedZoneName="network.shipchain.io.",
             Comment=f"DNS name for {stack_name} network ALB",
             Name=f"{stack_name}.network.shipchain.io.",
             Type="A",
             AliasTarget=route53.AliasTarget(
                 DNSName=GetAtt(provision_refs.alb, 'DNSName'),
                 HostedZoneId=GetAtt(provision_refs.alb,
                                     "CanonicalHostedZoneID"))))
예제 #10
0
 def add_s3_dns(self):
     name, tags = self._name_tags('s3_dns')
     self.s3_dns = self.t.add_resource(
         route53.RecordSetType(
             name,
             HostedZoneName=self.aws['s3_dns.zone'],
             Comment='CNAME to public ELB',
             Name=self.aws['s3_dns.record'] + '.' + self.aws['s3_dns.zone'],
             TTL=self.aws['s3_dns.ttl'],
             Type='CNAME',
             ResourceRecords=[GetAtt(self.s3.name, 'DomainName')],
             # Doesn't support: Tags=Tags(**tags),
         ))
예제 #11
0
파일: trop.py 프로젝트: swipswaps/builder
def internal_dns_ec2_single(context):
    # The DNS name of an existing Amazon Route 53 hosted zone
    hostedzone = context['int_domain'] + "."  # TRAILING DOT IS IMPORTANT!
    dns_record = route53.RecordSetType(
        R53_INT_TITLE,
        HostedZoneName=hostedzone,
        Comment="Internal DNS record for EC2",
        Name=context['int_full_hostname'] + '.',
        Type="A",
        TTL="60",
        ResourceRecords=[GetAtt(EC2_TITLE, "PrivateIp")],
    )
    return dns_record
예제 #12
0
def alias2resource(record, zone_name):
    name = get_resource_name(record, suffix='ALIAS')
    resource = route53.RecordSetType(name)
    resource.HostedZoneName = zone_name.ref()
    resource.Name = record['Name']
    resource.Type = record['Type']
    alias_target = route53.AliasTarget()
    alias_target.HostedZoneId = record['AliasTarget']['HostedZoneId']
    alias_target.DNSName = record['AliasTarget']['DNSName']
    alias_target.EvaluateTargetHealth = record['AliasTarget'][
        'EvaluateTargetHealth']
    resource.AliasTarget = alias_target
    return resource
예제 #13
0
파일: trop.py 프로젝트: swipswaps/builder
def internal_dns_elb(context):
    # The DNS name of an existing Amazon Route 53 hosted zone
    hostedzone = context['int_domain'] + "."  # TRAILING DOT IS IMPORTANT!
    dns_record = route53.RecordSetType(R53_INT_TITLE,
                                       HostedZoneName=hostedzone,
                                       Comment="Internal DNS record for ELB",
                                       Name=context['int_full_hostname'],
                                       Type="A",
                                       AliasTarget=route53.AliasTarget(
                                           GetAtt(ELB_TITLE,
                                                  "CanonicalHostedZoneNameID"),
                                           GetAtt(ELB_TITLE, "DNSName")))
    return dns_record
예제 #14
0
def external_dns_ec2(context):
    # The DNS name of an existing Amazon Route 53 hosted zone
    hostedzone = context['domain'] + "."  # TRAILING DOT IS IMPORTANT!
    dns_record = route53.RecordSetType(
        R53_EXT_TITLE,
        HostedZoneName=hostedzone,
        Comment="External DNS record for EC2",
        Name=context['full_hostname'],
        Type="A",
        TTL="60",
        ResourceRecords=[GetAtt(EC2_TITLE, "PublicIp")],
    )
    return dns_record
예제 #15
0
파일: trop.py 프로젝트: swipswaps/builder
def external_dns_elb(context):
    # http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-choosing-alias-non-alias.html
    # The DNS name of an existing Amazon Route 53 hosted zone
    hostedzone = context['domain'] + "."  # TRAILING DOT IS IMPORTANT!
    dns_record = route53.RecordSetType(R53_EXT_TITLE,
                                       HostedZoneName=hostedzone,
                                       Comment="External DNS record for ELB",
                                       Name=context['full_hostname'],
                                       Type="A",
                                       AliasTarget=route53.AliasTarget(
                                           GetAtt(ELB_TITLE,
                                                  "CanonicalHostedZoneNameID"),
                                           GetAtt(ELB_TITLE, "DNSName")))
    return dns_record
예제 #16
0
 def create_dns_records(self):
     t = self.template
     t.add_resource(
         route53.RecordSetType(
             DNS_RECORD,
             HostedZoneId=Ref('InternalZoneId'),
             Comment='ES Domain CNAME Record',
             Name=Join('.', [Ref('InternalHostname'), Ref('InternalZoneName')]),
             Type='CNAME',
             TTL='120',
             ResourceRecords=[GetAtt('Domain', 'DomainEndpoint')],
             Condition='CreateInternalHostname',
         )
     )
     t.add_output(Output('CNAME', Condition='CreateInternalHostname', Value=Ref(DNS_RECORD)))
예제 #17
0
    def register_elb_to_dns(self, elb, tier_name, tier_args):
        '''
        Method handles the process of uniformly creating CNAME records for ELBs in a given tier
        @param elb [Troposphere.elasticloadbalancing.LoadBalancer]
        @param tier_name [str]
        @param tier_args [dict]
        '''
        if 'environmentHostedZone' not in self.template.parameters:
            hostedzone = self.template.add_parameter(
                Parameter(
                    "environmentHostedZone",
                    Description=
                    "The DNS name of an existing Amazon Route 53 hosted zone",
                    Default=tier_args.get('base_hosted_zone_name',
                                          'devopsdemo.com'),
                    Type="String"))
        else:
            hostedzone = self.template.parameters.get('environmentHostedZone')

        if tier_name.lower() + 'HostName' not in self.template.parameters:
            host_name = self.template.add_parameter(
                Parameter(
                    tier_name.lower() + 'HostName',
                    Description=
                    "Friendly host name to append to the environmentHostedZone base DNS record",
                    Type="String",
                    Default=tier_args.get('tier_host_name',
                                          tier_name.lower())))
        else:
            host_name = self.template.parameters.get(tier_name.lower() +
                                                     'HostName')

        self.template.add_resource(
            r53.RecordSetType(
                tier_name.lower() + 'DnsRecord',
                HostedZoneName=Join('', [Ref(hostedzone), '.']),
                Comment='CNAME record for ' + tier_name.capitalize() + ' tier',
                Name=Join(
                    '',
                    [Ref(host_name), '.', Ref(hostedzone)]),
                Type='CNAME',
                TTL='300',
                ResourceRecords=[GetAtt(elb, 'DNSName')]))
예제 #18
0
    def add_elb(self):

        self.ElasticLoadBalancer = self.template.add_resource(
            elb.LoadBalancer(
                "ElbWeb",
                Subnets=[Ref(self.Subnet1),
                         Ref(self.Subnet2)],
                Listeners=[{
                    "InstancePort": "80",
                    "LoadBalancerPort": "80",
                    "Protocol": "HTTP"
                }],
                CrossZone="true",
                LoadBalancerName=Join("-", ["elb", Ref(self.Project)]),
                SecurityGroups=[Ref(self.ElbSecurityGroup)],
                ConnectionDrainingPolicy=elb.ConnectionDrainingPolicy(
                    Enabled=True,
                    Timeout=300,
                ),
                HealthCheck=elb.HealthCheck(
                    HealthyThreshold="3",
                    Interval="30",
                    Target="HTTP:80/",
                    Timeout="5",
                    UnhealthyThreshold="5",
                ),
                Tags=Tags(
                    Name=Join("-", ["ELB", Ref(self.Project)]),
                    Environment=Ref(self.Environment),
                ),
            ))

        self.ELBcname = self.template.add_resource(
            route53.RecordSetType(
                "ELBcname",
                HostedZoneName=Join("", [Ref(self.Domain), "."]),
                Comment="CNAME to Web ELB",
                Name=Join(
                    ".",
                    [Ref(self.Hostname), Ref(self.Domain)]),
                Type="CNAME",
                TTL="60",
                ResourceRecords=[GetAtt(self.ElasticLoadBalancer, "DNSName")]))
예제 #19
0
 def create_dns_record(self):
     t = self.template
     variables = self.get_variables()
     should_create_dns = all([
         variables["InternalZoneId"],
         variables["InternalZoneName"],
         variables["InternalHostName"],
     ])
     if should_create_dns:
         t.add_resource(
             route53.RecordSetType(
                 DNS_RECORD,
                 HostedZoneId=variables["InternalZoneId"],
                 Comment="ES Domain CNAME Record",
                 Name="{}.{}".format(variables["InternalHostName"],
                                     variables["InternalZoneName"]),
                 Type="CNAME",
                 TTL="120",
                 ResourceRecords=[GetAtt(ES_DOMAIN, "DomainEndpoint")],
             ))
         t.add_output(Output("CNAME", Value=Ref(DNS_RECORD)))
예제 #20
0
파일: trop.py 프로젝트: swipswaps/builder
def external_dns_cloudfront(context):
    # http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-choosing-alias-non-alias.html
    dns_records = []
    i = 1
    for cdn_hostname in context['cloudfront']['subdomains']:
        if _is_domain_2nd_level(cdn_hostname):
            hostedzone = cdn_hostname + "."
        else:
            hostedzone = context['domain'] + "."
        dns_records.append(
            route53.RecordSetType(
                R53_CDN_TITLE % i,
                HostedZoneName=hostedzone,
                Comment="External DNS record for Cloudfront distribution",
                Name=cdn_hostname + ".",
                Type="A",
                AliasTarget=route53.AliasTarget(
                    CLOUDFRONT_HOSTED_ZONE_ID,
                    GetAtt(CLOUDFRONT_TITLE, "DomainName"))))
        i = i + 1

    return dns_records
    def add_cname(self):
        """
        Wrapper method to encapsulate process of creating a CNAME DNS record for the ELB
        Requires InternalHostedZone parameter
        Sets self.cname_record with the record resource
        """

        if not self.cname:
            return

        hosted_zone = self.add_parameter(
            Parameter('InternalHostedZone',
                      Description='Internal Hosted Zone Name',
                      Type='String'))

        self.cname_record = self.add_resource(
            route53.RecordSetType(
                self.name.lower() + 'DnsRecord',
                HostedZoneId=Ref(hosted_zone),
                Comment='CNAME record for %s' % self.name,
                Name=self.cname,
                Type='CNAME',
                TTL='300',
                ResourceRecords=[GetAtt(self.cluster_elb, 'DNSName')]))
예제 #22
0
    def __init__(self, title, template, single_instance_config):
        """
        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
        Create a singleton instance such as a nat or a jumphost
        :param title: Title of instance e.g 'nat1', 'nat2' or 'jump1'
        :param template: The template to add the SingleInstance object to.
        :param single_instance_config: object containing variables specific to single instance configuration
        """

        super(SingleInstance, self).__init__(vpc=single_instance_config.vpc,
                                             title=title,
                                             template=template)
        self.sns_topic = single_instance_config.sns_topic
        region = single_instance_config.availability_zone[:-1]
        userdata = """#cloud-config
# Capture all cloud-config output into a more readable logfile
output: {all: '| tee -a /var/log/cloud-init-output.log'}
# update and install packages, reboot if necessary
package_upgrade: true
package_reboot_if_required: true
packages:
 - perl-Switch
 - perl-DateTime
 - perl-Sys-Syslog
 - perl-LWP-Protocol-https

write_files:
 - path: /etc/awslogs.cfg
   content: |
    [general]
    state_file = /var/awslogs/state/agent-state

    [/var/log/messages]
    file = /var/log/messages
    log_group_name = /var/log/messages
    log_stream_name = {instance_id}
    datetime_format = %b %d %H:%M:%S

runcmd:
# cloudwatch monitoring scripts
 - curl -so /tmp/CloudWatchMonitoringScripts-1.2.1.zip http://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.1.zip
 - unzip -d /opt /tmp/CloudWatchMonitoringScripts-1.2.1.zip
 - echo '*/5 * * * * root /opt/aws-scripts-mon/mon-put-instance-data.pl --mem-util --mem-used --mem-avail --disk-space-util --disk-path=/ --from-cron' > /etc/cron.d/cloudwatch
# cloudwatch logs agent and forwarding config
 - curl https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py -O
 - chmod +x ./awslogs-agent-setup.py
 - ./awslogs-agent-setup.py -n -r """ + region + """ -c /etc/awslogs.cfg
"""

        tags = Tags(Name=Join('', [Ref('AWS::StackName'), '-', title]))
        if single_instance_config.ec2_scheduled_shutdown:
            # Add tag to instance, so it gets picked up by EC2 Scheduler (a CF stack that needs to be running):
            # http://docs.aws.amazon.com/solutions/latest/ec2-scheduler/deployment.html
            #
            # EC2 scheduler tag format: "<start time>;<stop time>;utc;<active days>"
            #
            # The times are in UTC, so need to account for this:
            # 1900 UTC (previous day) = 0600 AEDT, 0900 UTC = 2000 AEDT,
            # therefore, it needs to run Sunday UTC to be Monday AEDT.
            #
            # A work day is defined as: 6am-9pm. (An additional hour is added before & after for daylight savings)
            tags += Tags(**{
                'scheduler:ec2-startstop':
                '1900;0900;utc;sun,mon,tue,wed,thu'
            })

        self.single = self.template.add_resource(
            ec2.Instance(
                title,
                KeyName=single_instance_config.keypair,
                ImageId=single_instance_config.si_image_id,
                InstanceType=single_instance_config.si_instance_type,
                NetworkInterfaces=[
                    ec2.NetworkInterfaceProperty(
                        GroupSet=[self.security_group],
                        AssociatePublicIpAddress=True,
                        DeviceIndex='0',
                        DeleteOnTermination=True,
                        SubnetId=single_instance_config.subnet,
                    )
                ],
                # The below boolean determines whether source/destination checking is enabled on the
                # instance. This needs to be false to enable NAT functionality from the instance, or
                # true otherwise. For more info check the below:
                # http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-sourcedestcheck
                SourceDestCheck=False
                if single_instance_config.is_nat else True,
                Tags=tags,
                DependsOn=single_instance_config.instance_dependencies,
                UserData=Base64(userdata)))

        if single_instance_config.is_nat:
            metric = 'CPUUtilization'
            self.sns_topic.add_alarm(
                description='Alarms when {0} metric {1} reaches {2}'.format(
                    self.single.title, metric, '60'),
                metric=metric,
                namespace='AWS/EC2',
                threshold='60',
                instance=self.single)

        if single_instance_config.iam_instance_profile_arn:
            self.single.IamInstanceProfile = single_instance_config.iam_instance_profile_arn.split(
                '/')[1]

        if self.single.SourceDestCheck == 'true':
            # Give the instance an Elastic IP Address
            self.eip_address = self.template.add_resource(
                ec2.EIP(self.single.title + 'EIP',
                        DependsOn=single_instance_config.instance_dependencies,
                        Domain='vpc',
                        InstanceId=Ref(self.single)))
            if single_instance_config.public_hosted_zone_name:
                # Create a Route53 Record Set for the instances Elastic IP address.

                self.si_r53 = self.template.add_resource(
                    route53.RecordSetType(
                        self.single.title + 'R53',
                        HostedZoneName=single_instance_config.
                        public_hosted_zone_name,
                        Comment='DNS Record for {0}'.format(self.single.title),
                        Name=Join('', [
                            Ref('AWS::StackName'), '-', self.single.title, '.',
                            single_instance_config.public_hosted_zone_name
                        ]),
                        ResourceRecords=[Ref(self.eip_address)],
                        Type='A',
                        TTL='300',
                        DependsOn=single_instance_config.instance_dependencies)
                )

                # Create an output for the Record Set that has been created.

                self.template.add_output(
                    Output(self.single.title,
                           Description='URL of the jump host {0}'.format(
                               self.single.title),
                           Value=self.si_r53.Name))

            else:
                self.template.add_output(
                    Output(self.single.title,
                           Description='Public IP of the jump host {0}'.format(
                               self.single.title),
                           Value=Ref(self.eip_address)))
        HealthCheck=elb.HealthCheck(
            HealthyThreshold="3",
            Interval="5",
            Target="HTTP:80/",
            Timeout="2",
            UnhealthyThreshold="5",
        ),
    ))

ELBcname = t.add_resource(
    route53.RecordSetType(
        "ELBcname",
        DependsOn=["InternetGateway", "GatewayToInternet"],
        # HostedZoneName=Join("", [Ref(Domain), "."]),
        HostedZoneId="ZTUOGS2NQKC92",
        Comment="CNAME to Web ELB",
        Name=Join("", [Ref(Project), ".showroom.",
                       Ref(Domain)]),
        Type="CNAME",
        TTL="900",
        ResourceRecords=[GetAtt(ElasticLoadBalancer, "DNSName")]))

#  OUTPUTS

VPCID = t.add_output(
    Output(
        "VPCID",
        Description="VPC Info.",
        Value=Join("", [Ref(VPC), " (", Ref(VpcCidr), ")"]),
    ))
예제 #24
0
    [Ref("PublicSecurityGroup")],
    False
)

InternalGatewayElb = create_load_balancer(t,
    "IGateway",
    80,
    "/health-check",
    [Ref("PublicSecurityGroup")]
)

InternalMembraneDNSRecord = t.add_resource(route53.RecordSetType(
    "InternalMembraneDNSRecord",
    HostedZoneName=Join("", cell_domain() + ["."]),
    Comment="CNAME redirect to internal membrane elb",
    Name=Join("", ["*", "."] + cell_domain()),
    Type="CNAME",
    TTL="900",
    ResourceRecords=[GetAtt("IGatewayElb", "DNSName")],
    DependsOn=["IGatewayElb", "HostedZone"]
))

WaitHandle = t.add_resource(cfn.WaitConditionHandle("WaitHandle",))

def create_cellos_substack(t, name=None, role=None, cell_modules=None, tags=[],
                           security_groups=[], load_balancers=[],
                           instance_profile=None, instance_type=None,
                           subnet=Ref(private_subnet),
                           associate_public_ip=False):
    params = {
        "Role": role,
        "Tags": tags,
예제 #25
0
def setup_vpn(config, template):
    stack = config['stack']
    region = config['region']
    vpc_name = config['vpc']
    public_subnets = []
    private_subnets = []
    customer_gateways = []
    nat_ec2_instances = []

    if region == None:
        print_err('%(stack)s: missing region\n' % locals())
        sys.exit(1)

    vpcs_file = read_yaml_file('configuration/vpcs.yaml')
    vpcs = vpcs_file['vpcs']
    connections = vpcs_file['connections']

    eips = read_yaml_file('configuration/eips.yaml')

    # NOTE: we look for the base VPC in 'vpcs' and in eips
    # EIP's are allocated per VPC, since it's easier to manage
    if vpc_name not in vpcs:
        print_err('%(vpc_name)s: not found in vpcs\n' % locals())
        sys.exit(1)

    if vpc_name not in eips:
        print_err(
            '%(stack)s: not found in eips; execute "scripts/manage-eips"\n' %
            locals())
        sys.exit(1)

    vpc_id = get_vpc_id(vpc_name, region)

    incoming_connections = map(
        lambda x: x.keys()[0] if isinstance(x, dict) else x,
        list(
            itertools.chain.from_iterable(
                x['from'] for x in connections.values()
                if 'to' in x and vpc_name in x['to'])))

    outgoing_connections = map(
        lambda x: x.keys()[0] if isinstance(x, dict) else x,
        list(
            itertools.chain.from_iterable(
                x['to'] for x in connections.values()
                if 'from' in x and vpc_name in x['from'])))

    # if we expect incoming VPN connections then setup a VPN gateway
    if incoming_connections:
        vpn_gateway = template.add_resource(
            ec2.VPNGateway(
                'VpnGateway',
                Type='ipsec.1',
                Tags=Tags(
                    Name=stack,
                    VPC=vpc_name,
                ),
            ))

        vpn_gateway_attachment = template.add_resource(
            ec2.VPCGatewayAttachment(
                'VpcGatewayAttachment',
                VpcId=vpc_id,
                VpnGatewayId=Ref(vpn_gateway),
            ))

        vpn_gateway_route_propegation = template.add_resource(
            ec2.VPNGatewayRoutePropagation(
                'VpnGatewayRoutePropagation',
                RouteTableIds=get_route_table_ids(vpc_id, region),
                VpnGatewayId=Ref(vpn_gateway),
                DependsOn=Name(vpn_gateway_attachment),
            ))

        for index, connection_from in enumerate(incoming_connections, 1):
            if connection_from not in vpcs:
                print_err(
                    '%(stack)s: vpn from "%(connection_from)s" not found in vpcs\n'
                    % locals())
                sys.exit(1)

            if connection_from not in eips:
                print_err(
                    '%(stack)s: vpn from "%(connection_from)s" not found in eips\n'
                    % locals())
                sys.exit(1)

            alphanumeric_id = ''.join(
                [y.title() for y in connection_from.split('-')])
            customer_gateway = template.add_resource(
                ec2.CustomerGateway(
                    alphanumeric_id + 'CGW',
                    BgpAsn=vpcs[connection_from]['bgp_asn'],
                    IpAddress=eips[connection_from]['public_ip'],
                    Type='ipsec.1',
                    Tags=Tags(
                        Name='%(connection_from)s to %(stack)s' % locals(),
                        VPC=vpc_name,
                    ),
                ))

            vpn_connection = template.add_resource(
                ec2.VPNConnection(
                    alphanumeric_id + 'VPNConnection',
                    # We want this to always be 'False', for BGP
                    StaticRoutesOnly=config['static_routing'],
                    Type='ipsec.1',
                    VpnGatewayId=Ref(vpn_gateway),
                    CustomerGatewayId=Ref(customer_gateway),
                    Tags=Tags(
                        Name='%s CGW: IP %s' %
                        (connection_from, eips[connection_from]['public_ip']),
                        # The Tag 'RemoteVPC' is queried by
                        # configuration process on the remote VPC's NAT
                        # instance to identify the Virtual Connection they
                        # should connect to.
                        # It refers to the VPC stack name, not the WAN stack name
                        RemoteVPC=connection_from,
                        RemoteIp=eips[connection_from]['public_ip'],
                        VPC=vpc_name,
                    ),
                ))

            # Add static routes to the subnets behind each incoming VPN connection
            # NOTE: Can't be used when StaticRoutesOnly is False (which is required
            # when using BGP)
            if config['static_routing']:
                vpn_connection_static_route = template.add_resource(
                    ec2.VPNConnectionRoute(
                        '%(connection_from)s Static Route' % locals(),
                        VpnConnectionId=Ref(vpn_connection),
                        DestinationCidrBlock=vpcs[connection_from]['cidr'],
                    ))

            customer_gateways.append(customer_gateway)

    else:
        vpn_gateway = None

    if outgoing_connections:
        if not region in config['nat']['ami_id']:
            print_err('AMI ID not configured for region "%(region)s"\n' %
                      locals())
            sys.exit(1)

        nat_sg = template.add_resource(
            ec2.SecurityGroup(
                'NatSg',
                VpcId=vpc_id,
                GroupDescription='%(stack)s router Security Group' % locals(),
                SecurityGroupEgress=[
                    ec2.SecurityGroupRule(
                        CidrIp='0.0.0.0/0',
                        IpProtocol='-1',
                        FromPort='-1',
                        ToPort='-1',
                    )
                ],
                SecurityGroupIngress=  # Allow all traffic from internal networks
                map(
                    lambda cidr: ec2.SecurityGroupRule(CidrIp=cidr,
                                                       IpProtocol='-1',
                                                       FromPort='-1',
                                                       ToPort='-1'),
                    ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']) +
                # Allow all traffic from all other locations on our WAN
                map(
                    lambda eip: ec2.SecurityGroupRule(
                        CidrIp=eips[eip]['public_ip'] + '/32',
                        IpProtocol='-1',
                        FromPort='-1',
                        ToPort='-1'), eips.keys()) +
                # Optional extra traffic sources
                map(
                    lambda cidr: ec2.SecurityGroupRule(CidrIp=cidr,
                                                       IpProtocol='-1',
                                                       FromPort='-1',
                                                       ToPort='-1'),
                    config['nat']['extra_ingress_sources'] or {}),
                Tags=Tags(Name='%(stack)s router' % locals(), ),
            ))

        if 'openvpn_server' in config and config['openvpn_server']:
            nat_sg.SecurityGroupIngress.append(
                ec2.SecurityGroupRule(
                    CidrIp='0.0.0.0/0',
                    IpProtocol='udp',
                    FromPort='1194',
                    ToPort='1194',
                ))

            if 'external_tld' in config:
                template.add_resource(
                    route53.RecordSetType(
                        'OpenVpnDnsRecord',
                        Comment='%(stack)s OpenVPN server' % locals(),
                        HostedZoneName=config['external_tld'] + '.',
                        Name='%s.%s.' % (vpc_name, config['external_tld']),
                        ResourceRecords=[eips[vpc_name]['public_ip']],
                        TTL='900',
                        Type='A'))

        assume_role_policy_statement = awacs.aws.Policy(Statement=[
            awacs.aws.Statement(
                Effect=awacs.aws.Allow,
                Principal=awacs.aws.Principal(principal='Service',
                                              resources=['ec2.amazonaws.com']),
                Action=[awacs.sts.AssumeRole],
            )
        ])

        root_role = template.add_resource(
            iam.Role(
                'RootRole',
                AssumeRolePolicyDocument=assume_role_policy_statement,
                Path='/',
            ))

        root_role_policy = template.add_resource(
            iam.PolicyType(
                'RootRolePolicy',
                PolicyName='AllowAllPolicy',
                PolicyDocument={
                    'Version':
                    '2012-10-17',
                    'Statement': [{
                        'Action': '*',
                        'Effect': 'Allow',
                        'Resource': '*',
                    }]
                },
                Roles=[Ref(root_role)],
            ))

        root_instance_profile = template.add_resource(
            iam.InstanceProfile(
                'RootInstanceProfile',
                Path='/',
                Roles=[Ref(root_role)],
            ))

        for index, egress_config in enumerate(config['nat']['sg_egress_rules'],
                                              1):
            template.add_resource(
                ec2.SecurityGroupEgress(
                    'NatSgEgressRule%d' % index,
                    ToPort=egress_config['port'],
                    FromPort=egress_config['port'],
                    IpProtocol=egress_config['protocol'],
                    CidrIp=egress_config['cidr'],
                    GroupId=Ref(nat_sg),
                ))

        launch_configuration = template.add_resource(
            autoscaling.LaunchConfiguration(
                'Ec2NatLaunchConfiguration',
                AssociatePublicIpAddress=True,
                SecurityGroups=[Ref(nat_sg)],
                IamInstanceProfile=Ref(root_instance_profile),
                ImageId=config['nat']['ami_id'][region],
                KeyName=config['nat']['key_name'],
                InstanceType=config['nat']['instance_type'],
                UserData=build_user_data(stack),
            ))

        AutoScalingGroup = template.add_resource(
            autoscaling.AutoScalingGroup(
                'AutoScalingGroup',
                VPCZoneIdentifier=get_public_subnet_ids(vpc_id, region),
                TerminationPolicies=['ClosestToNextInstanceHour'],
                MinSize=1,
                MaxSize=2,
                #####
                # TODO: Have to find a way for VyOS to send the signal without
                # having access to cfn-signal script (old python version)
                # That's also the reason we allow one instance - since ha-nat
                # can't send the signal
                ####
                # CreationPolicy=policies.CreationPolicy(
                #     ResourceSignal=policies.ResourceSignal(
                #         Count=2,
                #         Timeout='PT10M',
                #     ),
                # ),
                LaunchConfigurationName=Ref(launch_configuration),
                HealthCheckType='EC2',
                UpdatePolicy=policies.UpdatePolicy(
                    AutoScalingRollingUpdate=policies.AutoScalingRollingUpdate(
                        MaxBatchSize=1,
                        MinInstancesInService=1,
                        PauseTime='PT2M',
                        # TODO: switch to 'True' when we teach VyOS to send signal
                        WaitOnResourceSignals=False,
                    )),
                Tags=[
                    autoscaling.Tag('Name', stack + ' router', True),
                    autoscaling.Tag('VPC', vpc_name, True),
                    # Just have to be unique for this provisioning run, could
                    # be any unique string
                    autoscaling.Tag(
                        'Version',
                        datetime.datetime.utcnow().strftime(
                            '%Y-%m-%d %H:%M:%S.%f'), True),
                ],
            ))
예제 #26
0
    def set_up_stack(self):
        """Sets up the stack"""
        if not self.INPUTS or not self.STACK_NAME_PREFIX or not self.HEALTH_ENDPOINT:
            raise MKInputError(
                'Must define INPUTS, STACK_NAME_PREFIX, and HEALTH_ENDPOINT')

        super(AppServerStack, self).set_up_stack()

        tags = self.get_input('Tags').copy()
        self.add_description('{} App Server Stack for Cac'.format(
            self.STACK_NAME_PREFIX))

        assert isinstance(tags, dict), 'tags must be a dictionary'

        self.availability_zones = get_availability_zones()

        tags.update({'StackType': 'AppServer'})
        self.default_tags = tags

        self.app_server_instance_type_parameter = self.add_parameter(
            Parameter(
                'AppServerInstanceType',
                Type='String',
                Default='t2.medium',
                Description='NAT EC2 instance type',
                AllowedValues=EC2_INSTANCE_TYPES,
                ConstraintDescription='must be a valid EC2 instance type.'),
            source='AppServerInstanceType')

        self.param_app_server_iam_profile = self.add_parameter(
            Parameter('AppServerIAMProfile',
                      Type='String',
                      Description='IAM Profile for instances'),
            source='AppServerIAMProfile')

        self.app_server_ami = self.add_parameter(Parameter(
            'AppServerAMI',
            Type='String',
            Description='{} Server EC2 AMI'.format(self.STACK_NAME_PREFIX)),
                                                 source='AppServerAMI')

        self.keyname_parameter = self.add_parameter(Parameter(
            'KeyName',
            Type='String',
            Default='cac',
            Description='Name of an existing EC2 key pair'),
                                                    source='KeyName')

        self.param_color = self.add_parameter(Parameter(
            'StackColor',
            Type='String',
            Description='Stack color',
            AllowedValues=['Blue', 'Green', 'Orange']),
                                              source='StackColor')

        self.param_stacktype = self.add_parameter(Parameter(
            'StackType',
            Type='String',
            Description='Stack type',
            AllowedValues=['Development', 'Staging', 'Production']),
                                                  source='StackType')

        self.param_public_hosted_zone_name = self.add_parameter(
            Parameter('PublicHostedZoneName',
                      Type='String',
                      Description='Public hosted zone name'),
            source='PublicHostedZoneName')

        self.param_vpc = self.add_parameter(Parameter(
            'VpcId', Type='String', Description='Name of an existing VPC'),
                                            source='VpcId')

        self.param_notification_arn = self.add_parameter(
            Parameter(
                'GlobalNotificationsARN',
                Type='String',
                Description='Physical resource ID on an AWS::SNS::Topic for '
                'notifications'),
            source='GlobalNotificationsARN')

        self.param_ssl_certificate_arn = self.add_parameter(
            Parameter('SSLCertificateARN',
                      Type='String',
                      Description=
                      'Physical resource ID on an AWS::IAM::ServerCertificate '
                      'for the application server load balancer'),
            source='SSLCertificateARN')

        self.param_public_subnets = self.add_parameter(
            Parameter('PublicSubnets',
                      Type='CommaDelimitedList',
                      Description='A list of public subnets'),
            source='AppServerPublicSubnets')

        self.param_private_subnets = self.add_parameter(
            Parameter('PrivateSubnets',
                      Type='CommaDelimitedList',
                      Description='A list of private subnets'),
            source='AppServerPrivateSubnets')

        self.param_bastion_security_group = self.add_parameter(
            Parameter('BastionSecurityGroup',
                      Type='String',
                      Description='The ID of the bastion security group'),
            source='BastionSecurityGroup')

        self.param_database_security_group = self.add_parameter(
            Parameter('DatabaseSecurityGroup',
                      Type='String',
                      Description='The ID of the database security group'),
            source='DatabaseSecurityGroup')

        self.param_nat_security_group = self.add_parameter(
            Parameter('NATSecurityGroup',
                      Type='String',
                      Description='The ID of the NAT security group'),
            source='NATSecurityGroup')

        self.param_min_size = self.add_parameter(Parameter(
            'ASGMinSize',
            Type='Number',
            Default='1',
            Description='Min size of ASG'),
                                                 source='ASGMinSize')

        self.param_max_size = self.add_parameter(Parameter(
            'ASGMaxSize',
            Type='Number',
            Default='1',
            Description='Max size of ASG'),
                                                 source='ASGMaxSize')

        self.param_desired_capacity = self.add_parameter(
            Parameter('ASGDesiredCapacity',
                      Type='Number',
                      Default='1',
                      Description='Desired capacity of ASG'),
            source='ASGDesiredCapacity')

        #
        # Security Group
        #
        app_server_load_balancer_security_group = self.add_resource(
            ec2.SecurityGroup(
                'sgAppServerLoadBalancer',
                GroupDescription=
                'Enables access to app servers via a load balancer',
                VpcId=Ref(self.param_vpc),
                SecurityGroupIngress=[
                    ec2.SecurityGroupRule(IpProtocol='tcp',
                                          CidrIp=ALLOW_ALL_CIDR,
                                          FromPort=p,
                                          ToPort=p) for p in [80, 443]
                ],
                Tags=Tags(Name='sgAppServerLoadBalancer',
                          Color=Ref(self.param_color))))

        app_server_security_group = self.add_resource(
            ec2.SecurityGroup(
                'sgAppServer',
                GroupDescription='Enables access to App Servers',
                VpcId=Ref(self.param_vpc),
                SecurityGroupIngress=[
                    ec2.SecurityGroupRule(IpProtocol='tcp',
                                          CidrIp=VPC_CIDR,
                                          FromPort=p,
                                          ToPort=p) for p in [22, 80, 443]
                ] + [
                    ec2.SecurityGroupRule(IpProtocol='tcp',
                                          SourceSecurityGroupId=Ref(sg),
                                          FromPort=80,
                                          ToPort=80)
                    for sg in [app_server_load_balancer_security_group]
                ] + [
                    ec2.SecurityGroupRule(IpProtocol='tcp',
                                          SourceSecurityGroupId=Ref(sg),
                                          FromPort=443,
                                          ToPort=443)
                    for sg in [app_server_load_balancer_security_group]
                ],
                SecurityGroupEgress=[
                    ec2.SecurityGroupRule(IpProtocol='tcp',
                                          CidrIp=ALLOW_ALL_CIDR,
                                          FromPort=p,
                                          ToPort=p)
                    for p in [80, 443, PAPERTRAIL_PORT]
                ],
                Tags=Tags(Name='sgAppServer', Color=Ref(self.param_color))))

        # ELB to App Server
        self.add_resource(
            ec2.SecurityGroupEgress(
                'sgEgressELBtoAppHTTP',
                GroupId=Ref(app_server_load_balancer_security_group),
                DestinationSecurityGroupId=Ref(app_server_security_group),
                IpProtocol='tcp',
                FromPort=80,
                ToPort=80))

        self.add_resource(
            ec2.SecurityGroupEgress(
                'sgEgressELBtoAppHTTPS',
                GroupId=Ref(app_server_load_balancer_security_group),
                DestinationSecurityGroupId=Ref(app_server_security_group),
                IpProtocol='tcp',
                FromPort=443,
                ToPort=443))

        # Bastion to App Server, app server to db, app server to inet
        rules = [(self.param_bastion_security_group, app_server_security_group,
                  [80, 443, 22]),
                 (app_server_security_group,
                  self.param_database_security_group, [POSTGRES]),
                 (app_server_security_group, self.param_nat_security_group,
                  [80, 443, 22, 587, PAPERTRAIL_PORT])]
        for num, (srcsg, destsg, ports) in enumerate(rules):
            for port in ports:
                self.add_resource(
                    ec2.SecurityGroupEgress(
                        'sgEgress{}p{}'.format(num, port),
                        GroupId=Ref(srcsg),
                        DestinationSecurityGroupId=Ref(destsg),
                        IpProtocol='tcp',
                        FromPort=port,
                        ToPort=port))
                self.add_resource(
                    ec2.SecurityGroupIngress('sgIngress{}p{}'.format(
                        num, port),
                                             GroupId=Ref(destsg),
                                             SourceSecurityGroupId=Ref(srcsg),
                                             IpProtocol='tcp',
                                             FromPort=port,
                                             ToPort=port))

        #
        # ELB
        #
        app_server_load_balancer = self.add_resource(
            elb.LoadBalancer(
                'elbAppServer',
                ConnectionDrainingPolicy=elb.ConnectionDrainingPolicy(
                    Enabled=True, Timeout=300),
                CrossZone=True,
                SecurityGroups=[Ref(app_server_load_balancer_security_group)],
                Listeners=[
                    elb.Listener(LoadBalancerPort='80',
                                 Protocol='HTTP',
                                 InstancePort='80',
                                 InstanceProtocol='HTTP'),
                    elb.Listener(LoadBalancerPort='443',
                                 Protocol='HTTPS',
                                 InstancePort='443',
                                 InstanceProtocol='HTTP',
                                 SSLCertificateId=Ref(
                                     self.param_ssl_certificate_arn))
                ],
                HealthCheck=elb.HealthCheck(
                    Target=self.HEALTH_ENDPOINT,
                    HealthyThreshold='3',
                    UnhealthyThreshold='2',
                    Interval='30',
                    Timeout='5',
                ),
                Subnets=Ref(self.param_public_subnets),
                Tags=Tags(Name='elbAppServer', Color=Ref(self.param_color))))

        self.add_resource(
            cw.Alarm('alarmAppServerBackend4xx',
                     AlarmActions=[Ref(self.param_notification_arn)],
                     Statistic='Sum',
                     Period=300,
                     Threshold='5',
                     EvaluationPeriods=1,
                     ComparisonOperator='GreaterThanThreshold',
                     MetricName='HTTPCode_Backend_4XX',
                     Namespace='AWS/ELB',
                     Dimensions=[
                         cw.MetricDimension(
                             'metricLoadBalancerName',
                             Name='LoadBalancerName',
                             Value=Ref(app_server_load_balancer))
                     ]))

        self.add_resource(
            cw.Alarm('alarmAppServerBackend5xx',
                     AlarmActions=[Ref(self.param_notification_arn)],
                     Statistic='Sum',
                     Period=60,
                     Threshold='0',
                     EvaluationPeriods=1,
                     ComparisonOperator='GreaterThanThreshold',
                     MetricName='HTTPCode_Backend_5XX',
                     Namespace='AWS/ELB',
                     Dimensions=[
                         cw.MetricDimension(
                             'metricLoadBalancerName',
                             Name='LoadBalancerName',
                             Value=Ref(app_server_load_balancer))
                     ]))

        #
        # ASG
        #
        app_server_launch_config = self.add_resource(
            asg.LaunchConfiguration(
                'lcAppServer',
                ImageId=Ref(self.app_server_ami),
                IamInstanceProfile=Ref(self.param_app_server_iam_profile),
                InstanceType=Ref(self.app_server_instance_type_parameter),
                KeyName=Ref(self.keyname_parameter),
                SecurityGroups=[Ref(app_server_security_group)]))

        autoscaling_group = self.add_resource(
            asg.AutoScalingGroup(
                'asgAppServer',
                AvailabilityZones=self.get_input(
                    'AppServerAvailabilityZones').split(','),
                Cooldown=300,
                DesiredCapacity=Ref(self.param_desired_capacity),
                HealthCheckGracePeriod=600,
                HealthCheckType='ELB',
                LaunchConfigurationName=Ref(app_server_launch_config),
                LoadBalancerNames=[Ref(app_server_load_balancer)],
                MaxSize=Ref(self.param_max_size),
                MinSize=Ref(self.param_min_size),
                NotificationConfiguration=asg.NotificationConfiguration(
                    TopicARN=Ref(self.param_notification_arn),
                    NotificationTypes=[
                        asg.EC2_INSTANCE_LAUNCH, asg.EC2_INSTANCE_LAUNCH_ERROR,
                        asg.EC2_INSTANCE_TERMINATE,
                        asg.EC2_INSTANCE_TERMINATE_ERROR
                    ]),
                VPCZoneIdentifier=Ref(self.param_private_subnets),
                Tags=[
                    asg.Tag('Name', '{}Server'.format(self.STACK_NAME_PREFIX),
                            True),
                    asg.Tag('Color', Ref(self.param_color), True)
                ]))

        # autoscaling policies
        autoscaling_policy_add = self.add_resource(
            asg.ScalingPolicy('scalingPolicyAddAppServer',
                              AdjustmentType='ChangeInCapacity',
                              AutoScalingGroupName=Ref(autoscaling_group),
                              Cooldown=600,
                              ScalingAdjustment='1'))

        autoscaling_policy_remove = self.add_resource(
            asg.ScalingPolicy('scalingPolicyRemoveAppServer',
                              AdjustmentType='ChangeInCapacity',
                              AutoScalingGroupName=Ref(autoscaling_group),
                              Cooldown=600,
                              ScalingAdjustment='-1'))

        if self.STACK_NAME_PREFIX == 'Otp':
            # trigger scale down if CPU avg usage < 10% for 3 consecutive 5 min periods
            self.add_resource(
                cw.Alarm('alarmAppServerLowCPU',
                         AlarmActions=[Ref(autoscaling_policy_remove)],
                         Statistic='Average',
                         Period=300,
                         Threshold='10',
                         EvaluationPeriods=3,
                         ComparisonOperator='LessThanThreshold',
                         MetricName='CPUUtilization',
                         Namespace='AWS/EC2',
                         Dimensions=[
                             cw.MetricDimension('metricAutoScalingGroupName',
                                                Name='AutoScalingGroupName',
                                                Value=Ref(autoscaling_group))
                         ]))

            # trigger scale up if CPU avg usage >= 30% for a 5 min period
            self.add_resource(
                cw.Alarm('alarmAppServerHighCPU',
                         AlarmActions=[
                             Ref(self.param_notification_arn),
                             Ref(autoscaling_policy_add)
                         ],
                         Statistic='Average',
                         Period=300,
                         Threshold='30',
                         EvaluationPeriods=1,
                         ComparisonOperator='GreaterThanOrEqualToThreshold',
                         MetricName='CPUUtilization',
                         Namespace='AWS/EC2',
                         Dimensions=[
                             cw.MetricDimension('metricAutoScalingGroupName',
                                                Name='AutoScalingGroupName',
                                                Value=Ref(autoscaling_group))
                         ]))
        else:
            # scale web servers based on network usage
            self.add_resource(
                cw.Alarm('alarmAppServerLowNetworkUsage',
                         AlarmActions=[Ref(autoscaling_policy_remove)],
                         Statistic='Average',
                         Period=300,
                         Threshold='500000',
                         EvaluationPeriods=3,
                         ComparisonOperator='LessThanThreshold',
                         MetricName='NetworkOut',
                         Namespace='AWS/EC2',
                         Dimensions=[
                             cw.MetricDimension('metricAutoScalingGroupName',
                                                Name='AutoScalingGroupName',
                                                Value=Ref(autoscaling_group))
                         ]))

            self.add_resource(
                cw.Alarm('alarmAppServerHighNetworkUsage',
                         AlarmActions=[
                             Ref(self.param_notification_arn),
                             Ref(autoscaling_policy_add)
                         ],
                         Statistic='Average',
                         Period=300,
                         Threshold='10000000',
                         EvaluationPeriods=1,
                         ComparisonOperator='GreaterThanOrEqualToThreshold',
                         MetricName='NetworkOut',
                         Namespace='AWS/EC2',
                         Dimensions=[
                             cw.MetricDimension('metricAutoScalingGroupName',
                                                Name='AutoScalingGroupName',
                                                Value=Ref(autoscaling_group))
                         ]))

        #
        # DNS name
        #
        self.create_resource(
            route53.RecordSetType(
                'dnsName',
                Name=Join('.', [
                    Ref(self.param_color),
                    Ref(self.param_stacktype), self.STACK_NAME_PREFIX,
                    Ref(self.param_public_hosted_zone_name)
                ]),
                Type='A',
                AliasTarget=route53.AliasTarget(
                    GetAtt(app_server_load_balancer,
                           'CanonicalHostedZoneNameID'),
                    GetAtt(app_server_load_balancer, 'DNSName')),
                HostedZoneName=Ref(self.param_public_hosted_zone_name)))

        self.add_output([
            Output('{}ServerLoadBalancerEndpoint'.format(
                self.STACK_NAME_PREFIX),
                   Description='Application server endpoint',
                   Value=GetAtt(app_server_load_balancer, 'DNSName')),
            Output('{}ServerLoadBalancerHostedZoneNameID'.format(
                self.STACK_NAME_PREFIX),
                   Description='ID of canonical hosted zone name for ELB',
                   Value=GetAtt(app_server_load_balancer,
                                'CanonicalHostedZoneNameID'))
        ])
예제 #27
0
    def __init__(self, tags=dict()):
        super(RDSFactory, self).__init__()
        self.tags = tags
        # Largely copied from
        # https://github.com/cloudtools/troposphere/blob/master/examples/RDS_VPC.py

        # Each parameter is followed by the resources which depend on it.
        # VPC and security groups
        vpcid = Parameter(
            'VpcId',
            Type='String',
            Description='Id of existing VPC'
        )
        private_hosted_zone_id = Parameter(
            'PrivateHostedZoneId',
            Type='String',
            Description='Private hosted zone id'
        )
        db_security_group = ec2.SecurityGroup(
            'sgDatabase',
            GroupDescription='Security group for RDS DB Instance.',
            VpcId=Ref(vpcid),
            Tags=Tags(Name='Database', **self.tags)
        )

        # Subnets
        subnets = Parameter(
            'AppServerSubnets',
            Type='CommaDelimitedList',
            Description='List of SubnetIds spanning at least two AZs in VPC'
        )
        subnet_group = rds.DBSubnetGroup(
            'CacDbSubnetGroup',
            DBSubnetGroupDescription='Subnets available for Cac RDS instance',
            SubnetIds=Ref(subnets),
            Tags=Tags(Name='RDSSubnetGroup', **self.tags)
        )

        # Database
        db_name = Parameter(
            'DbName',
            Description='Name of the database to be created',
            Type='String',
            MinLength='5',
            MaxLength='63',
            AllowedPattern='[a-zA-Z_][a-zA-Z0-9_]*',
            ConstraintDescription='Name must begin with a letter and contain only alphanumerics'
        )
        db_user = Parameter(
            'DbUser',
            NoEcho=True,
            Description='Database admin user account',
            Type='String',
            MinLength='5',
            MaxLength='16',
            AllowedPattern='[a-zA-Z][a-zA-Z0-9]*',
            ConstraintDescription='Name must begin with a letter and contain only alphanumerics'
        )
        db_password = Parameter(
            'DbPassword',
            NoEcho=True,
            Description='Database admin account password',
            Type='String',
            MinLength='8',
        )
        db_instance_class = Parameter(
            'DbInstanceClass',
            Default='db.m3.medium',
            Description='Database instance class',
            Type='String',
            AllowedValues=RDS_INSTANCE_TYPES
        )
        db_storage = Parameter(
            'DbStorage',
            Description='Available database storage (GB)',
            Default='100',
            Type='Number',
            MaxValue='1024',
            ConstraintDescription='Storage space must be less than 1024GB',
        )
        db_dns_name = Parameter(
            'DbDNSName',
            Type='String',
            Description='Private DNS name for database'
        )

        database = rds.DBInstance(
            'CacDb',
            DBName=Ref(db_name),
            AllocatedStorage=Ref(db_storage),
            DBInstanceClass=Ref(db_instance_class),
            Engine='postgres',
            EngineVersion='9.3',
            MasterUsername=Ref(db_user),
            MasterUserPassword=Ref(db_password),
            DBSubnetGroupName=Ref(subnet_group),
            VPCSecurityGroups=[Ref(db_security_group)],
            MultiAZ=True,
            Tags=Tags(Name='CacDB', **self.tags)
        )

        db_dns_record = route53.RecordSetType(
            'rsDatabase',
            Name=Ref(db_dns_name),
            ResourceRecords=[GetAtt('CacDb', 'Endpoint.Address')],
            TTL=600,
            Type='CNAME',
            HostedZoneId=Ref(private_hosted_zone_id),
        )

        # Outputs
        rds_endpoint = Output(
            'CacDbEndpoint',
            Description='Endpoint to which Postgres clients should connect',
            Value=GetAtt('CacDb', 'Endpoint.Address')
        )

        database_name = Output(
            'CacDbName',
            Description='Name of database created on Cac RDS instance',
            Value=Ref(db_name)
        )

        db_sg = Output(
            'DatabaseSecurityGroup',
            Description='Security Group of Database',
            Value=GetAtt('sgDatabase', 'GroupId')
        )

        self.parameters = [vpcid, private_hosted_zone_id, subnets, db_name,
                           db_user, db_password, db_instance_class,
                           db_storage, db_dns_name]

        self.resources = [db_security_group, subnet_group, database,
                          db_dns_record]

        self.outputs = [rds_endpoint, database_name, db_sg]
예제 #28
0
                SslSupportMethod='sni-only',
            ),
        ),
        Tags=GetAtt(cloudformation_tags, 'TagList'),
    ))

hosted_zone_map = "HostedZoneMap"
template.add_mapping(hosted_zone_map, cfnutils.mappings.r53_hosted_zone_id())

template.add_resource(
    route53.RecordSetType(
        "DomainA",
        AliasTarget=route53.AliasTarget(
            DNSName=GetAtt(example_distribution, 'DomainName'),
            HostedZoneId=FindInMap(hosted_zone_map, Ref(AWS_REGION),
                                   'CloudFront'),
        ),
        Comment=Sub('DNS for ${AWS::StackName}'),
        HostedZoneName=Join('', [Ref(param_hosted_zone_name), '.']),
        Name=domain_name,
        Type='A',
    ))
template.add_resource(
    route53.RecordSetType(
        "DomainAAAA",
        AliasTarget=route53.AliasTarget(
            DNSName=GetAtt(example_distribution, 'DomainName'),
            HostedZoneId=FindInMap(hosted_zone_map, Ref(AWS_REGION),
                                   'CloudFront'),
        ),
        Comment=Sub('DNS for ${AWS::StackName}'),
        HostedZoneName=Join('', [Ref(param_hosted_zone_name), '.']),
        Stage='Prod',  # Default name of Serverless generated Stage
        Condition=use_cert_cond,
    ))

hosted_zone_map = "HostedZoneMap"
template.add_mapping(hosted_zone_map, cfnutils.mappings.r53_hosted_zone_id())

template.add_resource(
    route53.RecordSetType(
        "DomainA",
        AliasTarget=route53.AliasTarget(
            DNSName=GetAtt(api_domain, 'DistributionDomainName'),
            HostedZoneId=FindInMap(hosted_zone_map, Ref(AWS_REGION),
                                   'CloudFront'),
        ),
        Comment=Sub('Default DNS for ${AWS::StackName} api'),
        HostedZoneName=Join('', [Ref(param_hosted_zone_name), '.']),
        Name=Join(
            '.',
            [Ref(param_label), Ref(param_hosted_zone_name)]),
        Type='A',
        Condition=use_cert_cond,
    ))

template.add_resource(
    route53.RecordSetType(
        "DomainAAAA",
        AliasTarget=route53.AliasTarget(
            DNSName=GetAtt(api_domain, 'DistributionDomainName'),
            HostedZoneId=FindInMap(hosted_zone_map, Ref(AWS_REGION),
                                   'CloudFront'),
param_target = t.add_parameter(
    Parameter(
        'Target',
        Description='Alias/cname target',
        Type='String',
    ))

#
# Resource
#

record = t.add_resource(
    route53.RecordSetType(
        'Record',
        HostedZoneName=Sub('${HostedZoneName}.'),
        Name=Join('.', [Ref(param_domain_name),
                        Ref(param_hosted_domain)]),
        Type=Ref(param_record_type),
        TTL=Ref(param_ttl),
        ResourceRecords=[Ref(param_target)]))

#
# Output
#
t.add_output([
    Output(
        'DnsName',
        Description='DNS name',
        Value=Ref(record),
        Export=Export(Sub('${AWS::StackName}-DnsName')),
    ),
])