Set up three-tier architecture with CloudFormation

Share

CloudFormation is most important aspect infrastructure as a code provided by AWS that aids in the infrastructure deployment, rollback, infrastructure automation and configuration management of your AWS resources so that you may spend more time concentrating on your AWS-based applications and less time managing those resources. The AWS resources you require (such as Amazon EC2 instances or Amazon RDS DB instances) are listed in a template that you build, and CloudFormation handles the provisioning and configuration of those resources on your behalf. CloudFormation takes care of the creation, configuration, and identification of the dependencies between AWS resources, so you don’t have to.

In this blog, we will write a AWS CloudFormation template to create a three-tier architecture in AWS.

The three-tier architecture, which includes the web tier, application tier, and database tier, is the most often used in implementation of a multi-tier architecture in AWS Services.

The web layer is with which end-users interact. The application layer contains the code or logic. It interacts with the web and data layer to respond to client requests. The database layer manages the data. The three-tier architecture helps in creating a secure, scalable, and highly available infrastructure.



Parameters:
  EnvironmentName:
    Type: String
    Description: Enter Environment Name

  myVPCcidrblock:
    Type: String
    Default: 10.192.0.0/16  

  myPublicSubnet1cidr:
    Type: String
    Default: 10.192.1.0/24 

  myPublicSubnet2cidr:
    Type: String
    Default: 10.192.2.0/24 

  myPrivateSubnet1cidr:
    Type: String
    Default: 10.192.3.0/24 

  myPrivateSubnet2cidr:
    Type: String
    Default: 10.192.4.0/24       

  myDBSubnet1cidr:
    Type: String
    Default: 10.192.5.0/24  

  myDBSubnet2cidr:
    Type: String
    Default: 10.192.6.0/24  

  myAMIID:
    Type: String
    Default: ami-0f924dc71d44d23e2

  InstanceType:
    Type: String
    Default: t2.micro    

  KeyName:
    Type: String
    Default: dell-ohio-keypair    

