Example #1
0
 def test_redirect_action(self):
     Action(Type='redirect',
            RedirectConfig=RedirectConfig(
                StatusCode='HTTP_301',
                Protocol='HTTPS',
                Host='api.troposphere.org',
                Path='redirect/#{path}')).to_dict()
Example #2
0
 def test_fixed_response_config_only_with_fixed_response(self):
     with self.assertRaises(ValueError):
         Action(
             Type="forward",
             FixedResponseConfig=FixedResponseConfig(
                 ContentType="text/plain", ),
         ).to_dict()
Example #3
0
 def __init__(self, title, template, *args, **kwargs):
     self.props['Port'] = (str, True)
     self.props['Certificates'] = (list, True)
     self.props['VpcId'] = (str, True)
     super().__init__(title, template, *args, **kwargs)
     target_group = TargetGroup(title + 'dummy',
                                VpcId=self.properties['VpcId'],
                                Port='80',
                                Protocol='HTTP')
     template.add_resource(target_group)
     template.add_resource(
         Listener(title + "httpslistener",
                  LoadBalancerArn=Ref(self),
                  Port=self.properties['Port'],
                  Protocol='HTTPS',
                  Certificates=self.properties['Certificates'],
                  DefaultActions=[
                      Action(Type='forward',
                             TargetGroupArn=Ref(target_group))
                  ]))
     self.props.pop('Port')
     self.properties.pop('Port')
     self.props.pop('Certificates')
     self.properties.pop('Certificates')
     self.props.pop('VpcId')
     self.properties.pop('VpcId')
Example #4
0
def __create_load_balancer():
    template = Template()
    load_balancer = template.add_resource(resource=LoadBalancer(
        title='SampleFargateLoadBalancer',
        Name='sample-fargate-load-balancer',
        Subnets=[
            ImportValue(CommonResource.ExportName.PUBLIC_SUBNET_A_ID.value),
            ImportValue(CommonResource.ExportName.PUBLIC_SUBNET_B_ID.value)
        ],
        SecurityGroups=[ImportValue(ExportName.ALB_SECURITY_GROUP.value)],
        Scheme='internet-facing'))

    target_group = template.add_resource(resource=TargetGroup(
        title='SampleFargateTargetGroup',
        Port=80,
        Protocol='HTTP',
        TargetType='ip',
        VpcId=ImportValue(CommonResource.ExportName.VPC_ID.value)))
    template.add_output(output=Output(title=target_group.title,
                                      Value=Ref(target_group),
                                      Export=Export(
                                          name=ExportName.TARGET_GROUP.value)))

    template.add_resource(resource=Listener(
        title='SampleFargateListener',
        DefaultActions=[
            Action(Type='forward', TargetGroupArn=Ref(target_group))
        ],
        LoadBalancerArn=Ref(load_balancer),
        Port=80,
        Protocol='HTTP'))

    output_template_file(template, 'alb.yml')

    return target_group
 def test_redirect_config_only_with_redirect(self):
     with self.assertRaises(ValueError):
         Action(
             Type='forward',
             RedirectConfig=RedirectConfig(
                 StatusCode='HTTP_301',
             )
         ).to_dict()
Example #6
0
 def test_fixed_response_action(self):
     Action(
         Type="fixed-response",
         FixedResponseConfig=FixedResponseConfig(
             ContentType="text/plain",
             MessageBody="I am a fixed response",
             StatusCode="200",
         ),
     ).to_dict()
 def test_fixed_response_action(self):
     Action(
         Type='fixed-response',
         FixedResponseConfig=FixedResponseConfig(
             ContentType='text/plain',
             MessageBody='I am a fixed response',
             StatusCode='200'
         )
     ).to_dict()
Example #8
0
 def test_redirect_action(self):
     Action(
         Type="redirect",
         RedirectConfig=RedirectConfig(
             StatusCode="HTTP_301",
             Protocol="HTTPS",
             Host="api.troposphere.org",
             Path="redirect/#{path}",
         ),
     ).to_dict()
Example #9
0
def create_alb_template():
    template = Template()

    vpc = template.add_parameter(
        parameter=Parameter(title='Vpc', Type='String'))
    subnet_a = template.add_parameter(
        parameter=Parameter(title='SubnetA', Type='String'))
    subnet_b = template.add_parameter(
        parameter=Parameter(title='SubnetB', Type='String'))
    ec2_instance = template.add_parameter(
        parameter=Parameter(title='Ec2Instance', Type='String'))

    security_group = template.add_resource(
        resource=SecurityGroup(title='SampleSecurityGroup',
                               GroupDescription='sample-security-group',
                               SecurityGroupIngress=[{
                                   'IpProtocol': 'tcp',
                                   'FromPort': 80,
                                   'ToPort': 80,
                                   'CidrIp': '0.0.0.0/0'
                               }],
                               VpcId=Ref(vpc)))

    load_balancer = template.add_resource(resource=LoadBalancer(
        title='SampleLoadBalancer',
        Name='sample-alb',
        Subnets=[Ref(subnet_a), Ref(subnet_b)],
        SecurityGroups=[Ref(security_group)],
    ))

    target_group = template.add_resource(resource=TargetGroup(
        title='SampleTargetGroup',
        Targets=[TargetDescription(
            Id=Ref(ec2_instance),
            Port=80,
        )],
        VpcId=Ref(vpc),
        Name='sample-target-group',
        Port=80,
        Protocol='HTTP',
    ))

    template.add_resource(resource=Listener(
        title='SampleListener',
        DefaultActions=[
            Action(TargetGroupArn=Ref(target_group), Type='forward')
        ],
        LoadBalancerArn=Ref(load_balancer),
        Port=80,
        Protocol='HTTP',
    ))

    with open('./alb.yml', mode='w') as file:
        file.write(template.to_yaml())
 def add_alb_listener(self):
     '''
     Add an ALB listner
     '''
     self.cfn_template.add_resource(Listener(
         title=constants.LISTENER,
         DefaultActions=[Action(
             TargetGroupArn=Ref(constants.ALB_TG),
             Type='forward')],
         LoadBalancerArn=Ref(constants.ALB),
         Port=int('8228'),
         Protocol='HTTP'))
     return self.cfn_template
Example #11
0
def tea_pot(default_of_all=False) -> Action:
    """
    Predefined reply for ALB config rule, returning HTTP Tea Pot
    """
    return Action(
        FixedResponseConfig=FixedResponseConfig(
            ContentType="application/json",
            MessageBody=dumps({"Info": "Be our guest"}),
            StatusCode="418",
        ),
        Type="fixed-response",
        Order=Ref(AWS_NO_VALUE) if not default_of_all else 50000,
    )
Example #12
0
def http_to_https_default(default_of_all=False) -> Action:
    """
    Predefined rule to redirect HTTP to HTTPS
    """
    return Action(
        RedirectConfig=RedirectConfig(
            Protocol="HTTPS",
            Port="443",
            Host="#{host}",
            Path="/#{path}",
            Query="#{query}",
            StatusCode=r"HTTP_301",
        ),
        Type="redirect",
        Order=Ref(AWS_NO_VALUE) if not default_of_all else 50000,
    )
 def _add_service_listener(self, service_name, target_group_action,
                           alb, internal):
     ssl_cert = Certificate(CertificateArn=self.ssl_certificate_arn)
     service_listener = Listener(
         "SslLoadBalancerListener" + service_name,
         Protocol="HTTPS",
         DefaultActions=[target_group_action],
         LoadBalancerArn=Ref(alb),
         Port=443,
         Certificates=[ssl_cert],
         SslPolicy="ELBSecurityPolicy-FS-1-2-Res-2019-08"
     )
     self.template.add_resource(service_listener)
     if internal:
         # Allow HTTP traffic on internal services
         http_service_listener = Listener(
             "LoadBalancerListener" + service_name,
             Protocol="HTTP",
             DefaultActions=[target_group_action],
             LoadBalancerArn=Ref(alb),
             Port=80
         )
         self.template.add_resource(http_service_listener)
     else:
         # Redirect HTTP to HTTPS on external services
         redirection_config = RedirectConfig(
             StatusCode='HTTP_301',
             Protocol='HTTPS',
             Port='443'
         )
         http_redirection_action = Action(
             RedirectConfig=redirection_config,
             Type="redirect"
         )
         http_redirection_listener = Listener(
             "LoadBalancerRedirectionListener" + service_name,
             Protocol="HTTP",
             DefaultActions=[http_redirection_action],
             LoadBalancerArn=Ref(alb),
             Port=80
         )
         self.template.add_resource(http_redirection_listener)
     return service_listener
