Initializing Amazon EC2 Instances with AWS CloudFormation Init

Updated: 2023-09-01
4 min read

Lab

Establishing Desired EC2 Instance State with AWS CloudFormation Init

1. In the AWS Console search bar, search for cloudformation and click the CloudFormation result under Services:

alt

2. Click the Create stack dropdown menu and select With new resources:

alt

3. In the Create stack form, in the Specify template section, ensure Amazon S3 URLis selected for the Template source.

4. Paste in the following URL in the Amazon S3 URL field:

AWSTemplateFormatVersion: '2010-09-09'
Description: Provision a Single Amazon EC2 Instance with CFN Helper Scripts

Parameters:
  AmiID:
    Description: The ID of the AMI.
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Resources:
  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref AmiID
      InstanceType: t3.micro
      SecurityGroupIds:
        - !Ref WebServerSecurityGroup
      UserData:
        # Update aws-cfn-bootstrap
        # Run cfn-init to initialize WebServer content
        # Return cfn-init run result to CloudFormation upon completion
        Fn::Base64:
          !Sub |
            #!/bin/bash -xe
            yum update -y aws-cfn-bootstrap
            /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServer --region ${AWS::Region}
            /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServer --region ${AWS::Region}
    CreationPolicy:
      ResourceSignal:
        Count: 1
        Timeout: PT5M
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
          files:
            "/var/www/html/index.html":
              content: |
                  <center>
                    <h1>Cloud Academy EC2 Instance</h1>
                    <h3>This content has been initialized with <a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-helper-scripts-reference.html" target="_blank">AWS CloudFormation Helper Scripts</a></h3>
                  </center>                  
              mode: '000644'
          services:
            sysvinit:
              httpd:
                enabled: 'true'
                ensureRunning: 'true'

  WebServerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SSH and HTTP
      SecurityGroupIngress:
      - CidrIp: 0.0.0.0/0
        FromPort: 22
        IpProtocol: tcp
        ToPort: 22
      - CidrIp: 0.0.0.0/0
        FromPort: 80
        IpProtocol: tcp
        ToPort: 80

Outputs:
  WebServerPublicDNS:
    Description: Public DNS of EC2 instance
    Value: !GetAtt WebServer.PublicDnsName

alt

The CloudFormation stack template is stored in a public S3 bucket. The EC2 instance resource definition is shown below:

alt

The WebServer EC2 instance is defined above. It is a size t3.micro instance that references a WebServerSecurityGroup resource for its security group and the AmiID parameter for its image ID. Both of these referenced configurations are defined elsewhere in the template.

The UserData script defined next performs the following tasks once the EC2 instance is created:

  • Updates the aws-cfn-bootstrappackage to retrieve the latest version of the helper scripts
  • Runs the cfn-init helper script to execute the WebServer instance Metadata scripts
  • Runs the cfn-signalhelper script to notify CloudFormation after all the service(s) (Apache in this case) is installed and configured on the EC2 instance

Note: The cfn-init helper script is not executed automatically. You must run the cfn-init script within the EC2 instance UserData in order to execute your metadata scripts.

The cfn-signal helper script works hand-in-hand with the CreationPolicy configuration. The ResourceSignal property has a Count of 1 and a Timeout of PT5M. This instructs CloudFormation to wait for up to 5 minutes to receive 1 resource signal from the EC2 instance.

The cfn-signal helper script call in the UserData uses $? to retrieve the return code of the previous script. If the cfn-init script is successful and the EC2 instance is configured properly, cfn-signal returns a success to CloudFormation which then transitions the EC2 instance to the CREATE_COMPLETEstatus. If the cfn-init script is unsuccessful or the timeout of 5 minutes expires before receiving a signal, then the EC2 instance will be transitioned to a CREATE_FAILEDstatus and the stack deployment will fail.

The EC2 instance Metadata configuration is the same as the previous lab step. It defines a AWS::CloudFormation::Init script to install the httpd package using yum, generate an index.html file within /var/www/html/ and start the httpd service to serve the content from the EC2 instance.

5. Click Nextto continue:

alt

6. Enter web-server-stack for the Stack name and click Next:

alt

7. You will not be configuring additional stack options. Scroll to the bottom of the page and click Next.

8. On the review page, scroll to the bottom and click Create stackto deploy your stack:

alt

Your stack will begin deploying and you will be brought to the Events page of your web-server-stack:

alt

The stack can take up to 3 minutes to deploy successfully.

9. If the Events section does not automatically refresh after 3 minutes, click the refresh icon:

alt

alt

The WebServer instance remains in a CREATE_IN_PROGRESS status until CloudFormation receives a SUCCESS signal from the instance. In the screenshot above, the UniqueId of i-0fd18c8deb52983d5 belongs to the WebServer instance.

After the success signal is received, the WebServer instance is transitioned into the CREATE_COMPLETE status.

Without the CloudFormation signal helper script, CloudFormation would have transitioned the EC2 instance to a completed status when the resource was created instead of waiting until the Apache service has been installed and running on the instance.

10. Click the Outputs tab on the web-server-stack page:

alt

11. Right-click and open the WebServerPublicDNS URL in a new browser tab:

alt

The HTMLpage generated in the cfn-init script is now being served from the Apache server running within your WebServer EC2 instance:

alt