AWS Cloud Formation (example 6)

  • VPC
  • Internet Gateway
  • NAT Gateway
  • Public Subnet x2
  • Private Subnet x2
  • Security Group x3
    • for Load Balancer (TCP 80)
    • for EC2 Bastion (TCP 22)
    • for EC2 Web Instances (TCP 80, TCP 22)
  • EC2 – Bastion
    • in PublicASubnet
  • EC2 – Web Instance x2
    • in PrivateASubnet
    • in PrivateBSubnet
  • Load Balancer
    • for EC2 – Web Instances
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  BastionKeyName:
    Description: The EC2 Key Pair to allow SSH access to the bastion
    Type: 'AWS::EC2::KeyPair::KeyName'
    Default: bastion
  InstanceKeyName:
    Description: The EC2 Key Pair to allow SSH access to the instance
    Type: 'AWS::EC2::KeyPair::KeyName'
    Default: instance

Resources:

# VPC -----------------------------------------------------

  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
      - Key: Name
        Value:  !Join ['', [!Ref "AWS::StackName", "-vpc" ]]

# InternetGateway -----------------------------------------------------

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    DependsOn: VPC
    Properties:
      Tags:
      - Key: Name
        Value:  !Join ['', [!Ref "AWS::StackName", "-ig" ]]

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway


# NATGateway -------------------------------------------------------

  ElasticIPAddress:
    Type: AWS::EC2::EIP
    Properties:
      Domain: VPC

  NATGateway:
    Type: AWS::EC2::NatGateway
    DependsOn: PublicASubnet
    Properties:
      AllocationId: !GetAtt ElasticIPAddress.AllocationId
      SubnetId: !Ref PublicASubnet
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-nat

# Subnet --------------------------------------------------------------

  PublicASubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.10.0/24
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-public-a

  PublicBSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.20.0/24
      AvailabilityZone: !Select [ 1, !GetAZs ]
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-public-b

  PrivateASubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.50.0/24
      AvailabilityZone: !Select [ 0, !GetAZs ]
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-private-a

  PrivateBSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.60.0/24
      AvailabilityZone: !Select [ 1, !GetAZs ]
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-private-b

# PublicARouteTable -------------------------------------------------------

  PublicARouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-public-a
  PublicARoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicARouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicASubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicASubnet
      RouteTableId: !Ref PublicARouteTable

# PublicBRouteTable -------------------------------------------------------

  PublicBRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-public-b
  PublicBRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicBRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicBSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicBSubnet
      RouteTableId: !Ref PublicBRouteTable

# PrivateARouteTable -------------------------------------------------------

  PrivateARouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-private-a
  PrivateARoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateARouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway
  PrivateASubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateASubnet
      RouteTableId: !Ref PrivateARouteTable

# PrivateBRouteTable -------------------------------------------------------

  PrivateBRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-private-b
  PrivateBRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateBRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGateway
  PrivateASubnetBRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateBSubnet
      RouteTableId: !Ref PrivateBRouteTable

# SecurityGroup --------------------------------------------------------------------

  LBSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPC
      GroupDescription: LB access
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-lb
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '80'
        ToPort: '80'
        CidrIp: 0.0.0.0/0

  BastionSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPC
      GroupDescription: Web access
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-bastion
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '22'
        ToPort: '22'
        CidrIp: 0.0.0.0/0

  InstanceSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPC
      GroupDescription: Instance access
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-instance
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '80'
        ToPort: '80'
        CidrIp: 0.0.0.0/0
      - IpProtocol: tcp
        FromPort: '22'
        ToPort: '22'
        "SourceSecurityGroupId": {
          "Fn::GetAtt": [
            "BastionSecurityGroup",
            "GroupId"
          ]
        }

# EC2 --------------------------------------------------------------------

  ElasticIPAddressWeb1:
    Type: AWS::EC2::EIP
    Properties:
      Domain: VPC
      InstanceId: !Ref BastionE2cInstance

  BastionE2cInstance:
    Type: 'AWS::EC2::Instance'
    Properties:
      KeyName: !Ref BastionKeyName
      ImageId: 'ami-035b3c7efe6d061d5'
      NetworkInterfaces:
      - AssociatePublicIpAddress: False
        DeviceIndex: "0"
        GroupSet:
        - !Ref BastionSecurityGroup
        SubnetId:
          !Ref PublicASubnet
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-bastion

  WebAEc2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      KeyName: !Ref InstanceKeyName
      ImageId: 'ami-035b3c7efe6d061d5'
      NetworkInterfaces:
      - AssociatePublicIpAddress: False
        DeviceIndex: "0"
        GroupSet:
        - !Ref InstanceSecurityGroup
        SubnetId:
          !Ref PrivateASubnet
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-web-a
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install httpd -y
          /etc/init.d/httpd start
          echo "Server 1" > /var/www/html/index.html

  WebBEc2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      KeyName: !Ref InstanceKeyName
      ImageId: 'ami-035b3c7efe6d061d5'
      NetworkInterfaces:
      - AssociatePublicIpAddress: False
        DeviceIndex: "0"
        GroupSet:
        - !Ref InstanceSecurityGroup
        SubnetId:
          !Ref PrivateBSubnet
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-web-b
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install httpd -y
          /etc/init.d/httpd start
          echo "Server 2" > /var/www/html/index.html

# LoadBalancer --------------------------------------------------------------------

  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Subnets:
      - !Ref PublicASubnet
      - !Ref PublicBSubnet
      SecurityGroups:
      - !Ref LBSecurityGroup
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-lb

  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Port: 80
      Protocol: HTTP
      DefaultActions:
      - Type: forward
        TargetGroupArn: !Ref DefaultTargetGroup

  DefaultTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${AWS::StackName}-dtg
      VpcId: !Ref VPC
      Port: 80
      Protocol: HTTP
      Targets:
      - Id: !Ref WebAEc2Instance
      - Id: !Ref WebBEc2Instance