AWS CloudFormation - Separately Manage Network and Server Stacks by Cross Stacks

vinhle

Vinh Le

Posted on August 21, 2022

AWS CloudFormation - Separately Manage Network and Server Stacks by Cross Stacks

🗒️ Content

  1. AWS CloudFormation 101
  2. One key pair f
  3. Hands-on Lab: Separately Manage Network and Server Stacks by Cross Stacks

1. AWS CloudFormation 101

1.1. Infrastructure as Code (IaC)

Treating infrastructure in the same way as developers treat code is one of the most fundamental principles of DevOps.

Infrastructure as code (IaC) means provisioning, configuring and managing your infrastructure resources using code and templates.

1.2. AWS CloudFormation

AWS CloudFormation is a service speeding up cloud provisioning with infrastructure as code

AWS resources and infrastructure architecture are modeled and described in CloudFormation templates written in JSON or YAML (recommended) formatted text file. After that CloudFormation takes care of provisioning and configuring those resources for you.

The CloudFormation workflow for creating stacks as the below diagram
CloudFormation workflow
CloudFormation Workflow (source: https://aws.amazon.com/cloudformation/)

2. CloudFormation Templates Structure

  • Resource (mandatory): declare the AWS resources
  • Parameters (optional): input custom values to template each time creating/updating a stack, using with !Ref <parameter>
  • Mapping (optional): map a key to a specific value, using with !FindInMap [ <map_name>, <top_key>, <second_key> ]
  • Condition (optional): control the creation of resources or outputs based on a condition
  • Output (optional): return output values of stack
  • Cross-stack: separate templates and refer values from different stacks, using with Export from one stack and !ImportValue <export_name> from other stacks

3. Hands-on Lab: Separately Manage Network and Server Stacks by Cross Stacks

Assume that we are developing a simple web application with the following architecture

  • One VPC, one public subnet, one EC2 instance
  • One security group opening in port 80 (for HTTP from anywhere) Application Architecture

Separating our infrastructure into 2 templates may help us manage them easier.

3.1. LabNetworkStack

The content of lab_network_cfn.yml:

Description: This template manages network components

Parameters:
  ApplicationName:
    Description: An application name that is prefixed to resource names
    Type: String
    Default: lab
  VpcCidr:
    Description: The IP range (CIDR notation) for VPC in form x.x.x.x/16-28
    Type: String
    AllowedPattern: "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(1[6-9]|2[0-8]))$"
    Default: 10.192.0.0/16
  PublicSubnetCidr:
    Description: The IP range (CIDR notation) for public subnet in form x.x.x.x/16-28
    Type: String
    AllowedPattern: "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/(1[6-9]|2[0-8]))$"
    Default: 10.192.10.0/24

Resources:
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub '${ApplicationName}-vpc'
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Vpc
      CidrBlock: !Ref PublicSubnetCidr
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub '${ApplicationName}-public-subnet'
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub '${ApplicationName}-igw'
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref Vpc
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - Key: Name
          Value: !Sub '${ApplicationName}-rtb'
  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet

Outputs:
  VpcId:
    Description: The VPC ID of lab application
    Value: !Ref Vpc
    Export:
      Name: !Sub '${AWS::StackName}-VpcId'
  SubnetId:
    Description: The Subnet ID of lab application
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub '${AWS::StackName}-PublicSubnetId'
Enter fullscreen mode Exit fullscreen mode

The template can be deployed with AWS CLI

aws s3 cp lab_network_cfn.yml s3://<your_bucket>
aws cloudformation create-stack --stack-name LabNetworkStack --template-url https://<your_bucket>.s3.<your_region>.amazonaws.com/lab_network_cfn.yml
Enter fullscreen mode Exit fullscreen mode

3.2. LabServerStack

The content of lab_server_cfn.yml:

Description: This template manages servers components

Parameters:
  ApplicationName:
    Description: An application name that is prefixed to resource names
    Type: String
    Default: lab
  Landscape:
    Type: String
    Default: develop
    AllowedValues:
    - develop
    - production
  NetworkStackName:
    Description: The name of Network CloudFormation stack
    Type: String
    Default: LabNetworkStack

Mappings:
  RegionMap:
    ap-southeast-1:
      AMI: ami-02ee763250491e04a
    ap-southeast-2:
      AMI: ami-0e040c48614ad1327

Conditions:
  IsProduction: !Equals [ !Ref Landscape, production]

Resources:
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub 'Security group for ${ApplicationName} instances'
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      VpcId: !ImportValue
        'Fn::Sub': '${NetworkStackName}-VpcId'
      Tags:
        - Key: Name
          Value: !Sub '${ApplicationName}-srg'
  Ec2Instance: 
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: !FindInMap [ RegionMap, !Ref 'AWS::Region', AMI ]
      InstanceType: !If [ IsProduction, t2.small, t2.micro ] 
      KeyName: your_key_name
      SubnetId: !ImportValue
        'Fn::Sub': '${NetworkStackName}-PublicSubnetId'
      SecurityGroupIds:
      - !Ref SecurityGroup
      BlockDeviceMappings: 
      - DeviceName: "/dev/sda1"
        Ebs:
          VolumeSize: 12
          VolumeType: gp2
          Encrypted: true
      UserData:
        "Fn::Base64":
          !Sub |
            #!/bin/bash
            apt update
            apt install apache2 -y
      Tags:
        - Key: Name
          Value: !Sub '${ApplicationName}-ec2'

Outputs:
  InstanceIp:
    Description: The IP address of instance
    Value: !GetAtt Ec2Instance.PublicIp
Enter fullscreen mode Exit fullscreen mode

The template can be deployed with AWS CLI

aws s3 cp lab_server_cfn.yml s3://<your_bucket>
aws cloudformation create-stack --stack-name LabServerStack --template-url https://<your_bucket>.s3.<your_region>.amazonaws.com/lab_server_cfn.yml
Enter fullscreen mode Exit fullscreen mode

Confirmation

  • Confirm the status of stacks are all CREATE_COMPLETE
  • Confirm the default Ubuntu Apache web page http://your_server_ip EC2 Apache default page

3.3. Clean resources

The stacks can be deleted by consoles or AWS CLI in the following order

aws cloudformation delete-stack --stack-name LabServerStack
aws cloudformation delete-stack --stack-name LabNetworkStack
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
vinhle
Vinh Le

Posted on August 21, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related