AWSTemplateFormatVersion: 2010-09-09
Description: Creating ECS service
Mappings:
  AWSRegionToAMI:
    ap-south-1:
      AMI: ami-00491f6f
    eu-west-3:
      AMI: ami-9aef59e7
    eu-west-2:
      AMI: ami-67cbd003
    eu-west-1:
      AMI: ami-1d46df64
    ap-northeast-2:
      AMI: ami-c212b2ac
    ap-northeast-1:
      AMI: ami-872c4ae1
    sa-east-1:
      AMI: ami-af521fc3
    ca-central-1:
      AMI: ami-435bde27
    ap-southeast-1:
      AMI: ami-910d72ed
    ap-southeast-2:
      AMI: ami-58bb443a
    eu-central-1:
      AMI: ami-509a053f
    us-east-1:
      AMI: ami-28456852
    us-east-2:
      AMI: ami-ce1c36ab
    us-west-1:
      AMI: ami-74262414
    us-west-2:
      AMI: ami-decc7fa6
Resources:
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: 10.0.0.0/24
  PrivateSubnet1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/26
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
  PrivateSubnet2:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.64/26
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ""
  PublicSubnet1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      MapPublicIpOnLaunch: true
      CidrBlock: 10.0.0.128/26
      AvailabilityZone:
        Fn::Select:
          - 0
          - Fn::GetAZs: ""
  PublicSubnet2:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      MapPublicIpOnLaunch: true
      CidrBlock: 10.0.0.192/26
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs: ""
  InternetGateway:
    Type: 'AWS::EC2::InternetGateway'
  GatewayAttachment:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC
  RouteIGW:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  NAT1:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
        - EIP1
        - AllocationId
      SubnetId: !Ref PublicSubnet1
  EIP1:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
  Route1:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId:
        Ref: PrivateRouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId:
        Ref: NAT1
  NAT2:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId:
        Fn::GetAtt:
        - EIP2
        - AllocationId
      SubnetId: !Ref PublicSubnet2
  EIP2:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
  Route2:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable2
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NAT2
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  PrivateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
  RouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable
  RouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet2
      RouteTableId: !Ref PublicRouteTable
  RouteTableAssociation3:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable1
  RouteTableAssociation4:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable2
  ECSCluster:
    Type: AWS::ECS::Cluster
  ALBPublic:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      SecurityGroups:
        - !GetAtt SecurityGroupPublic.GroupId
      Subnets:
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
  ALBPrivate:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internal
      SecurityGroups:
        - !GetAtt SecurityGroupWebapp.GroupId
      Subnets:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
  SecurityGroupPublic:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: ALBPublic
      GroupDescription: AllowWebTraffic
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
  SecurityGroupWebapp:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: WebAppSecurityGroup
      GroupDescription: WebAppSecurityGroupRules
      VpcId: !Ref VPC
  IngressRuleWebapp:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      FromPort: 8080
      ToPort: 8080
      SourceSecurityGroupId: !GetAtt SecurityGroupPublic.GroupId
      GroupId: !GetAtt SecurityGroupWebapp.GroupId
  IngressRuleWebapp001:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      IpProtocol: tcp
      FromPort: 8081
      ToPort: 8082
      SourceSecurityGroupId: !GetAtt SecurityGroupWebapp.GroupId
      GroupId: !GetAtt SecurityGroupWebapp.GroupId
  PublicECSHostSecurityGroup:
      Type: AWS::EC2::SecurityGroup
      Properties: 
          VpcId: !Ref VPC
          GroupDescription: Access to the ECS hosts and the tasks/containers that run on them
          SecurityGroupIngress:
                # Only allow inbound access to ECS from the ELB
              - SourceSecurityGroupId: !Ref SecurityGroupPublic 
                IpProtocol: -1
  PrivateECSHostSecurityGroup:
      Type: AWS::EC2::SecurityGroup
      Properties: 
          VpcId: !Ref VPC
          GroupDescription: Access to the ECS hosts and the tasks/containers that run on them
          SecurityGroupIngress:
                # Only allow inbound access to ECS from the ELB
              - SourceSecurityGroupId: !Ref SecurityGroupWebapp 
                IpProtocol: -1
  ECSRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref ECSRole
  PrivateAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier: [!Ref 'PrivateSubnet1']
      LaunchConfigurationName: !Ref PrivateLaunchConfiguration
      MinSize: 1
      MaxSize: 1
      DesiredCapacity: 1
      Tags: 
        - Key: Name
          Value: !Sub ${AWS::StackName} - ECS Host
          PropagateAtLaunch: true
    CreationPolicy:
      ResourceSignal:
        Timeout: PT15M
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinInstancesInService: 1
        MaxBatchSize: 1
        PauseTime: PT15M
        WaitOnResourceSignals: true

  PrivateLaunchConfiguration:
    Type: AWS::AutoScaling::LaunchConfiguration
    Metadata:
      AWS::CloudFormation::Init:
        config:
          commands:
            01_add_instance_to_cluster:
                command: !Sub echo ECS_CLUSTER=${ECSCluster} > /etc/ecs/ecs.config
          files:
            "/etc/cfn/cfn-hup.conf":
              mode: 000400
              owner: root
              group: root
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
            "/etc/cfn/hooks.d/cfn-auto-reloader.conf":
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.ContainerInstances.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource LaunchConfiguration
          services:
            sysvinit:
              cfn-hup:
                enabled: true
                ensureRunning: true
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    Properties:
      ImageId: !FindInMap [ AWSRegionToAMI, !Ref "AWS::Region", AMI ]
      InstanceType: m4.large
      IamInstanceProfile: !Ref InstanceProfile
      SecurityGroups:
        - !Ref PrivateECSHostSecurityGroup
      UserData:
        "Fn::Base64": !Sub |
          #!/bin/bash
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource PrivateLaunchConfiguration
          /opt/aws/bin/cfn-signal -e $? --region ${AWS::Region} --stack ${AWS::StackName} --resource PrivateAutoScalingGroup
   
  PublicAutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      VPCZoneIdentifier: [!Ref 'PublicSubnet1']
      LaunchConfigurationName: !Ref PublicLaunchConfiguration
      MinSize: 1
      MaxSize: 1
      DesiredCapacity: 1
      Tags: 
        - Key: Name
          Value: !Sub ${AWS::StackName} - ECS Host
          PropagateAtLaunch: true
    CreationPolicy:
      ResourceSignal:
        Timeout: PT15M
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinInstancesInService: 1
        MaxBatchSize: 1
        PauseTime: PT15M
        WaitOnResourceSignals: true

  PublicLaunchConfiguration:
    Type: AWS::AutoScaling::LaunchConfiguration
    Metadata:
      AWS::CloudFormation::Init:
        config:
          commands:
            01_add_instance_to_cluster:
                command: !Sub echo ECS_CLUSTER=${ECSCluster} > /etc/ecs/ecs.config
          files:
            "/etc/cfn/cfn-hup.conf":
              mode: 000400
              owner: root
              group: root
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
            "/etc/cfn/hooks.d/cfn-auto-reloader.conf":
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.ContainerInstances.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource LaunchConfiguration
          services:
            sysvinit:
              cfn-hup:
                enabled: true
                ensureRunning: true
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
    Properties:
      ImageId: !FindInMap [ AWSRegionToAMI, !Ref "AWS::Region", AMI ]
      InstanceType: m4.xlarge
      IamInstanceProfile: !Ref InstanceProfile
      SecurityGroups:
        - !Ref PublicECSHostSecurityGroup
      UserData:
        "Fn::Base64": !Sub |
          #!/bin/bash
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource PublicLaunchConfiguration
          /opt/aws/bin/cfn-signal -e $? --region ${AWS::Region} --stack ${AWS::StackName} --resource PublicAutoScalingGroup  
Outputs:
  ECSCluster:
    Value: !Ref ECSCluster
  VPC:
    Value: !Ref VPC
  PrivateSubnet1:
    Value: !Ref PrivateSubnet1
  PrivateSubnet2:
    Value: !Ref PrivateSubnet2
  PublicSubnet1:
    Value: !Ref PublicSubnet1
  PublicSubnet2:
    Value: !Ref PublicSubnet2
  ALBPublic:
    Value: !Ref ALBPublic
  ALBPrivate:
    Value: !Ref ALBPrivate
  ALBPublicCNAME:
    Value: !GetAtt ALBPublic.DNSName
  ALBPrivateCNAME:
    Value: !GetAtt ALBPrivate.DNSName
  SecurityGroupWebapp:
    Value: !GetAtt SecurityGroupWebapp.GroupId
  PrivateECSHostSecurityGroup:
    Value: !Ref PrivateECSHostSecurityGroup
  PublicECSHostSecurityGroup:
    Value: !Ref PrivateECSHostSecurityGroup