AWSTemplateFormatVersion: '2010-09-09'
Description: AWS CloudFormation Template for use with p42.
Parameters:
  SSHLocation:
    Description: Lockdown SSH access to the bastion host (default can be accessed from anywhere)
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: must be a valid CIDR range of the form x.x.x.x/x.
Mappings:
  SubnetConfig:
    VPC:
      CIDR: 10.0.0.0/16
    Public:
      CIDR: 10.0.0.0/24
Resources:
  VPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      CidrBlock:
        'Fn::FindInMap':
          - SubnetConfig
          - VPC
          - CIDR
      Tags:
        - Key: Application
          Value:
            Ref: 'AWS::StackName'
        - Key: Network
          Value: Public
  PublicSubnet:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId:
        Ref: VPC
      CidrBlock:
        'Fn::FindInMap':
          - SubnetConfig
          - Public
          - CIDR
      Tags:
        - Key: Application
          Value:
            Ref: 'AWS::StackName'
        - Key: Network
          Value: Public
  InternetGateway:
    Type: 'AWS::EC2::InternetGateway'
    Properties:
      Tags:
        - Key: Application
          Value:
            Ref: 'AWS::StackName'
        - Key: Network
          Value: Public
  GatewayToInternet:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      VpcId:
        Ref: VPC
      InternetGatewayId:
        Ref: InternetGateway
  PublicRouteTable:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId:
        Ref: VPC
      Tags:
        - Key: Application
          Value:
            Ref: 'AWS::StackName'
        - Key: Network
          Value: Public
  PublicRoute:
    Type: 'AWS::EC2::Route'
    DependsOn: GatewayToInternet
    Properties:
      RouteTableId:
        Ref: PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: InternetGateway
  PublicSubnetRouteTableAssociation:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId:
        Ref: PublicSubnet
      RouteTableId:
        Ref: PublicRouteTable
  PublicNetworkAcl:
    Type: 'AWS::EC2::NetworkAcl'
    Properties:
      VpcId:
        Ref: VPC
      Tags:
        - Key: Application
          Value:
            Ref: 'AWS::StackName'
        - Key: Network
          Value: Public
  InboundHTTPPublicNetworkAclEntry:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      NetworkAclId:
        Ref: PublicNetworkAcl
      RuleNumber: '100'
      Protocol: '6'
      RuleAction: allow
      Egress: 'false'
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: '80'
        To: '80'
  InboundHTTPSPublicNetworkAclEntry:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      NetworkAclId:
        Ref: PublicNetworkAcl
      RuleNumber: '101'
      Protocol: '6'
      RuleAction: allow
      Egress: 'false'
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: '443'
        To: '443'
  InboundSSHPublicNetworkAclEntry:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      NetworkAclId:
        Ref: PublicNetworkAcl
      RuleNumber: '102'
      Protocol: '6'
      RuleAction: allow
      Egress: 'false'
      CidrBlock:
        Ref: SSHLocation
      PortRange:
        From: '22'
        To: '22'
  InboundEphemeralPublicNetworkAclEntry:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      NetworkAclId:
        Ref: PublicNetworkAcl
      RuleNumber: '103'
      Protocol: '6'
      RuleAction: allow
      Egress: 'false'
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: '1024'
        To: '65535'
  OutboundPublicNetworkAclEntry:
    Type: 'AWS::EC2::NetworkAclEntry'
    Properties:
      NetworkAclId:
        Ref: PublicNetworkAcl
      RuleNumber: '100'
      Protocol: '6'
      RuleAction: allow
      Egress: 'true'
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: '0'
        To: '65535'
  PublicSubnetNetworkAclAssociation:
    Type: 'AWS::EC2::SubnetNetworkAclAssociation'
    Properties:
      SubnetId:
        Ref: PublicSubnet
      NetworkAclId:
        Ref: PublicNetworkAcl
  PrivateDNS:
    Type: 'AWS::Route53::HostedZone'
    DependsOn: VPC
    Properties:
      Name: 'name.internal.'
      VPCs:
        - VPCId:
            Ref: VPC
          VPCRegion:
            Ref: 'AWS::Region'
  DHCPOptions :
    Type: 'AWS::EC2::DHCPOptions'
    Properties:
      DomainName: 'name.internal'
      DomainNameServers:
       - AmazonProvidedDNS
  ELBSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: 'Allow ELB to accept traffic from the public Web'
      VpcId:
        Ref: 'VPC'
      SecurityGroupIngress:
        - IpProtocol: 'tcp'
          FromPort: '80'
          ToPort: '80'
          CidrIp: '0.0.0.0/0'
  ELB:
    Type: 'AWS::ElasticLoadBalancing::LoadBalancer'
    DependsOn: GatewayToInternet
    Properties:
      LoadBalancerName:
        Ref: 'AWS::StackName'
      SecurityGroups:
        - Ref: 'ELBSecurityGroup'
        - 'Fn::GetAtt':
          - VPC
          - DefaultSecurityGroup
      Listeners:
        - LoadBalancerPort: 80
          Protocol: HTTP
          InstancePort: 80
        # Ignore HTTPS for now
        # - LoadBalancerPort: 443
        #   Protocol: HTTPS
        #   InstancePort: 80
        #   InstanceProtocol: HTTP
      Subnets:
        - Ref: 'PublicSubnet'
      HealthCheck:
        HealthyThreshold: 2 # checks
        Interval: 30 # seconds
        Target: "TCP:80"
        Timeout: 5
        UnhealthyThreshold: 2
Outputs:
  VPCId:
    Description: VPCId of the newly created VPC
    Value:
      Ref: VPC
  PublicSubnet:
    Description: SubnetId of the public subnet
    Value:
      Ref: PublicSubnet
  AvailabilityZone:
    Description: Availability Zone of the public subnet
    Value:
      'Fn::GetAtt':
        - PublicSubnet
        - AvailabilityZone
  HostedZoneId:
    Description: HostedZoneId of the private HostedZone
    Value:
      Ref: PrivateDNS
  DefaultSecurityGroupId:
    Description: "Default security group ID for the VPC"
    Value:
      'Fn::GetAtt':
        - VPC
        - DefaultSecurityGroup