Example #14
0
template.add_output(Output(
    "LoadBalancerDNSName",
    Description="Loadbalancer DNS",
    Value=GetAtt(application_load_balancer, "DNSName")
))


application_listener = Listener(
    'ApplicationListener',
    template=template,
    LoadBalancerArn=Ref(application_load_balancer),
    Protocol='HTTP',
    Port=8080,
    DefaultActions=[Action(
        TargetGroupArn=Ref(application_target_group),
        Type='forward',
    )]
)


# ECS cluster
cluster = Cluster(
    "Cluster",
    template=template,
)


# ECS container role
container_instance_role = iam.Role(
    "ContainerInstanceRole",
    template=template,
Example #15
0
    def to_json(self):
        if self._json is not None:
            return self._json

        # Validity checks
        if len(self.subnet_ids) < 2:
            raise ValidationException(
                "Use .subnet_id() to specify at least two ELB subnets")
        if len(self.cert_ids) < 1:
            raise ValidationException(
                "Use .certificate_id() to specify at least one certificate")
        if not self._ecs_redirect and len(self.default_targets) < 1:
            raise ValidationException(
                "Use .default_target() to specify at least one default target or .ecs_redirect("
                ") to set up a redirect container")
        for (name, tp) in self.target_paths.iteritems():
            if len(set(map(lambda h: h.type, tp.hosts))) != 1:
                raise ValidationException(
                    "Inconsistent target types for %s. All hosts for a given path must have the "
                    "same type (ip or instance)." % name)

        # Build Security Group
        if self._custom_elb_sgs:
            elb_sgs = self._custom_elb_sgs
        else:
            elb_sg = SecurityGroup(
                "ElbSecurityGroup",
                GroupDescription=Sub("${AWS::StackName}-ElbSg"),
                Tags=self.tags_with(Name=Sub("${AWS::StackName}-ElbSg")),
                VpcId=self.vpc_id,
                SecurityGroupEgress=[
                    SecurityGroupRule(CidrIp="0.0.0.0/0", IpProtocol="-1")
                ],
                SecurityGroupIngress=self._sg_rules)
            self.template.add_resource(elb_sg)
            self.template.add_output(
                Output("ElbSecurityGroupOutput",
                       Description="Security group ID assigned to the ELB",
                       Value=Ref(elb_sg),
                       Export=Export(Sub("${AWS::StackName}-ElbSg"))))

            # Build Attachment Security Group
            inst_sg = SecurityGroup(
                "InstanceSecurityGroup",
                GroupDescription=Sub("${AWS::StackName}-InstSg"),
                Tags=self.tags_with(Name=Sub("${AWS::StackName}-InstSg")),
                VpcId=self.vpc_id,
                SecurityGroupEgress=[
                    SecurityGroupRule(CidrIp="0.0.0.0/0", IpProtocol="-1")
                ],
                SecurityGroupIngress=[
                    SecurityGroupRule(IpProtocol="-1",
                                      SourceSecurityGroupId=Ref(elb_sg))
                ])
            self.template.add_resource(inst_sg)
            self.template.add_output(
                Output("InstanceSecurityGroupOutput",
                       Description="Convenience SG to assign to instances",
                       Value=Ref(inst_sg),
                       Export=Export(Sub("${AWS::StackName}-InstSg"))))
            elb_sgs = [Ref("ElbSecurityGroup")]

        # Build ELB
        elb = LoadBalancer("ELB",
                           Name=Ref("AWS::StackName"),
                           SecurityGroups=elb_sgs,
                           Subnets=self.subnet_ids,
                           Tags=self.tags_with(Name=Ref("AWS::StackName")),
                           LoadBalancerAttributes=self.elb_attributes())
        self.template.add_resource(elb)
        self.template.add_output(
            Output("ElbArnOutput",
                   Description="ARN of the ELB",
                   Value=Ref(elb),
                   Export=Export(Sub("${AWS::StackName}-ElbArn"))))
        self.template.add_output(
            Output("ElbDnsOutput",
                   Description="DNS name of the ELB",
                   Value=GetAtt("ELB", "DNSName"),
                   Export=Export(Sub("${AWS::StackName}-ElbDns"))))

        # Build Default Target Group
        if self._ecs_redirect:
            default_tg_protocol = "HTTP"
        else:
            default_tg_protocol = self.default_targets[0].protocol
        default_tg = TargetGroup(
            "DefaultTargetGroup",
            Port=8080,
            Protocol=default_tg_protocol,
            Tags=self.tags_with(Name=Sub("${AWS::StackName}-Default")),
            VpcId=self.vpc_id,
            Targets=list(
                map(lambda h: TargetDescription(Id=h.host, Port=h.port),
                    self.default_targets)),
            HealthyThresholdCount=2,
            Matcher=Matcher(HttpCode="200-399"))
        self.template.add_resource(default_tg)
        self.attach_alarm(default_tg)

        # Build Listener
        self.template.add_resource(
            Listener("HttpsListener",
                     Certificates=list(
                         map(lambda i: Certificate(CertificateArn=i),
                             self.cert_ids)),
                     DefaultActions=[
                         Action(Type="forward",
                                TargetGroupArn=Ref("DefaultTargetGroup"))
                     ],
                     LoadBalancerArn=Ref("ELB"),
                     Port=443,
                     Protocol="HTTPS"))

        # Build HTTP redirect
        if len(self.http_redirect_targets) > 0:
            # Build Redirect Target Group
            http_tg = TargetGroup(
                "RedirectTargetGroup",
                Port=8080,
                Protocol=self.http_redirect_targets[0].protocol,
                Tags=self.tags_with(Name=Sub("${AWS::StackName}-Redirect")),
                VpcId=self.vpc_id,
                Targets=list(
                    map(lambda h: TargetDescription(Id=h.host, Port=h.port),
                        self.http_redirect_targets)),
                HealthyThresholdCount=2,
                Matcher=Matcher(HttpCode="200-399"))
            self.template.add_resource(http_tg)
            self.attach_alarm(http_tg)

        if self._ecs_redirect or len(self.http_redirect_targets) > 0:
            if self._ecs_redirect:
                redirect_tg = "DefaultTargetGroup"
            else:
                redirect_tg = "RedirectTargetGroup"
            # Build Listener
            self.template.add_resource(
                Listener("HttpListener",
                         DefaultActions=[
                             Action(Type="forward",
                                    TargetGroupArn=Ref(redirect_tg))
                         ],
                         LoadBalancerArn=Ref("ELB"),
                         Port=80,
                         Protocol="HTTP"))

        # Build Target Groups & Rules
        for (name, tp) in self.target_paths.iteritems():
            name_an = alpha_numeric_name(name)
            tag_name = taggable_name(name)

            g = TargetGroup(
                "PathTg" + name_an,
                Port=tp.hosts[0].port,
                Protocol=tp.hosts[0].protocol,
                Tags=self.tags_with(Name="%s/%s" % (self.env_name, tag_name),
                                    TargetPath=tag_name),
                Targets=list(map(lambda h: h.to_target_desc(), tp.hosts)),
                VpcId=self.vpc_id,
                HealthCheckPath="/%s" % name,
                HealthyThresholdCount=2,
                Matcher=tp.health_check_matcher)

            # TODO: We should probably explicitly specify this for every TG. Not
            #       doing that now because it will cause lots of updates. Maybe
            #       in 0.4?
            if len(tp.hosts) > 0 and tp.hosts[0].type != "instance":
                g.TargetType = tp.hosts[0].type

            if self.sticky:
                g.TargetGroupAttributes = [
                    TargetGroupAttribute(Key="stickiness.enabled",
                                         Value="true"),
                    TargetGroupAttribute(Key="stickiness.type",
                                         Value="lb_cookie")
                ]
            self.template.add_resource(g)
            self.attach_alarm(g)
            self.template.add_resource(
                ListenerRule(
                    "PathRl" + name_an,
                    Actions=[Action(Type="forward", TargetGroupArn=Ref(g))],
                    Conditions=[
                        Condition(Field="path-pattern",
                                  Values=["/%s/*" % name])
                    ],
                    ListenerArn=Ref("HttpsListener"),
                    Priority=self.priority_hash(name)))
            self.template.add_resource(
                ListenerRule(
                    "PathRln" + name_an,
                    Actions=[Action(Type="forward", TargetGroupArn=Ref(g))],
                    Conditions=[
                        Condition(Field="path-pattern", Values=["/%s" % name])
                    ],
                    ListenerArn=Ref("HttpsListener"),
                    Priority=self.priority_hash(name)))

        # Build Alternate Listeners
        for al in self.alt_listeners:
            tg_name = "AltTg%d" % al.port
            tg_protocol = al.hosts[0].protocol
            tg = TargetGroup(
                tg_name,
                Port=9999,
                Protocol=tg_protocol,
                Tags=self.tags_with(Name=Sub("${AWS::StackName}-%s" %
                                             tg_name)),
                VpcId=self.vpc_id,
                Targets=list(
                    map(lambda h: TargetDescription(Id=h.host, Port=h.port),
                        al.hosts)),
                HealthyThresholdCount=2,
                Matcher=Matcher(HttpCode="200-399"))
            self.template.add_resource(tg)
            self.attach_alarm(tg)

            listener = Listener("AltListener%d" % al.port,
                                DefaultActions=[
                                    Action(Type="forward",
                                           TargetGroupArn=Ref(tg_name))
                                ],
                                LoadBalancerArn=Ref("ELB"),
                                Port=al.port,
                                Protocol=al.protocol)

            if al.protocol == "HTTPS":
                listener.Certificates = list(
                    map(lambda i: Certificate(CertificateArn=i),
                        self.cert_ids))

            self.template.add_resource(listener)

        self._json = self.template.to_json()
        return self._json
Example #16
0
test_target_group = TargetGroup(
    "targetgroup",
    Name="service-live",
    Port=80,
    Protocol="HTTP",
    TargetType="instance",
    VpcId=vpc_id
)
template.add_resource(test_target_group)

listener_rule = ListenerRule(
    "listenerrule",
    Actions=[
        Action(
            TargetGroupArn=Ref(test_target_group),
            Type='forward'
        )
    ],
    Conditions=[
        Condition(
            Field="path-pattern",
            Values=[
                "/"
            ]
        )
    ],
    Priority=1,
    ListenerArn="arn:aws:elasticloadbalancing:eu-west-1:837380460554:listener/app/live-euwes-14F0KA84VQMOV/95ccdb141691f73e/01a71f7b4d1f6a1d"
)

template.add_resource(listener_rule)
Example #17
0
def build_template(sierrafile):
    template = Template()

    template.add_version('2010-09-09')

    template.add_metadata(build_interface(sierrafile.extra_params))

    parameters = AttrDict(

        # Network Parameters

        vpc_cidr=template.add_parameter(Parameter(
            'VpcCidr',
            Type='String',
            Default='192.172.0.0/16',
        )),
        subnet1_cidr=template.add_parameter(Parameter(
            'Subnet1Cidr',
            Type='String',
            Default='192.172.1.0/24',
        )),
        subnet2_cidr=template.add_parameter(Parameter(
            'Subnet2Cidr',
            Type='String',
            Default='192.172.2.0/24',
        )),

        # ECS Parameters

        cluster_size=template.add_parameter(Parameter(
            'ClusterSize',
            Type='Number',
            Default=2,
        )),
        instance_type=template.add_parameter(Parameter(
            'InstanceType',
            Type='String',
            Default='t2.medium'
        )),
        key_name=template.add_parameter(Parameter(
            'KeyName',
            Type='AWS::EC2::KeyPair::KeyName',
        )),
        image_id=template.add_parameter(Parameter(
            'ImageId',
            Type='AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>',
            Default=(
                '/aws/service/ecs/optimized-ami'
                '/amazon-linux/recommended/image_id'
            ),
            Description=(
              'An SSM parameter that resolves to a valid AMI ID.'
              ' This is the AMI that will be used to create ECS hosts.'
              ' The default is the current recommended ECS-optimized AMI.'
            )
        )),

        # Other Parameters

        github_token=template.add_parameter(Parameter(
            'GitHubToken',
            Type='String',
            NoEcho=True,
        )),
    )

    # Environment Variable Parameters

    for env_var_param, env_var_name in sierrafile.extra_params:
        template.add_parameter(Parameter(
            env_var_param,
            Type='String',
            NoEcho=True,
        ))

    # Resource Declarations

    # # Network

    network_vpc = template.add_resource(VPC(
        'NetworkVpc',
        CidrBlock=Ref(parameters.vpc_cidr),
        Tags=Tags(Name=Ref('AWS::StackName')),
    ))

    network_ig = template.add_resource(InternetGateway(
        'NetworkInternetGateway',
        Tags=Tags(Name=Ref('AWS::StackName')),
    ))

    vpc_attach = template.add_resource(VPCGatewayAttachment(
        'NetworkInternetGatewayAttachment',
        InternetGatewayId=Ref(network_ig),
        VpcId=Ref(network_vpc),
    ))

    route_table = template.add_resource(RouteTable(
        'NetworkRouteTable',
        VpcId=Ref(network_vpc),
        Tags=Tags(Name=Ref('AWS::StackName')),
    ))

    template.add_resource(Route(
        'NetworkDefaultRoute',
        DependsOn=[vpc_attach.title],
        RouteTableId=Ref(route_table),
        DestinationCidrBlock='0.0.0.0/0',
        GatewayId=Ref(network_ig),
    ))

    subnet1 = template.add_resource(Subnet(
        'NetworkSubnet1',
        VpcId=Ref(network_vpc),
        AvailabilityZone=Select(0, GetAZs()),
        MapPublicIpOnLaunch=True,
        CidrBlock=Ref(parameters.subnet1_cidr),
        Tags=Tags(Name=Sub('${AWS::StackName} (Public)')),
    ))

    subnet2 = template.add_resource(Subnet(
        'NetworkSubnet2',
        VpcId=Ref(network_vpc),
        AvailabilityZone=Select(1, GetAZs()),
        MapPublicIpOnLaunch=True,
        CidrBlock=Ref(parameters.subnet2_cidr),
        Tags=Tags(Name=Sub('${AWS::StackName} (Public)')),
    ))

    template.add_resource(SubnetRouteTableAssociation(
        'NetworkSubnet1RouteTableAssociation',
        RouteTableId=Ref(route_table),
        SubnetId=Ref(subnet1),
    ))

    template.add_resource(SubnetRouteTableAssociation(
        'NetworkSubnet2RouteTableAssociation',
        RouteTableId=Ref(route_table),
        SubnetId=Ref(subnet2),
    ))

    elb = template.add_resource(LoadBalancer(
        ELB_NAME,
        Name=Sub('${AWS::StackName}-elb'),
        Type='network',
        Subnets=[Ref(subnet1), Ref(subnet2)],
    ))

    # # Cluster

    ecs_host_role = template.add_resource(Role(
        'EcsHostRole',
        AssumeRolePolicyDocument=PolicyDocument(
            Statement=[Statement(
                Effect=Allow,
                Principal=Principal('Service', 'ec2.amazonaws.com'),
                Action=[awacs.sts.AssumeRole]
            )],
        ),
        ManagedPolicyArns=[
            'arn:aws:iam::aws:policy/'
            'service-role/AmazonEC2ContainerServiceforEC2Role'
        ]
    ))

    ecs_host_profile = template.add_resource(InstanceProfile(
        'EcsHostInstanceProfile',
        Roles=[Ref(ecs_host_role)]
    ))

    ecs_host_sg = template.add_resource(SecurityGroup(
        'EcsHostSecurityGroup',
        GroupDescription=Sub('${AWS::StackName}-hosts'),
        VpcId=Ref(network_vpc),
        SecurityGroupIngress=[SecurityGroupRule(
            CidrIp='0.0.0.0/0',
            IpProtocol='-1'
        )]
    ))

    cluster = template.add_resource(Cluster(
        'EcsCluster',
        ClusterName=Ref('AWS::StackName')
    ))

    autoscaling_name = 'EcsHostAutoScalingGroup'
    launch_conf_name = 'EcsHostLaunchConfiguration'

    launch_conf = template.add_resource(LaunchConfiguration(
        launch_conf_name,
        ImageId=Ref(parameters.image_id),
        InstanceType=Ref(parameters.instance_type),
        IamInstanceProfile=Ref(ecs_host_profile),
        KeyName=Ref(parameters.key_name),
        SecurityGroups=[Ref(ecs_host_sg)],
        UserData=Base64(Sub(
            '#!/bin/bash\n'
            'yum install -y aws-cfn-bootstrap\n'
            '/opt/aws/bin/cfn-init -v'
            ' --region ${AWS::Region}'
            ' --stack ${AWS::StackName}'
            f' --resource {launch_conf_name}\n'
            '/opt/aws/bin/cfn-signal -e $?'
            ' --region ${AWS::Region}'
            ' --stack ${AWS::StackName}'
            f' --resource {autoscaling_name}\n'
        )),
        Metadata={
            'AWS::CloudFormation::Init': {
                'config': {
                    'commands': {
                        '01_add_instance_to_cluster': {
                            'command': Sub(
                                f'echo ECS_CLUSTER=${{{cluster.title}}}'
                                f' > /etc/ecs/ecs.config'
                            ),
                        }
                    },
                    'files': {
                        '/etc/cfn/cfn-hup.conf': {
                            'mode': 0o400,
                            'owner': 'root',
                            'group': 'root',
                            'content': Sub(
                                '[main]\n'
                                'stack=${AWS::StackId}\n'
                                'region=${AWS::Region}\n'
                            ),
                        },
                        '/etc/cfn/hooks.d/cfn-auto-reloader.conf': {
                            'content': Sub(
                                '[cfn-auto-reloader-hook]\n'
                                'triggers=post.update\n'
                                'path=Resources.ContainerInstances.Metadata'
                                '.AWS::CloudFormation::Init\n'
                                'action=/opt/aws/bin/cfn-init -v'
                                ' --region ${AWS::Region}'
                                ' --stack ${AWS::StackName}'
                                f' --resource {launch_conf_name}\n'
                            ),
                        },
                    },
                    'services': {
                        'sysvinit': {
                            'cfn-hup': {
                                'enabled': True,
                                'ensureRunning': True,
                                'files': [
                                    '/etc/cfn/cfn-hup.conf',
                                    '/etc/cfn/hooks.d/cfn-auto-reloader.conf'
                                ]
                            }
                        }
                    }
                }
            }
        }
    ))

    autoscaling_group = template.add_resource(AutoScalingGroup(
        autoscaling_name,
        VPCZoneIdentifier=[Ref(subnet1), Ref(subnet2)],
        LaunchConfigurationName=Ref(launch_conf),
        DesiredCapacity=Ref(parameters.cluster_size),
        MinSize=Ref(parameters.cluster_size),
        MaxSize=Ref(parameters.cluster_size),
        Tags=[{
            'Key': 'Name',
            'Value': Sub('${AWS::StackName} - ECS Host'),
            'PropagateAtLaunch': True,
        }],
        CreationPolicy=CreationPolicy(
            ResourceSignal=ResourceSignal(Timeout='PT15M'),
        ),
        UpdatePolicy=UpdatePolicy(
            AutoScalingRollingUpdate=AutoScalingRollingUpdate(
                MinInstancesInService=1,
                MaxBatchSize=1,
                PauseTime='PT5M',
                WaitOnResourceSignals=True,
            ),
        ),
    ))

    # # Services

    task_role = template.add_resource(Role(
        'TaskExecutionRole',
        AssumeRolePolicyDocument=PolicyDocument(
            Statement=[Statement(
                Effect=Allow,
                Principal=Principal('Service', 'ecs-tasks.amazonaws.com'),
                Action=[awacs.sts.AssumeRole],
            )],
        ),
        ManagedPolicyArns=[
            'arn:aws:iam::aws:policy/'
            'service-role/AmazonECSTaskExecutionRolePolicy'
        ],
    ))

    artifact_bucket = template.add_resource(Bucket(
        'ArtifactBucket',
        DeletionPolicy='Retain',
    ))

    codebuild_role = template.add_resource(Role(
        'CodeBuildServiceRole',
        Path='/',
        AssumeRolePolicyDocument=PolicyDocument(
            Version='2012-10-17',
            Statement=[
                Statement(
                    Effect=Allow,
                    Principal=Principal(
                        'Service', 'codebuild.amazonaws.com'
                    ),
                    Action=[
                        awacs.sts.AssumeRole,
                    ],
                ),
            ],
        ),
        Policies=[Policy(
            PolicyName='root',
            PolicyDocument=PolicyDocument(
                Version='2012-10-17',
                Statement=[
                    Statement(
                        Resource=['*'],
                        Effect=Allow,
                        Action=[
                            awacs.ssm.GetParameters,
                        ],
                    ),
                    Statement(
                        Resource=['*'],
                        Effect=Allow,
                        Action=[
                            awacs.s3.GetObject,
                            awacs.s3.PutObject,
                            awacs.s3.GetObjectVersion,
                        ],
                    ),
                    Statement(
                        Resource=['*'],
                        Effect=Allow,
                        Action=[
                            awacs.logs.CreateLogGroup,
                            awacs.logs.CreateLogStream,
                            awacs.logs.PutLogEvents,
                        ],
                    ),
                ],
            ),
        )],
    ))

    codepipeline_role = template.add_resource(Role(
        'CodePipelineServiceRole',
        Path='/',
        AssumeRolePolicyDocument=PolicyDocument(
            Version='2012-10-17',
            Statement=[
                Statement(
                    Effect=Allow,
                    Principal=Principal(
                        'Service', 'codepipeline.amazonaws.com'
                    ),
                    Action=[
                        awacs.sts.AssumeRole,
                    ],
                ),
            ],
        ),
        Policies=[Policy(
            PolicyName='root',
            PolicyDocument=PolicyDocument(
                Version='2012-10-17',
                Statement=[
                    Statement(
                        Resource=[
                            Sub(f'${{{artifact_bucket.title}.Arn}}/*')
                        ],
                        Effect=Allow,
                        Action=[
                            awacs.s3.GetBucketVersioning,
                            awacs.s3.GetObject,
                            awacs.s3.GetObjectVersion,
                            awacs.s3.PutObject,
                        ],
                    ),
                    Statement(
                        Resource=['*'],
                        Effect=Allow,
                        Action=[
                            awacs.ecs.DescribeServices,
                            awacs.ecs.DescribeTaskDefinition,
                            awacs.ecs.DescribeTasks,
                            awacs.ecs.ListTasks,
                            awacs.ecs.RegisterTaskDefinition,
                            awacs.ecs.UpdateService,
                            awacs.codebuild.StartBuild,
                            awacs.codebuild.BatchGetBuilds,
                            awacs.iam.PassRole,
                        ],
                    ),
                ],
            ),
        )],
    ))

    log_group = template.add_resource(LogGroup(
        'LogGroup',
        LogGroupName=Sub('/ecs/${AWS::StackName}'),
    ))

    if any(conf.pipeline.enable for conf in sierrafile.services.values()):
        project = template.add_resource(Project(
            'CodeBuildProject',
            Name=Sub('${AWS::StackName}-build'),
            ServiceRole=Ref(codebuild_role),
            Artifacts=Artifacts(Type='CODEPIPELINE'),
            Source=Source(Type='CODEPIPELINE'),
            Environment=Environment(
                ComputeType='BUILD_GENERAL1_SMALL',
                Image='aws/codebuild/docker:17.09.0',
                Type='LINUX_CONTAINER',
            ),
        ))

    for name, settings in sierrafile.services.items():
        task_definition = template.add_resource(TaskDefinition(
            f'{name}TaskDefinition',
            RequiresCompatibilities=['EC2'],
            Cpu=str(settings.container.cpu),
            Memory=str(settings.container.memory),
            NetworkMode='bridge',
            ExecutionRoleArn=Ref(task_role.title),
            ContainerDefinitions=[
                ContainerDefinition(
                    Name=f'{name}',
                    Image=settings.container.image,
                    Memory=str(settings.container.memory),
                    Essential=True,
                    PortMappings=[
                        PortMapping(
                            ContainerPort=settings.container.port,
                            Protocol='tcp',
                        ),
                    ],
                    Environment=[
                        troposphere.ecs.Environment(Name=k, Value=v)
                        for k, v in sierrafile.env_vars.items()
                        if k in settings.get('environment', [])
                    ],
                    LogConfiguration=LogConfiguration(
                        LogDriver='awslogs',
                        Options={
                            'awslogs-region': Ref('AWS::Region'),
                            'awslogs-group': Ref(log_group.title),
                            'awslogs-stream-prefix': Ref('AWS::StackName'),
                        },
                    ),
                ),
            ],
        ))

        target_group = template.add_resource(TargetGroup(
            f'{name}TargetGroup',
            Port=settings.container.port,
            Protocol='TCP',
            VpcId=Ref(network_vpc),
            Tags=Tags(Name=Sub(f'${{AWS::StackName}}-{name}')),
        ))

        listener = template.add_resource(Listener(
            f'{name}ElbListener',
            LoadBalancerArn=Ref(elb),
            Port=settings.container.port,
            Protocol='TCP',
            DefaultActions=[
                Action(TargetGroupArn=Ref(target_group), Type='forward')
            ],
        ))

        service = template.add_resource(Service(
            f'{name}Service',
            Cluster=Ref(cluster),
            ServiceName=f'{name}-service',
            DependsOn=[autoscaling_group.title, listener.title],
            DesiredCount=settings.container.count,
            TaskDefinition=Ref(task_definition),
            LaunchType='EC2',
            LoadBalancers=[
                troposphere.ecs.LoadBalancer(
                    ContainerName=f'{name}',
                    ContainerPort=settings.container.port,
                    TargetGroupArn=Ref(target_group),
                ),
            ],
        ))

        if settings.pipeline.enable:
            pipeline = template.add_resource(Pipeline(
                f'{name}Pipeline',
                RoleArn=GetAtt(codepipeline_role, 'Arn'),
                ArtifactStore=ArtifactStore(
                    Type='S3',
                    Location=Ref(artifact_bucket),
                ),
                Stages=[
                    Stages(
                        Name='Source',
                        Actions=[Actions(
                            Name='Source',
                            ActionTypeId=ActionTypeId(
                                Category='Source',
                                Owner='ThirdParty',
                                Version='1',
                                Provider='GitHub',
                            ),
                            OutputArtifacts=[
                                OutputArtifacts(Name=f'{name}Source'),
                            ],
                            RunOrder='1',
                            Configuration={
                                'Owner': settings.pipeline.user,
                                'Repo': settings.pipeline.repo,
                                'Branch': settings.pipeline.branch,
                                'OAuthToken': Ref(parameters.github_token),
                            },
                        )],
                    ),
                    Stages(
                        Name='Build',
                        Actions=[Actions(
                            Name='Build',
                            ActionTypeId=ActionTypeId(
                                Category='Build',
                                Owner='AWS',
                                Version='1',
                                Provider='CodeBuild',
                            ),
                            InputArtifacts=[
                                InputArtifacts(Name=f'{name}Source'),
                            ],
                            OutputArtifacts=[
                                OutputArtifacts(Name=f'{name}Build'),
                            ],
                            RunOrder='1',
                            Configuration={
                                'ProjectName': Ref(project),
                            },
                        )],
                    ),
                    Stages(
                        Name='Deploy',
                        Actions=[Actions(
                            Name='Deploy',
                            ActionTypeId=ActionTypeId(
                                Category='Deploy',
                                Owner='AWS',
                                Version='1',
                                Provider='ECS',
                            ),
                            InputArtifacts=[
                                InputArtifacts(Name=f'{name}Build')
                            ],
                            RunOrder='1',
                            Configuration={
                                'ClusterName': Ref(cluster),
                                'ServiceName': Ref(service),
                                'FileName': 'image.json',
                            },
                        )],
                    ),
                ],
            ))

            template.add_resource(Webhook(
                f'{name}CodePipelineWebhook',
                Name=Sub(f'${{AWS::StackName}}-{name}-webhook'),
                Authentication='GITHUB_HMAC',
                AuthenticationConfiguration=AuthenticationConfiguration(
                    SecretToken=Ref(parameters.github_token),
                ),
                Filters=[FilterRule(
                    JsonPath='$.ref',
                    MatchEquals=f'refs/heads/{settings.pipeline.branch}'
                )],
                TargetAction='Source',
                TargetPipeline=Ref(pipeline),
                TargetPipelineVersion=1,
                RegisterWithThirdParty=True,
            ))

    return template
Example #18
0
 def test_redirect_action_requires_redirect_config(self):
     with self.assertRaises(ValueError):
         Action(Type="redirect").to_dict()
Example #19
0
 def test_target_arn_only_forward(self):
     with self.assertRaises(ValueError):
         Action(Type="redirect", TargetGroupArn="").to_dict()
Example #20
0
 def test_forward_action_requires_target_arn(self):
     with self.assertRaises(ValueError):
         Action(Type="forward").to_dict()
 def test_forward_action(self):
     Action(
         Type='forward',
         TargetGroupArn=''
     ).to_dict()
Example #22
0
def create_alb_template():
    template = Template()

    vpc = template.add_parameter(
        parameter=Parameter(title='Vpc', Type='String'))
    subnet_a = template.add_parameter(
        parameter=Parameter(title='SubnetA', Type='String'))
    subnet_b = template.add_parameter(
        parameter=Parameter(title='SubnetB', Type='String'))
    ec2_instance = template.add_parameter(
        parameter=Parameter(title='Ec2Instance', Type='String'))
    certificate = template.add_parameter(
        parameter=Parameter(title='Certificate', Type='String'))

    security_group = template.add_resource(
        resource=SecurityGroup(title='SampleSecurityGroup',
                               GroupDescription='sample-security-group',
                               SecurityGroupIngress=[{
                                   'IpProtocol': 'tcp',
                                   'FromPort': 80,
                                   'ToPort': 80,
                                   'CidrIp': '0.0.0.0/0'
                               }, {
                                   'IpProtocol': 'tcp',
                                   'FromPort': 443,
                                   'ToPort': 443,
                                   'CidrIp': '0.0.0.0/0'
                               }],
                               VpcId=Ref(vpc)))

    load_balancer = template.add_resource(resource=LoadBalancer(
        title='SampleLoadBalancer',
        Name='sample-alb-https',
        Subnets=[Ref(subnet_a), Ref(subnet_b)],
        SecurityGroups=[Ref(security_group)],
    ))

    target_group = template.add_resource(resource=TargetGroup(
        title='SampleTargetGroup',
        Targets=[TargetDescription(
            Id=Ref(ec2_instance),
            Port=80,
        )],
        VpcId=Ref(vpc),
        Name='sample-target-group-https',
        Port=443,
        Protocol='HTTP',
    ))

    template.add_resource(resource=Listener(
        title='SampleListenerHttps',
        Certificates=[Certificate(CertificateArn=Ref(certificate))],
        DefaultActions=[
            Action(TargetGroupArn=Ref(target_group), Type='forward')
        ],
        LoadBalancerArn=Ref(load_balancer),
        Port=443,
        Protocol='HTTPS',
    ))

    template.add_resource(resource=Listener(
        title='SampleListenerHttp',
        DefaultActions=[
            Action(
                RedirectConfig=RedirectConfig(
                    Host='#{host}',
                    Path='/#{path}',
                    Port='443',
                    Protocol='HTTPS',
                    Query='#{query}',
                    StatusCode='HTTP_301',
                ),
                Type='redirect',
            )
        ],
        LoadBalancerArn=Ref(load_balancer),
        Port=80,
        Protocol='HTTP',
    ))

    with open('./alb.yml', mode='w') as file:
        file.write(template.to_yaml())
Example #23
0
 def test_forward_action(self):
     Action(Type="forward", TargetGroupArn="").to_dict()
Example #24
0
        Matcher=Matcher(HttpCode='200'),
        Port=8080,
        Protocol='HTTP',
        TargetGroupAttributes=[
            TargetGroupAttribute(Key='deregistration_delay.timeout_seconds',
                                 Value='120')
        ],
        VpcId=Ref(vpc_id)))

