CloudFormation Examples

Main Menu

Overview

These examples build on each other, but are mostly designed to demonstrate the minimum requirements to make each resource and function work.

Syntax:

  • Text
    • Enter your own text here. If written as a single ‘word’, you must use a word and not a string of words.
  • # comment
    • A comment that let’s you know what the next line or section is about.  These can be safely deleted and will not affect the code.

Security Groups

 

Resources:
   MySecurityGroupId:
      Type: AWS::EC2::SecurityGroup
      Properties:
         GroupName: My Security Group Name
         GroupDescription: My Security Group Description
         # Set rules for incoming traffic
         SecurityGroupIngress:
         # Enable PING from anywhere to any port
         -  IpProtocol: icmp
            FromPort: -1
            ToPort: -1
            CidrIp: 0.0.0.0/0
         # Enable SSH
         -  IpProtocol: tcp
            FromPort: 22
            ToPort: 22
            CidrIp: 0.0.0.0/0
         # Enable Web traffic
         -  IpProtocol: tcp
            FromPort: 80
            ToPort: 80
            CidrIp: 0.0.0.0/0
         # These are optional, but helpful!
         Tags:
         -  Key: Name
            Value: My CF Security Group

EC2 Instances

EC2 Bare Minimum

Download: ec2-minimum.yaml

Resources:
   MyEc2Instance:
      Type: AWS::EC2::Instance
      Properties:
         ImageId: ami-710e2414
         InstanceType: t2.micro
         # Optional, but required if you want to actually access it.
         KeyName: MyKeyPair

Security Group and Key Name Parameter

This example will be used as the base script for the rest of the EC2 Section

Download Source:  Ec2-SecuityGroup-Parameters

This example includes:

  • A Security Group (Same as above)
  • A Parameter to allow you to enter your Key-Pair name.
# This section allows you to select an existing Key-Pair from the region you are creating the stack in.
Parameters:
   MyKeyPair:
      Description: Select the Key Pair you wish to use for these instances.
      Type: AWS::EC2::KeyPair::KeyName
      # Optional, but handy
      Default: MyDefaultKeyPair
Resources:
   # Define the Security Group
   MySecurityGroupId:
      Type: AWS::EC2::SecurityGroup
      Properties:
         GroupName: My Security Group Name
         GroupDescription: My Security Group Description
         SecurityGroupIngress:
         -  IpProtocol: icmp
            FromPort: -1
            ToPort: -1
            CidrIp: 0.0.0.0/0
         -  IpProtocol: tcp
            FromPort: 22
            ToPort: 22
            CidrIp: 0.0.0.0/0
         -  IpProtocol: tcp
            FromPort: 80
            ToPort: 80
            CidrIp: 0.0.0.0/0
         Tags:
         -  Key: Name
            Value: My CF Security Group

   # Define the EC2 Instance
   MyEc2Instance:
      Type: AWS::EC2::Instance
      Properties:
         ImageId: ami-710e2414
         InstanceType: t2.micro
         # Optional, but required if you want to actually access it.
         KeyName: !Ref MyKeyPair
         # Use the Security Group created above
         SecurityGroups:
            -  !Ref MySecurityGroupId
         Tags:
            -  Key: Name
               Value: My EC2 Instance

Using UserData to install Apache and PHP

Download Source: Ec2-SecuityGroup-Parameters-UserData

Using the script above, add the following lines within the ‘Properties’ section.
* Hint: You can safely append this data to the end of the previous file!

         UserData:
            Fn::Base64: |
               #!/bin/bash
               # Update Yum
               yum update
               # Install Apache (-y installs without requiring confirmation)
               yum install -y httpd
               # Start Apache
               service httpd start
               # Set Apache to start at reboot
               chkconfig httpd on
               # Install PHP
               yum install -y php

AWS::CloudFormation::Init

Example 1: Using config and services

Download Source: CloudFormation-Init-1

The previous example can can also be accomplished using special AWS::CloudFormation::Init scripts. To use these, replace the previously added UserData section with the following:

         # These lines initialize the use of ::Init.  Init will not function without them.
         UserData:
            Fn::Base64: !Sub |
               #!/bin/bash -xe
               /opt/aws/bin/cfn-init -s ${AWS::StackId} -r MyEc2Instance --region ${AWS::Region} || error_exit 'Failed to run cfn-init'

      # Add the Metadata commands to install Apache and PHP
      Metadata:
         AWS::CloudFormation::Init:
            config:
               # Install Apache and PHP at their current versions
               packages:
                  yum:
                     httpd: []
                     php: []
               # Start Apache and configure to restart at reboot
               services:
                  sysvinit:
                     httpd:
                        enabled: true
                        ensureRunning: true

Example 2: Using files

