Ejemplo n.º 1
0
 def alb_listener_443(self):
     """ ALB port 443 """
     app_target_group = elbv2.CfnTargetGroup(
         self,
         "AppTG",
         name='pelican-tg',
         health_check_path="/health-check.do",
         health_check_protocol='HTTP',
         port=9000,
         protocol="HTTP",
         target_type="instance",
         vpc_id='vpc-44a44b44',
         targets=[{'id': self.instance_id, 'port': 9000}]
     )
     self.listener_443 = elbv2.CfnListener(
         scope=self,
         id='Listener443',
         default_actions=[
             elbv2.CfnListener.ActionProperty(
                 target_group_arn=app_target_group.ref,
                 type="forward"
             )
         ],
         certificates=[elbv2.CfnListener.CertificateProperty(certificate_arn=self.sel_cert_arn)],
         load_balancer_arn=self.lb.ref,
         port=443,
         protocol="HTTPS"
     )
Ejemplo n.º 2
0
 def add_listener_80(self):
     elbv2.CfnListener(
         scope=self,
         id='Listener80',
         default_actions=[
             elbv2.CfnListener.ActionProperty(
                 type='redirect',
                 redirect_config=elbv2.CfnListener.RedirectConfigProperty(
                     status_code='HTTP_301',
                     host='#{host}',
                     path='/#{path}',
                     query='#{query}',
                     port='443',
                     protocol='HTTPS'
                 )
             )
         ],
         load_balancer_arn=self.lb.ref,
         port=80,
         protocol="HTTP"
     )