listener = template.add_resource(
    Listener('HttpListener',
             Port=80,
             Protocol='HTTP',
             LoadBalancerArn=Ref(load_balancer),
             DefaultActions=[
                 Action(Type="forward", TargetGroupArn=Ref(target_group))
             ]))

template.add_resource(
    ListenerRule(
        'ListenerRule',
        ListenerArn=Ref(listener),
        Conditions=[Condition(Field='path-pattern', Values=['*'])],
        Actions=[Action(Type='forward', TargetGroupArn=Ref(target_group))],
        Priority=1000))

target_group_dimension = GetAtt(target_group, 'TargetGroupFullName')
load_balancer_dimension = GetAtt(load_balancer, 'LoadBalancerFullName')
template.add_resource(
    Alarm(
        'LowHealthyHostsAlarm',
    def create_wordpress_environment(self):

        template = Template()
        template.add_version('2010-09-09')
        
        # Wordpress preparation: format vpc name and split private and public subnets in two lists
       
        vpc_name_formatted = ''.join(
            e for e in self.private_vpc_name if e.isalnum()).capitalize()

        filter_private_subnets = filter(lambda x : x["type"] == "private", self.private_vpc_subnets)
        filter_public_subnets = filter(lambda x : x["type"] == "public", self.private_vpc_subnets)

        private_subnets = []
        for subnet in filter_private_subnets:
            subnet_name_formatted = ''.join(e for e in subnet["name"] if e.isalnum()).capitalize()

            private_subnets.append(ImportValue("{}{}{}SubnetId".format(self.stage, vpc_name_formatted, subnet_name_formatted)))

        public_subnets = []
        for subnet in filter_public_subnets:
            subnet_name_formatted = ''.join(e for e in subnet["name"] if e.isalnum()).capitalize()

            public_subnets.append(ImportValue("{}{}{}SubnetId".format(self.stage, vpc_name_formatted, subnet_name_formatted)))

        # Instances Security Groups

        web_dmz_security_group = template.add_resource(
            SecurityGroup(
                "{}WebDMZSecurityGroup".format(self.stage),
                GroupName="{}webdmz-sg".format(self.stage),
                VpcId=ImportValue("{}{}VpcId".format(self.stage,vpc_name_formatted)),
                GroupDescription="Enables external http access to EC2 instance(s) that host the webpages",
                SecurityGroupIngress=[
                    SecurityGroupRule(
                        IpProtocol="tcp",
                        FromPort="80",
                        ToPort="80",
                        CidrIp="0.0.0.0/0",
                    ),
                    SecurityGroupRule(
                        IpProtocol="tcp",
                        FromPort="22",
                        ToPort="22",
                        SourceSecurityGroupId=ImportValue("{}BastionHostSecurityGroupID".format(self.stage))
                    )
                ]
            )
        )

        rds_private_security_group = template.add_resource(
            SecurityGroup(
                "{}RdsPrivateSecurityGroup".format(self.stage),
                GroupName="{}rds-private-sg".format(self.stage),
                VpcId=ImportValue("{}{}VpcId".format(self.stage,vpc_name_formatted)),
                GroupDescription="Allow access to the mysql port from the webservers",
                SecurityGroupIngress=[
                    SecurityGroupRule(
                        IpProtocol="tcp",
                        FromPort=self.database_port,
                        ToPort=self.database_port,
                        SourceSecurityGroupId=Ref(web_dmz_security_group)
                    )
                ]
            )
        )

        # S3 Buckets for wordpress content

        bucket_wordpress_code = template.add_resource(
            Bucket(
                "{}BucketWordpressCode".format(self.stage),
                BucketName="{}-wordpress-code".format(self.stage),
                AccessControl=Private
            )
        )

        bucket_wordpress_media_assets = template.add_resource(
            Bucket(
                "{}BucketWordpressMediaAssets".format(self.stage),
                BucketName="{}-wordpress-media-assets".format(self.stage),
                AccessControl=Private
            )
        )

        # Database Instance to store wordpress data

        rds_subnet_group = template.add_resource(
            DBSubnetGroup(
                "{}PrivateRDSSubnetGroup".format(self.stage),
                DBSubnetGroupName="{}private-rds-subnet-group".format(self.stage),
                DBSubnetGroupDescription="Subnets available for the RDS DB Instance",
                SubnetIds=private_subnets
            )
        )

        template.add_resource(
            DBInstance(
                "{}RdsInstance".format(self.stage),
                DBInstanceIdentifier="{}RdsInstance".format(self.stage),
                DBName=self.database_name,
                AllocatedStorage="20",
                DBInstanceClass=self.database_instance_class,
                Engine=self.database_engine,
                EngineVersion=self.database_engine_version,
                MasterUsername=self.database_username,
                MasterUserPassword=self.database_password,
                Port=self.database_port,
                BackupRetentionPeriod=0,
                MultiAZ=self.database_multiaz,
                DBSubnetGroupName=Ref(rds_subnet_group),
                VPCSecurityGroups=[Ref(rds_private_security_group)],
                Tags=Tags(
                    Name=self.database_name_tag
                )
            )
        )

        # Cloudfront Distribution to load images

        cloudfront_origin_access_identity = template.add_resource(
            CloudFrontOriginAccessIdentity(
                "{}CloudfrontOriginAccessIdentity".format(self.stage),
                CloudFrontOriginAccessIdentityConfig=CloudFrontOriginAccessIdentityConfig(
                    "{}CloudFrontOriginAccessIdentityConfig".format(self.stage),
                    Comment="WordPress Origin Access Identity"
                )
            )
        )

        template.add_resource(BucketPolicy(
            "{}BucketWordpressMediaAssetsPolicy".format(self.stage),
            Bucket=Ref(bucket_wordpress_media_assets),
            PolicyDocument={
                "Version": "2008-10-17",
                "Id": "PolicyForCloudFrontPrivateContent",
                "Statement": [
                    {
                        "Sid": "1",
                        "Effect": "Allow",
                        "Principal": {
                            "CanonicalUser": GetAtt(cloudfront_origin_access_identity, 'S3CanonicalUserId')
                        },
                        "Action": "s3:GetObject",
                        "Resource": "arn:aws:s3:::{}-wordpress-media-assets/*".format(self.stage)
                    }
                ]
            }
        ))

        cloudfront_distribution = template.add_resource(
            Distribution(
                "{}CloudfrontDistribution".format(self.stage),
                DistributionConfig=DistributionConfig(
                    Origins=[
                        Origin(
                            Id="MediaAssetsOrigin",
                            DomainName=GetAtt(bucket_wordpress_media_assets, 'DomainName'),
                            S3OriginConfig=S3Origin(
                                OriginAccessIdentity=Join("", [
                                    "origin-access-identity/cloudfront/",
                                    Ref(cloudfront_origin_access_identity)
                                ])
                            )
                        )
                    ],
                    DefaultCacheBehavior=DefaultCacheBehavior(
                        TargetOriginId="MediaAssetsOrigin",
                        ForwardedValues=ForwardedValues(
                            QueryString=False
                        ),
                        ViewerProtocolPolicy="allow-all"
                    ),
                    Enabled=True,
                    HttpVersion='http2'
                )
            )
        )

        # Wordpress EC2 Instances
        
        ''' 
            EC2 Instances types:
                Write node = To make changes to your blog. E.g: add new posts
                Read Nodes = Instances open to the internet for blog reading
        '''

        wordpress_ec2_role = template.add_resource(
            Role(
                "{}WordPressEC2InstanceRole".format(self.stage),
                RoleName="{}WordPressEC2InstanceRole".format(self.stage),
                Path="/",
                AssumeRolePolicyDocument={"Statement": [{
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["ec2.amazonaws.com"]
                    },
                    "Action": ["sts:AssumeRole"]
                }]},
                Policies=[
                    Policy(
                        PolicyName="S3FullAccess",
                        PolicyDocument={
                            "Statement": [{
                                "Effect": "Allow",
                                "Action": "s3:*",
                                "Resource": "*"
                            }],
                        }
                    )
                ]
            )
        )

        spotfleetrole = template.add_resource(
            Role(
                "{}spotfleetrole".format(self.stage),
                AssumeRolePolicyDocument={
                    "Statement": [
                        {
                            "Action": "sts:AssumeRole",
                            "Principal": {
                                "Service": "spotfleet.amazonaws.com"
                            },
                            "Effect": "Allow",
                            "Sid": ""
                        }
                    ],
                    "Version": "2012-10-17"
                },
                ManagedPolicyArns=[
                    "arn:aws:iam::aws:policy/service-role/AmazonEC2SpotFleetRole"
                ]
            )
        )

        ec2_instance_profile = template.add_resource(
            InstanceProfile(
                "{}WriteWordpressEc2InstanceProfile".format(self.stage),
                Roles=[Ref(wordpress_ec2_role)]
            )
        )

        template.add_resource(
            SpotFleet(
                "{}WriteWordpressEc2Instance".format(self.stage),
                SpotFleetRequestConfigData=SpotFleetRequestConfigData(
                    AllocationStrategy="lowestPrice",
                    IamFleetRole=GetAtt(spotfleetrole,"Arn"),
                    LaunchSpecifications=[LaunchSpecifications(
                        IamInstanceProfile=IamInstanceProfile(
                            Arn=GetAtt(ec2_instance_profile, "Arn")
                        ),
                        ImageId=self.write_instance_image_id,
                        InstanceType=self.write_instance_type,
                        KeyName=self.write_instance_key_name,
                        SecurityGroups=[SecurityGroups(GroupId=Ref(web_dmz_security_group))],
                        SubnetId=next(iter(public_subnets)),
                        UserData=Base64(
                            Join("", [
                                """ #!/bin/bash
                                yum install httpd php php-mysql -y
                                cd /var/www/html
                                echo \"healthy\" > healthy.html
                                wget https://wordpress.org/latest.tar.gz
                                tar -xzf latest.tar.gz
                                cp -r wordpress/* /var/www/html/
                                rm -rf wordpress
                                rm -rf latest.tar.gz
                                chmod -R 755 wp-content
                                chown -R apache:apache wp-content
                                echo -e 'Options +FollowSymlinks \nRewriteEngine on \nrewriterule ^wp-content/uploads/(.*)$ http://""",
                                GetAtt(cloudfront_distribution, 'DomainName'),
                                """/$1 [r=301,nc]' > .htaccess
                                chkconfig httpd on
                                cd /var/www
                                sudo chown -R apache /var/www/html
                                cd html/
                                sudo find . -type d -exec chmod 0755 {} \;
                                sudo find . -type f -exec chmod 0644 {} \;
                                sed -i 's/AllowOverride None/AllowOverride All/g' /etc/httpd/conf/httpd.conf
                                sed -i 's/AllowOverride none/AllowOverride All/g' /etc/httpd/conf/httpd.conf
                                echo -e "*/1 * * * * root aws s3 sync --delete /var/www/html s3://""",
                                Ref(bucket_wordpress_code),
                                """">> /etc/crontab 
                                echo -e "*/1 * * * * root aws s3 sync --delete /var/www/html/wp-content/uploads s3://""",
                                Ref(bucket_wordpress_media_assets),
                                """">> /etc/crontab
                                service httpd start
                                """
                            ])
                        )
                    )],
                    TargetCapacity=1,
                    Type="request"
                )
            )
        )

        template.add_resource(
            LaunchConfiguration(
                "{}WordPressReadLaunchConfiguration".format(self.stage),
                InstanceType=self.read_instance_type,
                ImageId=self.read_instance_image_id,
                KeyName=self.read_instance_key_name,
                LaunchConfigurationName="{}-wordpress-launch-config".format(self.stage),
                SecurityGroups=[Ref(web_dmz_security_group)],
                IamInstanceProfile=Ref(ec2_instance_profile),
                SpotPrice="0.5",
                UserData=Base64(
                    Join("", [
                        """ #!/bin/bash
                        yum install httpd php php-mysql -y
                        cd /var/www/html
                        echo \"healthy\" > healthy.html
                        wget https://wordpress.org/latest.tar.gz
                        tar -xzf latest.tar.gz
                        cp -r wordpress/* /var/www/html/
                        rm -rf wordpress
                        rm -rf latest.tar.gz
                        chmod -R 755 wp-content
                        chown -R apache:apache wp-content
                        echo -e 'Options +FollowSymlinks \nRewriteEngine on \nrewriterule ^wp-content/uploads/(.*)$ http://""",
                        GetAtt(cloudfront_distribution, 'DomainName'),
                        """/$1 [r=301,nc]' > .htaccess
                        chkconfig httpd on
                        cd /var/www
                        sudo chown -R apache /var/www/html
                        cd html/
                        sudo find . -type d -exec chmod 0755 {} \;
                        sudo find . -type f -exec chmod 0644 {} \;
                        sed -i 's/AllowOverride None/AllowOverride All/g' /etc/httpd/conf/httpd.conf
                        sed -i 's/AllowOverride none/AllowOverride All/g' /etc/httpd/conf/httpd.conf
                        echo -e "*/1 * * * * root aws s3 sync --delete s3://""",
                        Ref(bucket_wordpress_code),
                        """ /var/www/html">> /etc/crontab 
                        echo -e "*/1 * * * * root aws s3 sync --delete s3://""",
                        Ref(bucket_wordpress_media_assets),
                        """/var/www/html/wp-content/uploads">> /etc/crontab
                        service httpd start
                        """
                    ])
                )
            )
        )

        alb = template.add_resource(
            LoadBalancer(
                "{}ApplicationLoadBalancer".format(self.stage),
                Name="{}-wordpress-alb".format(self.stage),
                SecurityGroups=[Ref(web_dmz_security_group)],
                Subnets=public_subnets,
                Type="application"
            )
        )

        target_group = template.add_resource(
            TargetGroup(
                "{}TargetGroup".format(self.stage),
                Name="{}-wordpress-target-group".format(self.stage),
                Port=80,
                Protocol="HTTP",
                VpcId=ImportValue("{}{}VpcId".format(self.stage,vpc_name_formatted)),
                HealthCheckPort=8080
            )
        )

        template.add_resource(
            AutoScalingGroup(
                "{}AutoScalingGroup".format(self.stage),
                DependsOn="{}WordPressReadLaunchConfiguration".format(self.stage),
                AutoScalingGroupName="{}-wordpress-auto-scaling".format(self.stage),
                LaunchConfigurationName="{}-wordpress-launch-config".format(self.stage),
                TargetGroupARNs=[Ref(target_group)],
                MaxSize="3",
                MinSize="1",
                VPCZoneIdentifier=public_subnets,
                Tags=[
                    Tag("Name", "{}-wordpress-read-node".format(self.stage), True)
                ]
            )
        )

        template.add_resource(
            Listener(
                "ALBListener",
                DefaultActions=[
                    Action(
                        TargetGroupArn=Ref(target_group), 
                        Type="forward"
                    )
                ],
                LoadBalancerArn=Ref(alb),
                Port=80,
                Protocol="HTTP"
            )
        )

        f = open("modules/template_wordpress.yaml", 'w')
        print(template.to_yaml(), file=f)
Example #26
0
    ],
    SecurityGroups=[Ref(alb_security_group)],
    DependsOn=Ref(logs_bucket_policy))