Download Source: CloudFormation-Init-2
We can use ‘files:’ to create files. In this example, we’ll create a basic phpinfo page to show the website is both working and that PHP is functioning. The following example can be directly appended to the end of the previous example.

               files:
                  "/var/www/html/index.php":
                     content: !Sub |
                        <h1>Hello</h1>
                        I'm glad you made it!<br/>
                        You just created a Cloud Formation stack called: ${AWS::StackName}!<br/>
                        <?php phpinfo(); ?>
                     mode: '000400'
                     owner: apache
                     group: apache

Browse to the IP address for the instance to view the results.
Example: http:IP.ADD.RE.SS/index.php

Example 3: Install WordPress and Configure

Download Source: CloudFormation-Init-3

There are several steps required to get WordPress running, so before we dive in, let’s outline those steps so it’s easier to follow along.

  • Download and Install the WordPress files using ‘sources’
  • Install the database software and supporting modules using ‘packages’
  • Start the database and configure it to start on reboot using ‘services’
  • Update the database with the information required by WordPress
    • These will be manually entered in the Parameters
    • We’ll use ‘files’ and ‘commands’ to apply them
    • Since the config files need to be executed in a specific order (commands after services), we need to create ‘confSets’

Download and Install the WordPress files using ‘sources’

We’ll continue working from the last script.  To download and extract WordPress, append the following code to the bottom of our previous script:

               sources:
                  /var/www/html: https://wordpress.org/latest.tar.gz

Install the database software and supporting modules using ‘packages’

Update the packages section with the following programs:

  • mariadb
  • php-mysql

Your code should look like this:

               packages:
                  yum:
                     httpd: []
                     php: []
                     mariadb-server: []
                     php-mysql: []

Start the database and configure it to start on reboot using ‘services’

Add the following lines in the services section
Your ‘services’ code should look like this:

               services:
                  sysvinit:
                     # needs to be in this order
                     # I do not know why
                     mariadb:
                        enabled: true
                        ensureRunning: true
                     httpd: 
                        enabled: true 
                        ensureRunning: true

Update the database with the information required by WordPress

Update Parameters to get the user and database information

Add the following lines to the Parameters section:

   DBName:
      AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'
      ConstraintDescription: must begin with a letter and contain only alphanumeric characters.
      Default: wordpressdb
      Description: The WordPress database name
      MinLength: 4
      MaxLength: 64
      Type: String
   DBPassword:
      AllowedPattern: '[a-zA-Z0-9]*'
      ConstraintDescription: must contain only alphanumeric characters.
      Description: The WordPress database admin account password
      MaxLength: 41
      MinLength: 8
      NoEcho: true
      Type: String
   DBRootPassword:
      AllowedPattern: '[a-zA-Z0-9]*'
      ConstraintDescription: must contain only alphanumeric characters.
      Description: MySQL root password
      MaxLength: 41
      MinLength: 8
      NoEcho: true
      Type: String
   DBUser:
      AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'
      ConstraintDescription: must begin with a letter and contain only alphanumeric characters.
      Description: The WordPress database admin account username
      MaxLength: 16
      MinLength: 1
      NoEcho: true
      Type: String
Commands

Run the commands to:

  • Set the root database password
  • Create the empty database using the file we’ll create in the next step.

Enter the following code at the bottom of the existing script.

               commands:
                  01_set_mysql_root_password:
                     command: !Sub |
                        mysqladmin -u root password '${DBRootPassword}'
                  02_create_database:
                     command: !Sub |  
                        mysql -u root --password='${DBRootPassword}' < /tmp/setup.mysql
Create The File

Create a file that will setup and create our database.  Add this to the files section.

                  "/tmp/setup.mysql":
                     content: !Sub |
                        CREATE DATABASE ${DBName};
                        CREATE USER '${DBUser}'@'localhost' IDENTIFIED BY '${DBPassword}';
                        GRANT ALL ON ${DBName}.* TO '${DBUser}'@'localhost'; 
                        FLUSH PRIVILEGES;
                     group: root
                     mode: '000400'
                     owner: root
Create the configSets
IMPORTANT!
The cfn-init order of execution is pre-defined as:
packages -> groups -> users-> sources -> files -> commands -> servicesThis causes us trouble because we need to have MariaDB running in order to configure it with our commands. To move ‘commands’ after the ‘services’ section, we need to create a config set.

This is a multi-part process.

  • Define the ConfigSet to use
  • Define the installation order.

Edit the cfn-init command to specify the ‘configSet’ to use.

/opt/aws/bin/cfn-init -c RunThisConfiguration -s ${AWS::StackId} ...

Now, create a config set with the execution order (These will make more sense in the next step)

      Metadata:
         AWS::CloudFormation::Init:
            configSets:
               RunThisConfiguration:
                  -  First
                  -  Second
            First:
               packages:
                  yum:
                     httpd: []
                     ...
               services:
                  sysvinit:
                     ...
               files:
                  "/var/www/html/index.php":
                     ...
               sources:
                  /var/www/html: https://wordpress.org/latest.tar.gz
            Second:
               commands:
                  ...

 

LEAVE A COMMENT