Ejemplo n.º 3
0
 def __init__(self, scope: core.Construct, id: str, data, iam_vars) -> None:
     super().__init__(scope, id)
     # VPC
     vpc = ec2.CfnVPC(self, "cdk-vpc", cidr_block=data["vpc"])
     igw = ec2.CfnInternetGateway(self, id="igw")
     ec2.CfnVPCGatewayAttachment(self,
                                 id="igw-attach",
                                 vpc_id=vpc.ref,
                                 internet_gateway_id=igw.ref)
     public_route_table = ec2.CfnRouteTable(self,
                                            id="public_route_table",
                                            vpc_id=vpc.ref)
     ec2.CfnRoute(self,
                  id="public_route",
                  route_table_id=public_route_table.ref,
                  destination_cidr_block="0.0.0.0/0",
                  gateway_id=igw.ref)
     public_subnets = []
     for i, s in enumerate(data["subnets"]["public"]):
         subnet = ec2.CfnSubnet(self,
                                id="public_{}".format(s),
                                cidr_block=s,
                                vpc_id=vpc.ref,
                                availability_zone=core.Fn.select(
                                    i, core.Fn.get_azs()),
                                map_public_ip_on_launch=True)
         public_subnets.append(subnet)
         ec2.CfnSubnetRouteTableAssociation(
             self,
             id="public_{}_association".format(s),
             route_table_id=public_route_table.ref,
             subnet_id=subnet.ref)
     eip = ec2.CfnEIP(self, id="natip")
     nat = ec2.CfnNatGateway(self,
                             id="nat",
                             allocation_id=eip.attr_allocation_id,
                             subnet_id=public_subnets[0].ref)
     private_route_table = ec2.CfnRouteTable(self,
                                             id="private_route_table",
                                             vpc_id=vpc.ref)
     ec2.CfnRoute(self,
                  id="private_route",
                  route_table_id=private_route_table.ref,
                  destination_cidr_block="0.0.0.0/0",
                  nat_gateway_id=nat.ref)
     private_subnets = []
     for i, s in enumerate(data["subnets"]["private"]):
         subnet = ec2.CfnSubnet(self,
                                id="private_{}".format(s),
                                cidr_block=s,
                                vpc_id=vpc.ref,
                                availability_zone=core.Fn.select(
                                    i, core.Fn.get_azs()),
                                map_public_ip_on_launch=False)
         private_subnets.append(subnet)
         ec2.CfnSubnetRouteTableAssociation(
             self,
             id="private_{}_association".format(s),
             route_table_id=private_route_table.ref,
             subnet_id=subnet.ref)
     # Security groups
     lb_sg = ec2.CfnSecurityGroup(self,
                                  id="lb",
                                  group_description="LB SG",
                                  vpc_id=vpc.ref)
     lambda_sg = ec2.CfnSecurityGroup(self,
                                      id="lambda",
                                      group_description="Lambda SG",
                                      vpc_id=vpc.ref)
     public_prefix = ec2.CfnPrefixList(self,
                                       id="cidr_prefix",
                                       address_family="IPv4",
                                       max_entries=1,
                                       prefix_list_name="public",
                                       entries=[{
                                           "cidr": "0.0.0.0/0",
                                           "description": "Public"
                                       }])
     _sg_rules = [{
         'sg':
         lb_sg.attr_group_id,
         'rules': [{
             "direction": "ingress",
             "description": "HTTP from Internet",
             "from_port": 80,
             "to_port": 80,
             "protocol": "tcp",
             "cidr_blocks": public_prefix.ref
         }, {
             "direction": "egress",
             "description": "LB to Lambda",
             "from_port": 80,
             "to_port": 80,
             "protocol": "tcp",
             "source_security_group_id": lambda_sg.attr_group_id
         }]
     }, {
         "sg":
         lambda_sg.attr_group_id,
         "rules": [{
             "direction": "ingress",
             "description": "HTTP from LB",
             "from_port": 80,
             "to_port": 80,
             "protocol": "tcp",
             "source_security_group_id": lb_sg.attr_group_id
         }, {
             "direction": "egress",
             "description": "All to Internet",
             "from_port": 0,
             "to_port": 65535,
             "protocol": "tcp",
             "cidr_blocks": public_prefix.ref
         }]
     }]
     for ruleset in _sg_rules:
         for rule in ruleset["rules"]:
             if rule["direction"] == "ingress":
                 ec2.CfnSecurityGroupIngress(
                     self,
                     id=rule["description"].replace(" ", "_"),
                     description=rule["description"],
                     to_port=rule["to_port"],
                     from_port=rule["from_port"],
                     ip_protocol=rule["protocol"],
                     group_id=ruleset["sg"],
                     source_prefix_list_id=rule["cidr_blocks"]
                     if "cidr_blocks" in rule else None,
                     source_security_group_id=rule[
                         "source_security_group_id"]
                     if "source_security_group_id" in rule else None)
             else:
                 ec2.CfnSecurityGroupEgress(
                     self,
                     id=rule["description"].replace(" ", "_"),
                     description=rule["description"],
                     to_port=rule["to_port"],
                     from_port=rule["from_port"],
                     ip_protocol=rule["protocol"],
                     group_id=ruleset["sg"],
                     destination_prefix_list_id=rule["cidr_blocks"]
                     if "cidr_blocks" in rule else None,
                     destination_security_group_id=rule[
                         "source_security_group_id"]
                     if "source_security_group_id" in rule else None)
     # IAM
     assume_policy_doc = iam.PolicyDocument()
     for statement in iam_vars["assume"]["Statement"]:
         _statement = iam.PolicyStatement(actions=[statement["Action"]], )
         _statement.add_service_principal(statement["Principal"]["Service"])
         assume_policy_doc.add_statements(_statement)
     role = iam.CfnRole(self,
                        id="iam_role",
                        path="/",
                        assume_role_policy_document=assume_policy_doc)
     role_policy_doc = iam.PolicyDocument()
     for statement in iam_vars["policy"]["Statement"]:
         _statement = iam.PolicyStatement(actions=statement["Action"],
                                          resources=["*"])
         role_policy_doc.add_statements(_statement)
     policy = iam.CfnPolicy(self,
                            id="iam_policy",
                            policy_document=role_policy_doc,
                            policy_name="cdkPolicy",
                            roles=[role.ref])
     # Lambda
     shutil.make_archive("../lambda", 'zip', "../lambda/")
     s3_client = boto3.client('s3')
     s3_client.upload_file("../lambda.zip", "cloudevescops-zdays-demo",
                           "cdk.zip")
     function = lmd.CfnFunction(self,
                                id="lambda_function",
                                handler="lambda.lambda_handler",
                                role=role.attr_arn,
                                runtime="python3.7",
                                code={
                                    "s3Bucket": "cloudevescops-zdays-demo",
                                    "s3Key": "cdk.zip"
                                },
                                vpc_config={
                                    "securityGroupIds": [lambda_sg.ref],
                                    "subnetIds":
                                    [s.ref for s in private_subnets]
                                },
                                environment={"variables": {
                                    "TOOL": "CDK"
                                }})
     # LB
     lb = alb.CfnLoadBalancer(self,
                              id="alb",
                              name="lb-cdk",
                              scheme="internet-facing",
                              type="application",
                              subnets=[s.ref for s in public_subnets],
                              security_groups=[lb_sg.ref])
     lmd.CfnPermission(self,
                       id="lambda_permis",
                       action="lambda:InvokeFunction",
                       function_name=function.ref,
                       principal="elasticloadbalancing.amazonaws.com")
     tg = alb.CfnTargetGroup(self,
                             id="alb_tg",
                             name="lambda-cdk",
                             target_type="lambda",
                             health_check_enabled=True,
                             health_check_interval_seconds=40,
                             health_check_path="/",
                             health_check_timeout_seconds=30,
                             targets=[{
                                 "id":
                                 function.get_att("Arn").to_string()
                             }],
                             matcher={"httpCode": "200"})
     alb.CfnListener(self,
                     id="listener",
                     default_actions=[{
                         "type": "forward",
                         "targetGroupArn": tg.ref
                     }],
                     load_balancer_arn=lb.ref,
                     port=80,
                     protocol="HTTP")
     core.CfnOutput(self, id="fqdn", value=lb.attr_dns_name)