template.add_resource(load_balancer)
target_group = TargetGroup("exampletargetgroup",
                           VpcId=vpc_id,
                           HealthCheckPath='/',
                           Port='80',
                           Protocol='HTTP')
listener = Listener(
    "examplelistener",
    LoadBalancerArn=Ref(load_balancer),
    Port='443',
    Protocol='HTTPS',
    Certificates=[Certificate(CertificateArn=certificate_arn)],
    DefaultActions=[Action(Type='forward', TargetGroupArn=Ref(target_group))],
    SslPolicy="ELBSecurityPolicy-TLS-1-2-Ext-2018-06")
template.add_resource(target_group)
template.add_resource(listener)

# Setup the ASG & launch config
launch_config = LaunchConfiguration(
    "LaunchConfig",
    ImageId=image_id,
    IamInstanceProfile=Ref(example_instance_profile),
    InstanceType=instance_type,
    Metadata=Metadata(
        Init({
            'config':
            InitConfig(
                commands={
    def _add_alb(self, cd, service_name, config, launch_type):
        sg_name = 'SG' + self.env + service_name
        svc_alb_sg = SecurityGroup(
            re.sub(r'\W+', '', sg_name),
            GroupName=self.env + '-' + service_name,
            SecurityGroupIngress=self._generate_alb_security_group_ingress(
                config
            ),
            VpcId=Ref(self.vpc),
            GroupDescription=Sub(service_name + "-alb-sg")
        )
        self.template.add_resource(svc_alb_sg)
        alb_name = service_name + pascalcase(self.env)
        if config['http_interface']['internal']:
            alb_subnets = [
                Ref(self.private_subnet1),
                Ref(self.private_subnet2)
            ]
            scheme = "internal"
            alb_name += 'Internal'
            alb_name = alb_name[:32]
            alb = ALBLoadBalancer(
                'ALB' + service_name,
                Subnets=alb_subnets,
                SecurityGroups=[
                    self.alb_security_group,
                    Ref(svc_alb_sg)
                ],
                Name=alb_name,
                Tags=[
                    {'Value': alb_name, 'Key': 'Name'}
                ],
                Scheme=scheme
            )
        else:
            alb_subnets = [
                Ref(self.public_subnet1),
                Ref(self.public_subnet2)
            ]
            alb_name = alb_name[:32]
            alb = ALBLoadBalancer(
                'ALB' + service_name,
                Subnets=alb_subnets,
                SecurityGroups=[
                    self.alb_security_group,
                    Ref(svc_alb_sg)
                ],
                Name=alb_name,
                Tags=[
                    {'Value': alb_name, 'Key': 'Name'}
                ]
            )

        self.template.add_resource(alb)

        target_group_name = "TargetGroup" + service_name
        health_check_path = config['http_interface']['health_check_path'] if 'health_check_path' in config['http_interface'] else "/elb-check"
        if config['http_interface']['internal']:
            target_group_name = target_group_name + 'Internal'

        target_group_config = {}
        if launch_type == self.LAUNCH_TYPE_FARGATE:
            target_group_config['TargetType'] = 'ip'

        service_target_group = TargetGroup(
            target_group_name,
            HealthCheckPath=health_check_path,
            HealthyThresholdCount=2,
            HealthCheckIntervalSeconds=30,
            TargetGroupAttributes=[
                TargetGroupAttribute(
                    Key='deregistration_delay.timeout_seconds',
                    Value='30'
                )
            ],
            VpcId=Ref(self.vpc),
            Protocol="HTTP",
            Matcher=Matcher(HttpCode="200-399"),
            Port=int(config['http_interface']['container_port']),
            HealthCheckTimeoutSeconds=10,
            UnhealthyThresholdCount=3,
            **target_group_config
        )

        self.template.add_resource(service_target_group)
        # Note: This is a ECS Loadbalancer definition. Not an ALB.
        # Defining this causes the target group to add a target to the correct
        # port in correct ECS cluster instance for the service container.
        lb = LoadBalancer(
            ContainerName=cd.Name,
            TargetGroupArn=Ref(service_target_group),
            ContainerPort=int(config['http_interface']['container_port'])
        )
        target_group_action = Action(
            TargetGroupArn=Ref(target_group_name),
            Type="forward"
        )
        service_listener = self._add_service_listener(
            service_name,
            target_group_action,
            alb,
            config['http_interface']['internal']
        )
        self._add_alb_alarms(service_name, alb)
        return alb, lb, service_listener, svc_alb_sg
Example #28
0
 def test_fixed_response_requires_fixed_response_config(self):
     with self.assertRaises(ValueError):
         Action(Type="fixed-response").to_dict()
Example #29
0
    ]
)

template.add_resource(origin_certificate),
template.add_resource(origin_issued_certificate),
template.add_resource(certificate_dns_record)
template.add_resource(alb_record_set_group)

http_listener = Listener(
    region.replace("-", "") + "ecslivehttplistener",
    DefaultActions = [
        Action(
            region.replace("-", "") + "ecslivehttpredirectaction",
            RedirectConfig = RedirectConfig(
                region.replace("-", "") + "ecslivehttpredirectconfig",
                Port = "443",
                Protocol = "HTTPS",
                StatusCode = "HTTP_301"
            ),
            Type = "redirect"
        )
    ],
    LoadBalancerArn = Ref(application_load_balancer),
    Port = 80,
    Protocol = "HTTP"
)

https_listener = Listener(
    region.replace("-", "") + "ecslivehttpslistener",
    Certificates = [
        Certificate(
            CertificateArn = Ref(origin_issued_certificate)
    def __init__(self,
                 prefix: str,
                 lb_security_groups: List[SecurityGroup],
                 subnets: List[Subnet],
                 vpc: VPC,
                 desired_domain_name: str,
                 healthy_http_codes: Optional[List[int]] = None):
        """
        Constructor.

        :param prefix: A prefix for resource names.
        :param lb_security_groups: Security groups to attach to a loadbalancer. NOTE! when passing loadbalancer
        security groups - make sure the loadbalancer can communicate through ci/cd blue/green deployments
        opened ports. Usually they are 8000 and 44300.
        :param subnets: Subnets in which loadbalancer can exist.
        :param vpc: Virtual private cloud in which target groups and a loadbalancer exist.
        :param desired_domain_name: Domain name for using https.
        :param healthy_http_codes: The deployed instance is constantly pinged to determine if it is available
        (healthy) or not. Specify a list of http codes that your service can return and should be treated as healthy.
        """
        # By default a healthy http code is considered to be 200.
        healthy_http_codes = healthy_http_codes or [200]

        # If your service's task definition uses the awsvpc network mode
        # (which is required for the Fargate launch type), you must choose ip as the target type,
        # not instance, when creating your target groups because
        # tasks that use the awsvpc network mode are associated with an elastic network interface,
        # not an Amazon EC2 instance.
        self.target_type = 'ip'

        # Certificate so a loadbalancer could communicate via HTTPS.
        self.certificate = Certificate(
            prefix + 'FargateEcsCertificate',
            DomainName=desired_domain_name,
            ValidationMethod='DNS',
        )

        # A main target group to which a loadbalancer forwards a HTTP traffic.
        # This is the main group with which our ecs container is associated.
        self.target_group_1_http = TargetGroup(
            prefix + 'FargateEcsTargetGroup1',
            Name=prefix + 'FargateEcsTargetGroup1',
            Matcher=Matcher(
                HttpCode=','.join([str(code) for code in healthy_http_codes])),
            Port=self.TARGET_GROUP_PORT,
            Protocol='HTTP',
            VpcId=Ref(vpc),
            TargetType=self.target_type)

        # Second target group is usd for Blue/Green deployments. A new container (that should be deployed)
        # is associated with the second target group.
        self.target_group_2_http = TargetGroup(
            prefix + 'FargateEcsTargetGroup2',
            Name=prefix + 'FargateEcsTargetGroup2',
            Matcher=Matcher(
                HttpCode=','.join([str(code) for code in healthy_http_codes])),
            Port=self.TARGET_GROUP_PORT,
            Protocol='HTTP',
            VpcId=Ref(vpc),
            TargetType=self.target_type)

        self.load_balancer = LoadBalancer(
            prefix + 'FargateEcsLoadBalancer',
            Subnets=[Ref(sub) for sub in subnets],
            SecurityGroups=[Ref(group) for group in lb_security_groups],
            Name=prefix + 'FargateEcsLoadBalancer',
            Scheme='internet-facing',
        )

        self.load_balancer_output = Output(
            prefix + 'FargateEcsLoadBalancerUrl',
            Description='The endpoint url of a loadbalancer.',
            Value=GetAtt(self.load_balancer, 'DNSName'))

        # Listener that listens to HTTP incoming traffic and redirects to other HTTPS listener.
        self.listener_http_1 = Listener(
            prefix + 'FargateEcsHttpListener1',
            Port=self.LISTENER_HTTP_PORT_1,
            Protocol='HTTP',
            LoadBalancerArn=Ref(self.load_balancer),
            DefaultActions=[
                # Redirect to https.
                Action(Type='redirect',
                       RedirectConfig=RedirectConfig(
                           Host='#{host}',
                           Path='/#{path}',
                           Port=str(self.LISTENER_HTTPS_PORT_1),
                           Query='#{query}',
                           StatusCode='HTTP_301',
                           Protocol='HTTPS'))
            ])

        # Listener that listens to HTTPS traffic and forwards to a target group.
        self.listener_https_1 = Listener(
            prefix + 'FargateEcsHttpsListener1',
            Certificates=[LBCertificate(CertificateArn=Ref(self.certificate))],
            Port=self.LISTENER_HTTPS_PORT_1,
            Protocol='HTTPS',
            LoadBalancerArn=Ref(self.load_balancer),
            DefaultActions=[
                Action(Type='forward',
                       TargetGroupArn=Ref(self.target_group_1_http))
            ])

        # Second listener is usd for Blue/Green deployments (testing new instance). Test HTTP traffic is
        # redirected to test HTTPS traffic.
        self.listener_http_2 = Listener(
            prefix + 'FargateEcsHttpListener2',
            Port=self.LISTENER_HTTP_PORT_2,
            Protocol='HTTP',
            LoadBalancerArn=Ref(self.load_balancer),
            DefaultActions=[
                # Redirect to https.
                Action(Type='redirect',
                       RedirectConfig=RedirectConfig(
                           Host='#{host}',
                           Path='/#{path}',
                           Port=str(self.LISTENER_HTTPS_PORT_2),
                           Query='#{query}',
                           StatusCode='HTTP_301',
                           Protocol='HTTPS'))
            ])

        # Listener that listens to test HTTP traffic and forwards to a secondary target group (new container).
        self.listener_https_2 = Listener(
            prefix + 'FargateEcsHttpsListener2',
            Certificates=[LBCertificate(CertificateArn=Ref(self.certificate))],
            Port=self.LISTENER_HTTPS_PORT_2,
            Protocol='HTTPS',
            LoadBalancerArn=Ref(self.load_balancer),
            DefaultActions=[
                Action(Type='forward',
                       TargetGroupArn=Ref(self.target_group_2_http))
            ])