Main Menu
- The Ultimate Cloud Formation Guide
- Overview
- Security Groups
- EC2 Instances
- EC2 Bare Minimum
- Security Group and Key Name Parameter
- UserData to install Apache and PHP
- AWS::CloudFormation::Init
- config: packages to install Apache
- config: files to create a basic web page
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
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:
...