Ejemplo n.º 4
0
    def __init__(self, scope: core.Construct, construct_id: str,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        vpc = ec2.Vpc(self,
                      id="MyVPC",
                      nat_gateways=0,
                      cidr="192.168.0.0/20",
                      max_azs=3,
                      subnet_configuration=[])
        pub_subnet = ec2.PublicSubnet(self,
                                      id="PublicSubnet",
                                      availability_zone="eu-central-1c",
                                      cidr_block="192.168.0.0/24",
                                      vpc_id=vpc.vpc_id,
                                      map_public_ip_on_launch=True)

        igw = ec2.CfnInternetGateway(
            self, id="MyIGW", tags=[core.CfnTag(key="Name", value="IGW")])

        ec2.CfnVPCGatewayAttachment(self,
                                    id="IGW_Assoc",
                                    vpc_id=vpc.vpc_id,
                                    internet_gateway_id=igw.ref)

        pub_subnet.add_route(id="default_route-sub01",
                             router_id=igw.ref,
                             router_type=ec2.RouterType('GATEWAY'),
                             destination_cidr_block="0.0.0.0/0",
                             enables_internet_connectivity=True)

        # Elastic IP
        eip_01 = ec2.CfnEIP(self, id="EIP01")

        # NAT gateway
        ngw = ec2.CfnNatGateway(self,
                                id="NAT_GW",
                                allocation_id=eip_01.attr_allocation_id,
                                subnet_id=pub_subnet.subnet_id,
                                tags=[core.CfnTag(key="Name", value="NAT_GW")])

        subnet01 = ec2.Subnet(self,
                              id="Subnet01",
                              availability_zone="eu-central-1a",
                              cidr_block="192.168.1.0/24",
                              vpc_id=vpc.vpc_id,
                              map_public_ip_on_launch=False)

        subnet02 = ec2.Subnet(self,
                              id="Subnet02",
                              availability_zone="eu-central-1b",
                              cidr_block="192.168.2.0/24",
                              vpc_id=vpc.vpc_id,
                              map_public_ip_on_launch=False)

        subnet01.add_route(id="default_route-sub01",
                           router_id=ngw.ref,
                           router_type=ec2.RouterType('NAT_GATEWAY'),
                           destination_cidr_block="0.0.0.0/0",
                           enables_internet_connectivity=True)

        subnet02.add_route(id="default_route-sub02",
                           router_id=ngw.ref,
                           router_type=ec2.RouterType('NAT_GATEWAY'),
                           destination_cidr_block="0.0.0.0/0",
                           enables_internet_connectivity=True)

        sg_lb = ec2.CfnSecurityGroup(
            self,
            id="SG_ALB",
            group_description="SG for the APP LB",
            group_name="SG_ALB",
            vpc_id=vpc.vpc_id,
            tags=[core.CfnTag(key="Name", value="SG_ALB")])

        sg_ec2i = ec2.CfnSecurityGroup(
            self,
            id="SG_Instances",
            group_description="SG for the Instances",
            group_name="SG_Instances",
            vpc_id=vpc.vpc_id,
            tags=[core.CfnTag(key="Name", value="SG_Instances")])

        # my_home_ip = requests.get("https://api.ipify.org").text
        my_home_ip = "94.112.113.195"
        ports_pub = {'tcp': [22, 80], 'icmp': [-1]}

        for protocol, ports_list in ports_pub.items():
            for port in ports_list:
                ec2.CfnSecurityGroupIngress(
                    self,
                    id=f"sg_alb_in_{protocol}_{port}",
                    group_id=sg_lb.attr_group_id,
                    ip_protocol=protocol,
                    cidr_ip=f"{my_home_ip}/32",
                    to_port=port,
                    from_port=port,
                    description=f"{protocol.upper()} {port} from home IP")

                ec2.CfnSecurityGroupIngress(
                    self,
                    id=f"sg_ec2i_in_{protocol}_{port}",
                    group_id=sg_ec2i.attr_group_id,
                    ip_protocol=protocol,
                    to_port=port,
                    from_port=port,
                    source_security_group_id=sg_lb.ref,
                    description=f"{protocol.upper()} {port} from the ALB SG")

        with open(
                "/home/dragos/Documents/AWS_CDK/app_lb_sample/app_lb_sample/configure.sh",
                'r') as config_file:
            ud = core.Fn.base64(config_file.read())

        bastion_host = ec2.CfnInstance(
            self,
            id="bastion",
            image_id="ami-0de9f803fcac87f46",
            instance_type="t2.micro",
            subnet_id=pub_subnet.subnet_id,
            key_name="proton_mail_kp",
            security_group_ids=[sg_lb.ref],
            tags=[core.CfnTag(key="Name", value="bastion")])

        instance01 = ec2.CfnInstance(
            self,
            id="WebServer01",
            image_id="ami-0de9f803fcac87f46",
            instance_type="t2.micro",
            subnet_id=subnet01.subnet_id,
            key_name="proton_mail_kp",
            security_group_ids=[sg_ec2i.ref],
            user_data=ud,
            tags=[core.CfnTag(key="Name", value="WebServer01")])

        instance02 = ec2.CfnInstance(
            self,
            id="WebServer02",
            image_id="ami-0de9f803fcac87f46",
            instance_type="t2.micro",
            subnet_id=subnet02.subnet_id,
            key_name="proton_mail_kp",
            security_group_ids=[sg_ec2i.ref],
            user_data=ud,
            tags=[core.CfnTag(key="Name", value="WebServer02")])

        # health_check = elbv2.HealthCheck(enabled=True,
        #                                  healthy_http_codes="200",
        #                                  path="/index.html",
        #                                  protocol=elbv2.Protocol("HTTP"))

        target01 = elbv2.CfnTargetGroup.TargetDescriptionProperty(
            id=instance01.ref)
        target02 = elbv2.CfnTargetGroup.TargetDescriptionProperty(
            id=instance02.ref)

        tg = elbv2.CfnTargetGroup(
            self,
            id="TG-WEB-HTTP",
            name="TG-WEB-HTTP",
            health_check_enabled=True,
            health_check_path="/index.html",
            health_check_port="80",
            matcher=elbv2.CfnTargetGroup.MatcherProperty(http_code="200"),
            port=80,
            protocol="HTTP",  # CASE SENSITIVE
            target_type="instance",  # CASE SENSITIVE
            targets=[target01, target02],
            vpc_id=vpc.vpc_id)

        alb = elbv2.CfnLoadBalancer(
            self,
            id="MyALB-HTTP",
            ip_address_type="ipv4",
            name="MyALB-HTTP",
            scheme="internet-facing",
            security_groups=[sg_lb.ref],
            type="application",
            subnets=[subnet01.subnet_id, subnet02.subnet_id])

        def_act = Listener.ActionProperty(type="forward",
                                          authenticate_cognito_config=None,
                                          authenticate_oidc_config=None,
                                          fixed_response_config=None,
                                          forward_config=None,
                                          order=50000,
                                          redirect_config=None,
                                          target_group_arn=tg.ref)

        listener = elbv2.CfnListener(self,
                                     id="Listener01",
                                     load_balancer_arn=alb.ref,
                                     port=80,
                                     protocol="HTTP",
                                     default_actions=[def_act])
Ejemplo n.º 5
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Parameter
        LatestAmiId = core.CfnParameter(
            self,
            "LatestAmiId",
            type="AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
            default=
            "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2")

        # S3 Bucket
        source_bucket = "sourcebucketname%s" % (core.Aws.ACCOUNT_ID)

        # Resources
        CloudFormationLogs = logs.LogGroup(
            self,
            'CloudFormationLogs',
            retention=logs.RetentionDays('ONE_WEEK'))

        WebInstance1 = ec2.CfnInstance(
            self,
            'WebInstance1',
            additional_info=None,
            affinity=None,
            iam_instance_profile=core.Fn.import_value(
                "WebServerInstanceProfileOutput"),
            image_id=LatestAmiId.value_as_string,
            instance_type='t3.micro',
            network_interfaces=[{
                "deviceIndex":
                "0",
                "groupSet": [core.Fn.import_value("WebSecurityGroupOutput")],
                "subnetId":
                core.Fn.import_value("PrivateSubnet1")
            }],
            tags=[core.CfnTag(key="Name", value="WebServer1")],
            user_data=core.Fn.base64("""#!/bin/bash -ex
            yum update -y
            /opt/aws/bin/cfn-init -v --stack {StackName} --resource WebInstance1 --configsets InstallAndDeploy --region {Region}
            # Signal the status from cfn-init (via $?)
            /opt/aws/bin/cfn-signal -e $? --stack {StackName} --resource WebInstance1 --region {Region}
            """.format(StackName=core.Aws.STACK_NAME, Region=core.Aws.REGION)))
        WebInstance1.cfn_options.metadata = {
            "AWS::CloudFormation::Authentication": {
                "rolebased": {
                    "type": "S3",
                    "buckets": [source_bucket],
                    "roleName": core.Fn.import_value("WebServerRoleOutput")
                }
            },
            "AWS::CloudFormation::Init": {
                "configSets": {
                    "InstallAndDeploy": ["Install", "InstallLogs", "Deploy"]
                },
                "Install": {
                    "packages": {
                        "yum": {
                            "python36": [],
                            "python36-devel": [],
                            "nginx": [],
                            "gcc": []
                        }
                    },
                    "files": {
                        "/etc/cfn/cfn-hup.conf": {
                            "content":
                            """
                                [main]
                                stack={}
                                region={}
                                interval=1
                                verbose=true""".format(core.Aws.STACK_ID,
                                                       core.Aws.REGION),
                            "mode":
                            "000400",
                            "owner":
                            "root",
                            "group":
                            "root"
                        },
                        "/etc/cfn/hooks.d/cfn-auto-reloader.conf": {
                            "content":
                            """
                                [cfn-auto-reloader-hook]
                                triggers=post.update
                                path=Resources.WebInstance1.Metadata.AWS::CloudFormation::Init
                                action=/opt/aws/bin/cfn-init -v --stack {} --resource WebInstance1 --configsets InstallAndDeploy --region {}
                                runas=root""".format(core.Aws.STACK_NAME,
                                                     core.Aws.REGION),
                            "mode":
                            "000400",
                            "owner":
                            "root",
                            "group":
                            "root"
                        }
                    },
                    "services": {
                        "sysvinit": {
                            "nginx": {
                                "enabled": "true",
                                "ensureRunning": "true"
                            },
                            "cfn-hup": {
                                "enabled":
                                "true",
                                "ensureRunning":
                                "true",
                                "files": [
                                    "/etc/cfn/cfn-hup.conf",
                                    "/etc/cfn/hooks.d/cfn-auto-reloader.conf"
                                ]
                            }
                        }
                    },
                    "commands": {
                        "01_unblock_nginx": {
                            "command": "chkconfig nginx on"
                        },
                        "02_install_xray": {
                            "command":
                            "curl https://s3.dualstack.us-east-2.amazonaws.com/aws-xray-assets.us-east-2/xray-daemon/aws-xray-daemon-3.x.rpm -o /tmp/xray.rpm && yum install -y /tmp/xray.rpm\n",
                            "cwd": "/tmp",
                            "ignoreErrors": "true"
                        }
                    }
                },
                "InstallLogs": {
                    "packages": {
                        "yum": {
                            "awslogs": []
                        }
                    },
                    "files": {
                        "/etc/awslogs/awslogs.conf": {
                            "content":
                            """
                            [general]
                            state_file= /var/awslogs/state/agent-state
                            [yum]
                            file = /var/log/yum.log
                            log_group_name = %s
                            log_stream_name = {{hostname}} - {{instance_id}} yum.log
                            [messages]
                            file = /var/log/messages
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} messages.log
                            [cfn-hup]
                            file = /var/log/cfn-hup.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cfn-hup.log
                            [cfn-init]
                            file = /var/log/cfn-init.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cfn-init.log
                            [cfn-init-cmd]
                            file = /var/log/cfn-init-cmd.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cfn-init-cmd.log
                            [cloud-init]
                            file = /var/log/cloud-init.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cloud-init.log
                            [cloud-init-output]
                            file = /var/log/cloud-init-output.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cloud-init.log
                            [handler]
                            file = /var/log/handler.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} handler.log
                            [uwsgi]
                            file = /var/log/uwsgi.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} uwsgi.log
                            [nginx_access]
                            file = /var/log/nginx/access.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} nginx_access.log
                            [nginx_error]
                            file = /var/log/nginx/error.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} nginx_error.log
                            """.format(CloudFormationLogs=CloudFormationLogs.
                                       log_group_name),
                            "group":
                            "root",
                            "owner":
                            "root",
                            "mode":
                            "000400"
                        },
                        "/etc/awslogs/awscli.conf": {
                            "content":
                            """
                                [plugins]
                                cwlogs = cwlogs
                                [default]
                                region = {}
                            """.format(core.Aws.REGION),
                            "mode":
                            "000444",
                            "owner":
                            "root",
                            "group":
                            "root"
                        }
                    },
                    "commands": {
                        "01_create_state_directory": {
                            "command": "mkdir -p /var/awslogs/state"
                        }
                    },
                    "services": {
                        "sysvinit": {
                            "awslogs": {
                                "enabled": "true",
                                "ensureRunning": "true",
                                "files": ["/etc/awslogs/awslogs.conf"]
                            }
                        }
                    }
                },
                "Deploy": {
                    "sources": {
                        "/photos":
                        "https://s3.amazonaws.com/{}/deploy-app.zip".format(
                            source_bucket)
                    },
                    "commands": {
                        "01_pip_uwsgi": {
                            "command": "pip-3.6 install uwsgi",
                            "cwd": "/photos",
                            "ignoreErrors": "false"
                        },
                        "02_pip_flask_app_requirements": {
                            "command": "pip-3.6 install -r requirements.txt",
                            "cwd": "/photos/FlaskApp",
                            "ignoreErrors": "false"
                        },
                        "03_stop_uwsgi": {
                            "command": "stop uwsgi",
                            "ignoreErrors": "true"
                        },
                        "04_stop_nginx": {
                            "command": "service nginx stop"
                        },
                        "05_copy_config": {
                            "command":
                            "mv -f nginx.conf /etc/nginx/nginx.conf && mv -f uwsgi.conf /etc/init/uwsgi.conf",
                            "cwd": "/photos/Deploy",
                            "ignoreErrors": "false"
                        },
                        "06_create_database": {
                            "command": "python3 database_create_tables.py",
                            "cwd": "/photos/Deploy",
                            "ignoreErrors": "false"
                        },
                        "07_start_uwsgi": {
                            "command": "start uwsgi"
                        },
                        "08_restart_nginx": {
                            "command": "service nginx start"
                        }
                    }
                }
            }
        }
        WebInstance1.cfn_options.creation_policy = core.CfnCreationPolicy(
            resource_signal=core.CfnResourceSignal(timeout='PT10M'))

        WebInstance2 = ec2.CfnInstance(
            self,
            'WebInstance2',
            additional_info=None,
            affinity=None,
            iam_instance_profile=core.Fn.import_value(
                "WebServerInstanceProfileOutput"),
            image_id=LatestAmiId.value_as_string,
            instance_type='t3.micro',
            network_interfaces=[{
                "deviceIndex":
                "0",
                "groupSet": [core.Fn.import_value("WebSecurityGroupOutput")],
                "subnetId":
                core.Fn.import_value("PrivateSubnet2")
            }],
            tags=[core.CfnTag(key="Name", value="WebServer2")],
            user_data=core.Fn.base64("""#!/bin/bash -ex
              yum update -y
              /opt/aws/bin/cfn-init -v --stack {StackName} --resource WebInstance2 --configsets InstallAndDeploy --region {Region}
              # Signal the status from cfn-init (via $?)
              /opt/aws/bin/cfn-signal -e $? --stack {StackName} --resource WebInstance2 --region {Region}
            """.format(StackName=core.Aws.STACK_NAME, Region=core.Aws.REGION)))
        WebInstance2.cfn_options.metadata = {
            "AWS::CloudFormation::Authentication": {
                "rolebased": {
                    "type": "S3",
                    "buckets": [source_bucket],
                    "roleName": core.Fn.import_value("WebServerRoleOutput")
                }
            },
            "AWS::CloudFormation::Init": {
                "configSets": {
                    "InstallAndDeploy": ["Install", "InstallLogs", "Deploy"]
                },
                "Install": {
                    "packages": {
                        "yum": {
                            "python36": [],
                            "python36-devel": [],
                            "nginx": [],
                            "gcc": []
                        }
                    },
                    "files": {
                        "/etc/cfn/cfn-hup.conf": {
                            "content":
                            """
                                [main]
                                stack={}
                                region={}
                                interval=1
                                verbose=true""".format(core.Aws.STACK_ID,
                                                       core.Aws.REGION),
                            "mode":
                            "000400",
                            "owner":
                            "root",
                            "group":
                            "root"
                        },
                        "/etc/cfn/hooks.d/cfn-auto-reloader.conf": {
                            "content":
                            """
                                [cfn-auto-reloader-hook]
                                triggers=post.update
                                path=Resources.WebInstance1.Metadata.AWS::CloudFormation::Init
                                action=/opt/aws/bin/cfn-init -v --stack {} --resource WebInstance2 --configsets InstallAndDeploy --region {}
                                runas=root""".format(core.Aws.STACK_NAME,
                                                     core.Aws.REGION),
                            "mode":
                            "000400",
                            "owner":
                            "root",
                            "group":
                            "root"
                        }
                    },
                    "services": {
                        "sysvinit": {
                            "nginx": {
                                "enabled": "true",
                                "ensureRunning": "true"
                            },
                            "cfn-hup": {
                                "enabled":
                                "true",
                                "ensureRunning":
                                "true",
                                "files": [
                                    "/etc/cfn/cfn-hup.conf",
                                    "/etc/cfn/hooks.d/cfn-auto-reloader.conf"
                                ]
                            }
                        }
                    },
                    "commands": {
                        "01_unblock_nginx": {
                            "command": "chkconfig nginx on"
                        },
                        "02_install_xray": {
                            "command":
                            "curl https://s3.dualstack.us-east-2.amazonaws.com/aws-xray-assets.us-east-2/xray-daemon/aws-xray-daemon-3.x.rpm -o /tmp/xray.rpm && yum install -y /tmp/xray.rpm\n",
                            "cwd": "/tmp",
                            "ignoreErrors": "true"
                        }
                    }
                },
                "InstallLogs": {
                    "packages": {
                        "yum": {
                            "awslogs": []
                        }
                    },
                    "files": {
                        "/etc/awslogs/awslogs.conf": {
                            "content":
                            """
                            [general]
                            state_file= /var/awslogs/state/agent-state
                            [yum]
                            file = /var/log/yum.log
                            log_group_name = %s
                            log_stream_name = {{hostname}} - {{instance_id}} yum.log
                            [messages]
                            file = /var/log/messages
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} messages.log
                            [cfn-hup]
                            file = /var/log/cfn-hup.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cfn-hup.log
                            [cfn-init]
                            file = /var/log/cfn-init.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cfn-init.log
                            [cfn-init-cmd]
                            file = /var/log/cfn-init-cmd.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cfn-init-cmd.log
                            [cloud-init]
                            file = /var/log/cloud-init.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cloud-init.log
                            [cloud-init-output]
                            file = /var/log/cloud-init-output.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} cloud-init.log
                            [handler]
                            file = /var/log/handler.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} handler.log
                            [uwsgi]
                            file = /var/log/uwsgi.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} uwsgi.log
                            [nginx_access]
                            file = /var/log/nginx/access.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} nginx_access.log
                            [nginx_error]
                            file = /var/log/nginx/error.log
                            log_group_name = {CloudFormationLogs}
                            log_stream_name = {{hostname}} - {{instance_id}} nginx_error.log
                            """.format(CloudFormationLogs=CloudFormationLogs.
                                       log_group_name),
                            "group":
                            "root",
                            "owner":
                            "root",
                            "mode":
                            "000400"
                        },
                        "/etc/awslogs/awscli.conf": {
                            "content":
                            """
                                [plugins]
                                cwlogs = cwlogs
                                [default]
                                region = {}
                            """.format(core.Aws.REGION),
                            "mode":
                            "000444",
                            "owner":
                            "root",
                            "group":
                            "root"
                        }
                    },
                    "commands": {
                        "01_create_state_directory": {
                            "command": "mkdir -p /var/awslogs/state"
                        }
                    },
                    "services": {
                        "sysvinit": {
                            "awslogs": {
                                "enabled": "true",
                                "ensureRunning": "true",
                                "files": ["/etc/awslogs/awslogs.conf"]
                            }
                        }
                    }
                },
                "Deploy": {
                    "sources": {
                        "/photos":
                        "https://s3.amazonaws.com/{}/deploy-app.zip".format(
                            source_bucket)
                    },
                    "commands": {
                        "01_pip_uwsgi": {
                            "command": "pip-3.6 install uwsgi",
                            "cwd": "/photos",
                            "ignoreErrors": "false"
                        },
                        "02_pip_flask_app_requirements": {
                            "command": "pip-3.6 install -r requirements.txt",
                            "cwd": "/photos/FlaskApp",
                            "ignoreErrors": "false"
                        },
                        "03_stop_uwsgi": {
                            "command": "stop uwsgi",
                            "ignoreErrors": "true"
                        },
                        "04_stop_nginx": {
                            "command": "service nginx stop"
                        },
                        "05_copy_config": {
                            "command":
                            "mv -f nginx.conf /etc/nginx/nginx.conf && mv -f uwsgi.conf /etc/init/uwsgi.conf",
                            "cwd": "/photos/Deploy",
                            "ignoreErrors": "false"
                        },
                        "06_create_database": {
                            "command": "python3 database_create_tables.py",
                            "cwd": "/photos/Deploy",
                            "ignoreErrors": "false"
                        },
                        "07_start_uwsgi": {
                            "command": "start uwsgi"
                        },
                        "08_restart_nginx": {
                            "command": "service nginx start"
                        }
                    }
                }
            }
        }

        WebInstance2.cfn_options.creation_policy = core.CfnCreationPolicy(
            resource_signal=core.CfnResourceSignal(timeout='PT10M'))

        DefaultTargetGroup = elasticloadbalancingv2.CfnTargetGroup(
            self,
            'DefaultTargetGroup',
            health_check_interval_seconds=15,
            health_check_path="/",
            health_check_protocol="HTTP",
            health_check_timeout_seconds=10,
            healthy_threshold_count=2,
            unhealthy_threshold_count=2,
            matcher={'httpCode': '200-299'},
            port=80,
            protocol="HTTP",
            vpc_id=core.Fn.import_value("VPC"),
            target_group_attributes=[{
                "key": "deregistration_delay.timeout_seconds",
                "value": "30"
            }],
            targets=[{
                "id": WebInstance1.ref,
                "port": 80
            }, {
                "id": WebInstance2.ref,
                "port": 80
            }])

        HttpListener = elasticloadbalancingv2.CfnListener(
            self,
            'HttpListener',
            default_actions=[{
                "type": "forward",
                "targetGroupArn": DefaultTargetGroup.ref
            }],
            load_balancer_arn=core.Fn.import_value("LoadBalancerArn"),
            port=80,
            protocol="HTTP")
    def __init__(self, scope: core.Construct, id: str, application_port,
                 ingress_security_group_ids, ssl_certificate_arn, ssl_policy,
                 subnet_ids, vpc_id):
        super().__init__(scope, id)

        # Use low level constructs to build security groups as it allows us to name the
        # ingress rules properly. It's also easier to map the low level construct params
        # to their cfn equivalent
        app_sg = ec2.CfnSecurityGroup(
            self,
            id='SharedApplicationSecurityGroup',
            group_description='Shared Fargate Security Group',
            vpc_id=vpc_id)
        app_lb_sg = ec2.CfnSecurityGroup(
            self,
            id='SharedApplicationLBSecurityGroup',
            group_description='Shared ALB Security Group',
            vpc_id=vpc_id,
            security_group_egress=[{
                'ipProtocol': 'tcp',
                'fromPort': application_port,
                'toPort': application_port,
                'destinationSecurityGroupId': app_sg.ref
            }])
        app_sg_ingress = ec2.CfnSecurityGroupIngress(
            self,
            id='SharedApplicationSecurityGroupIngress',
            group_id=app_sg.ref,
            source_security_group_id=app_lb_sg.ref,
            ip_protocol='tcp',
            from_port=application_port,
            to_port=application_port)
        for index, sg in enumerate(ingress_security_group_ids):
            ec2.CfnSecurityGroupIngress(
                self,
                id=f"SharedApplicationLBSecurityGroupIngress{index}",
                group_id=app_lb_sg.ref,
                source_security_group_id=sg,
                ip_protocol='tcp',
                from_port=443,
                to_port=443)
        lb = elbv2.CfnLoadBalancer(self,
                                   id='SharedLoadBalancer',
                                   scheme='internal',
                                   security_groups=[app_lb_sg.ref],
                                   subnets=subnet_ids)
        listener = elbv2.CfnListener(
            self,
            id='SharedListener',
            certificates=[{
                'certificateArn': ssl_certificate_arn
            }],
            default_actions=[{
                'type': 'fixed-response',
                'fixedResponseConfig': {
                    'contentType': 'text/plain',
                    'messageBody':
                    'You have reached the the Load Balancer, but not matched any of the listener rules',
                    'statusCode': '200'
                }
            }],
            load_balancer_arn=lb.ref,
            port=443,
            protocol='HTTPS',
            ssl_policy=ssl_policy)

        core.CfnOutput(
            self,
            id=SHARED_LB_DNS_NAME,
            description='Shared Load Balancer DNS Name',
            export_name=f"{core.Aws.STACK_NAME}:{SHARED_LB_DNS_NAME}",
            value=lb.attr_dns_name)
        core.CfnOutput(
            self,
            id=SHARED_LB_HOSTED_ZONE_ID,
            description='Shared Load Balancer Canonical Hosted Zone ID',
            export_name=f"{core.Aws.STACK_NAME}:{SHARED_LB_HOSTED_ZONE_ID}",
            value=lb.attr_canonical_hosted_zone_id)
        core.CfnOutput(
            self,
            id=SHARED_LB_LISTENER,
            description='Shared Load Balancer Listener',
            export_name=f"{core.Aws.STACK_NAME}:{SHARED_LB_LISTENER}",
            value=listener.ref)
        core.CfnOutput(
            self,
            id=SHARED_SERVICE_SECURITY_GROUP,
            description='Shared Fargate Security Group',
            export_name=
            f"{core.Aws.STACK_NAME}:{SHARED_SERVICE_SECURITY_GROUP}",
            value=app_sg.ref)