Resources:
  myVPC:
    Type: AWS::EC2::VPC
    Properties:
     CidrBlock: !Ref myVPCcidrblock
     EnableDnsSupport: true
     EnableDnsHostnames: true
     Tags:
      - Key: Name
        Value: !Ref EnvironmentName

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Ref EnvironmentName

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref myVPC

      

  
  myPublicWebSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref myVPC
      CidrBlock: !Ref myPublicSubnet1cidr
      MapPublicIpOnLaunch: true
      AvailabilityZone:  !Select [ 0, !GetAZs '' ]
      Tags:
       - Key: Name
         Value:  !Sub ${EnvironmentName} Public Subnet (AZ1)

  myPublicWebSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref myVPC
      CidrBlock: !Ref myPublicSubnet2cidr
      MapPublicIpOnLaunch: true
      AvailabilityZone:  !Select [ 1, !GetAZs '' ]
      Tags:
       - Key: Name
         Value:  !Sub ${EnvironmentName} Public Subnet (AZ2)

  myPrivateAppSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref myVPC
      CidrBlock: !Ref myPrivateSubnet1cidr
      AvailabilityZone:  !Select [ 0, !GetAZs '' ]
      Tags:
       - Key: Name
         Value:  !Sub ${EnvironmentName} Private Subnet (AZ1)

  myPrivateAppSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref myVPC
      CidrBlock: !Ref myPrivateSubnet2cidr
      AvailabilityZone:  !Select [ 1, !GetAZs '' ]
      Tags:
       - Key: Name
         Value:  !Sub ${EnvironmentName} Private Subnet (AZ2)

  myPrivateDBSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref myVPC
      CidrBlock: !Ref myDBSubnet1cidr
      AvailabilityZone:  !Select [ 0, !GetAZs '' ]
      Tags:
       - Key: Name
         Value:  !Sub ${EnvironmentName} DB Subnet (AZ1)

  myPrivateDBSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref myVPC
      CidrBlock: !Ref myDBSubnet2cidr
      AvailabilityZone:  !Select [ 1, !GetAZs '' ]
      Tags:
       - Key: Name
         Value:  !Sub ${EnvironmentName} DB Subnet (AZ2)
       
       

  myPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref myVPC
      Tags:
       - Key: Name
         Value: !Sub ${EnvironmentName} Public Route Table       

  myPrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref myVPC
      Tags:
       - Key: Name
         Value: !Sub ${EnvironmentName} Private Route Table       

  myRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref myPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  myPublicWebSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: myPublicWebSubnet1
      RouteTableId:
        Ref: myPublicRouteTable         

  myPublicWebSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: myPublicWebSubnet2
      RouteTableId:
        Ref: myPublicRouteTable           

  myPrivateAppSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: myPrivateAppSubnet1
      RouteTableId:
        Ref: myPrivateRouteTable           

  myPrivateAppSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: myPrivateAppSubnet2
      RouteTableId:
        Ref: myPrivateRouteTable 

  myPrivateDBSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: myPrivateDBSubnet1
      RouteTableId:
        Ref: myPrivateRouteTable            

  myPrivateDBSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: myPrivateDBSubnet2
      RouteTableId:
        Ref: myPrivateRouteTable            

  NATGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NATGatewayEIP.AllocationId
      SubnetId: !Ref myPublicWebSubnet1
      Tags:
      - Key: Name
        Value: !Ref EnvironmentName
  NATGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc
  RouteNATGateway:
    DependsOn: NATGateway
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref myPrivateRouteTable
      DestinationCidrBlock: '0.0.0.0/0'
      NatGatewayId: !Ref NATGateway           


  BastionHostSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn: myVPC
    Properties:
      GroupDescription: Bastion sg to talk to web and app tier
      VpcId: !Ref myVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0    

  ApplicationLoadBalancerSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn: myVPC
    Properties:
      GroupDescription: http traffic to web tier
      VpcId: !Ref myVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0

  InternalLoadBalancerSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn: myVPC
    Properties:
      GroupDescription: Web tier traffic to app tier
      VpcId: !Ref myVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref WebtierSG
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22        
          SourceSecurityGroupId: !Ref WebtierSG
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0     

  WebtierSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn: myVPC
    Properties:
      GroupDescription: ApplicationLoadBalancer to web tier
      VpcId: !Ref myVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref ApplicationLoadBalancerSG
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref BastionHostSG 
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0   

  AppTierSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn: myVPC
    Properties:
      GroupDescription: Internal Load Balancer to AppTier
      VpcId: !Ref myVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref InternalLoadBalancerSG
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref BastionHostSG 
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0 

  DatabaseSG:
    Type: AWS::EC2::SecurityGroup
    DependsOn: myVPC
    Properties:
      GroupDescription: Apptier to database tier
      VpcId: !Ref myVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !Ref AppTierSG
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0        

  BastionHostEC2: 
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: !Ref myAMIID
      SecurityGroupIds: 
        - !GetAtt BastionHostSG.GroupId 
      InstanceType: !Ref InstanceType
      SubnetId: !Ref myPublicWebSubnet1
      KeyName: !Ref KeyName   
    

  
  myLaunchConfig:
    Type: AWS::AutoScaling::LaunchConfiguration
    Properties:
      ImageId: !Ref myAMIID
      InstanceType: !Ref InstanceType
      SecurityGroups: 
        - !Ref WebtierSG                            
      KeyName: !Ref KeyName 
      UserData:
           Fn::Base64: |
            #!/bin/bash
            yum update -y
            yum install -y httpd
            systemctl start httpd
            systemctl enable httpd
            echo 'Checkmate Global Technologies' > /var/www/html/index.html

  myASG:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:      
      LaunchConfigurationName: !Ref myLaunchConfig
      MaxSize: '1'
      MinSize: '1'
      DesiredCapacity: '1'
      VPCZoneIdentifier:   
        - !Ref myPublicWebSubnet1
        - !Ref myPublicWebSubnet2
      TargetGroupARNs: 
       - Ref: WebTierALBTargetGroup    

  WebTierLoadBalancer:
    Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
    Properties:
      Subnets: 
       - !Ref myPublicWebSubnet1
       - !Ref myPublicWebSubnet2
      SecurityGroups: 
        - !GetAtt ApplicationLoadBalancerSG.GroupId 
  WebTierListener:
    Type: "AWS::ElasticLoadBalancingV2::Listener"
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref WebTierALBTargetGroup
      LoadBalancerArn: !Ref WebTierLoadBalancer
      Port: "80"
      Protocol: HTTP
  WebTierALBTargetGroup:
    Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      Port: 80
      Protocol: HTTP
      UnhealthyThresholdCount: 5
      VpcId: !Ref myVPC

  AppTierASG:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      LaunchConfigurationName: !Ref AppTierLaunchConfig
      MaxSize: '1'
      MinSize: '1'
      DesiredCapacity: '1'
      VPCZoneIdentifier:   
        - !Ref myPrivateAppSubnet1
        - !Ref myPrivateAppSubnet2
      TargetGroupARNs: 
       - Ref: AppTierTargetGroup       
  AppTierLaunchConfig: 
    Type: AWS::AutoScaling::LaunchConfiguration
    Properties:
      ImageId: !Ref myAMIID
      SecurityGroups: 
        - !Ref AppTierSG
      InstanceType: 
        !Ref InstanceType
      KeyName:  !Ref KeyName
  AppTierLoadBalancer:
    Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
    Properties:
      Subnets: 
       - !Ref myPrivateAppSubnet1
       - !Ref myPrivateAppSubnet2
      SecurityGroups: 
       - !GetAtt InternalLoadBalancerSG.GroupId  
  AppTierListener:
    Type: "AWS::ElasticLoadBalancingV2::Listener"
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref AppTierTargetGroup
      LoadBalancerArn: !Ref AppTierLoadBalancer
      Port: "80"
      Protocol: HTTP
  AppTierTargetGroup:
    Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      Port: 80
      Protocol: HTTP
      UnhealthyThresholdCount: 5
      VpcId: !Ref myVPC   

  Database:
    Type: AWS::RDS::DBInstance
    Properties:
      VPCSecurityGroups: 
       - !Ref DatabaseSG
      AllocatedStorage: '20'
      PubliclyAccessible: 'true'
      DBInstanceClass: db.t2.micro
      Engine: MySQL
      MasterUsername: MyName
      MasterUserPassword: MyPassword
      DBSubnetGroupName: !Ref DatabaseSubnetGroup
      AvailabilityZone:  !Select [ 0, !GetAZs '' ]


  DatabaseSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: subnet group
      SubnetIds: 
       - !Ref myPrivateDBSubnet1
       - !Ref myPrivateDBSubnet2 

  • Next login to your AWS account and navigate to the CloudFormation console.
  • Click Create Stack.
  • Upload your template.

CloudFormation

 

  • Give Stack name and Environment name. Click Next and Create Stack.
  • The stack will be created in a few minutes.

CloudFormation

Author Detail

This blog is written by Checkmate Global Technologies cloud engineering team. Please contact with our technical consultants if you have anything related to cloud infrastructure, DevOps operation management and SaaS based product engineering to be discussed.

Leave a Reply

Your email address will not be published.

*