Related
I'm trying to implement configuration management that meets the following criteria for an assighment:
https://s3.amazonaws.com/seis615/AnsiblePress.json
Take a quick look at the template in a text editor. Notice how the UserData property for the mgmt1 instance is configured. When CloudFormation launches this stack, it will automatically install and configure Ansible software on the management server. It’s very common to use a small amount of scripting code to bootstrap configuration management software onto a new system. Once Ansible is installed it can be used to install and configure other servers in the environment.
The CloudFormation template is missing a couple resources that you will need to add:
An application load balancer with a logical name of webserverlb which distributes HTTP (port 80) requests to the web1 and web2 instances. The health check endpoint for the load balancer should be the root (/) directory.
A db.t2.micro RDS database instance (not a cluster) running a MariaDB 10.2.21 database called wordpress located in a private VPC subnet. Use the logical name wordpressdb for the CloudFormation RDS resource. RDS and EC2 instances actually pre-date the arrival of VPCs in AWS so confusingly there are two different ways to configure these resources. You need to make sure this database instance is designed to run inside a VPC with the proper database subnet group and security group resources defined.
A security group called WebserverLbSecurityGroup which allows incoming http access from the Internet.
A security group called WordpressDbSecurityGroup which allows incoming access on the standard MySQL port from the WebServerSecurityGroup
An input parameter called DBName which will define the database name to create (default to wordpress)
An input parameter called DBUser which will be used for the database server username.
An input parameter called DBPassword which will be used for the database server password.
A stack output called wordpressDbEndpoint which shows the MariaDB instance endpoint address.
A stack output called wordpressLbEndpoint which shows the application load balancer URL.
The JSON I've configured (below) gives me the following template format error and I don't know why:
Template format error: Unresolved resource dependencies [wordpressVPC] in the Resources block of the template
{"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SSMAccessRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Principal": {
"Service": [ "ec2.amazonaws.com" ]
},
"Action": [ "sts:AssumeRole" ]
} ]
},
"Path": "/"
}
},
"SSMRolePolicies": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "ssmProperties",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:DescribeParameters",
"ssm:PutParameter",
"ssm:GetParameters",
"ssm:DeleteParameter"
],
"Resource": {
"Fn::Join" : [
"",
[
"arn:aws:ssm:",
{ "Ref" : "AWS::Region" },
":",
{ "Ref" : "AWS::AccountId"},
{
"Fn::Join" : [
"",
[ ":parameter/", { "Ref": "AWS::StackName" }, ".*" ]
]
}
]
]
}
}
]
},
"Roles": [ { "Ref": "SSMAccessRole" } ]
}
},
"SSMInstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [ { "Ref": "SSMAccessRole" } ]
}
},
"web1pem" : {
"Type" : "AWS::SSM::Parameter",
"Properties" : {
"Name" : {
"Fn::Join" : [
"",
[ { "Ref": "AWS::StackName" }, ".web1pem" ]
]
},
"Type" : "String",
"Value" : "0",
"Description": "web1 instance private key."
}
},
"web2pem" : {
"Type" : "AWS::SSM::Parameter",
"Properties" : {
"Name" : {
"Fn::Join" : [
"",
[ { "Ref": "AWS::StackName" }, ".web2pem" ]
]
},
"Type" : "String",
"Value" : "0",
"Description": "web2 instance private key."
}
},
"wordpressVpc": {
"Type": "AWS::EC2::VPC",
"Properties": {
"EnableDnsSupport": "true",
"EnableDnsHostnames": "true",
"CidrBlock": "10.0.0.0/16",
"Tags": [
{
"Key": "Environment",
"Value": "Test"
}
]
}
},
"publicSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "wordpressVpc"
},
"CidrBlock": "10.0.0.0/24",
"AvailabilityZone" : {
"Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]
}
}
},
"publicSubnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "wordpressVpc"
},
"CidrBlock": "10.0.1.0/24",
"AvailabilityZone" : {
"Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]
}
}
},
"privateSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "wordpressVpc"
},
"CidrBlock": "10.0.2.0/24",
"AvailabilityZone" : {
"Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]
}
}
},
"privateSubnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "wordpressVpc"
},
"CidrBlock": "10.0.3.0/24",
"AvailabilityZone" : {
"Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]
}
}
},
"web1": {
"Type": "AWS::EC2::Instance",
"DependsOn": [
"web1pem"
],
"Properties": {
"InstanceType": "t2.micro",
"ImageId": {"Ref": "AMI"},
"IamInstanceProfile": {
"Ref": "SSMInstanceProfile"
},
"KeyName": {
"Ref": "KeyName"
},
"NetworkInterfaces": [
{
"GroupSet": [
{
"Ref": "WebServerSecurityGroup"
}
],
"AssociatePublicIpAddress": "true",
"DeviceIndex": "0",
"DeleteOnTermination": "true",
"SubnetId": {
"Ref": "publicSubnet1"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": "web1"
}
],
"UserData" : {
"Fn::Base64" : {
"Fn::Join" : [
"", [
"#!/bin/bash -xe\n",
"ssh-keygen -f /home/ec2-user/.ssh/web1-key.pem -q -N \"\"\n",
"chown ec2-user:ec2-user /home/ec2-user/.ssh/web1-key.pem\n",
"chown ec2-user:ec2-user /home/ec2-user/.ssh/web1-key.pem.pub\n",
"PEMFILE=`cat /home/ec2-user/.ssh/web1-key.pem`\n",
"aws ssm put-parameter --name ", { "Ref" : "web1pem" }, " --type String --value \"${PEMFILE}\" --overwrite --region ", { "Ref" : "AWS::Region" },"\n",
"cat /home/ec2-user/.ssh/web1-key.pem.pub >> /home/ec2-user/.ssh/authorized_keys\n",
"# Signal the status from cfn-init\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource web1 ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
}
},
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT5M"
}
}
},
"web2": {
"Type": "AWS::EC2::Instance",
"DependsOn": [
"web1pem"
],
"Properties": {
"InstanceType": "t2.micro",
"ImageId": {"Ref": "AMI"},
"IamInstanceProfile": {
"Ref": "SSMInstanceProfile"
},
"KeyName": {
"Ref": "KeyName"
},
"NetworkInterfaces": [
{
"GroupSet": [
{
"Ref": "WebServerSecurityGroup"
}
],
"AssociatePublicIpAddress": "true",
"DeviceIndex": "0",
"DeleteOnTermination": "true",
"SubnetId": {
"Ref": "publicSubnet2"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": "web2"
}
],
"UserData" : {
"Fn::Base64" : {
"Fn::Join" : [
"", [
"#!/bin/bash -xe\n",
"ssh-keygen -f /home/ec2-user/.ssh/web2-key.pem -q -N \"\"\n",
"chown ec2-user:ec2-user /home/ec2-user/.ssh/web2-key.pem\n",
"chown ec2-user:ec2-user /home/ec2-user/.ssh/web2-key.pem.pub\n",
"PEMFILE=`cat /home/ec2-user/.ssh/web2-key.pem`\n",
"aws ssm put-parameter --name ", { "Ref" : "web2pem" }, " --type String --value \"${PEMFILE}\" --overwrite --region ", { "Ref" : "AWS::Region" },"\n",
"cat /home/ec2-user/.ssh/web2-key.pem.pub >> /home/ec2-user/.ssh/authorized_keys\n",
"# Signal the status from cfn-init\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource web2 ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
}
},
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT5M"
}
}
},
"WebServerSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"VpcId": {
"Ref": "wordpressVpc"
},
"GroupDescription": "Allow access from HTTP and SSH traffic",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {"Ref": "YourIp"}
}
]
}
},
"WebServerSGIngressTCP22": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Metadata": {
"Comment": "SSH ingress security rule"
},
"Properties" : {
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"SourceSecurityGroupId": { "Ref": "WebServerSecurityGroup" },
"GroupId": { "Fn::GetAtt": ["WebServerSecurityGroup", "GroupId"]}
}
},
"InternetGateway": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {}
},
"AttachGateway": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"InternetGatewayId": {
"Ref": "InternetGateway"
},
"VpcId": {
"Ref": "wordpressVpc"
}
}
},
"PublicRouteTable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "wordpressVpc"
}
}
},
"PublicRoute": {
"Type": "AWS::EC2::Route",
"Properties": {
"DestinationCidrBlock": "0.0.0.0/0",
"RouteTableId": {
"Ref": "PublicRouteTable"
},
"GatewayId": {
"Ref": "InternetGateway"
}
},
"DependsOn": [
"InternetGateway", "AttachGateway"
]
},
"Public1RouteTableAssociation": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "PublicRouteTable"
},
"SubnetId": {
"Ref": "publicSubnet1"
}
}
},
"Public2RouteTableAssociation": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "PublicRouteTable"
},
"SubnetId": {
"Ref": "publicSubnet2"
}
}
},
"webserverlb": {
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"Properties": {
"IpAddressType": "ipv4",
"SecurityGroups": [
{
"Ref": "webserverlbSecurityGroup"
}
],
"Subnets": [
{
"Ref": "publicSubnet1"
},
{
"Ref": "publicSubnet2"
}
],
"Tags": [
{
"Key": "Name",
"Value": "webserverlb"
}
]
},
"DependsOn": [
"webserversSecurityGroup"
]
},
"webserverlbSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"VpcId": {
"Ref": "wordpressVPC"
},
"GroupDescription": "Allows incoming requests from port 80 via HTTP.",
"SecurityGroupIngress": [
{
"IpProtocol": "TCP",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0",
"Description": "Allows 80 from Internet"
}
]
}
},
"wordpressdb": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"VpcId": {
"Ref": "wordpressVPC"
},
"AvailabilityZone": "us-east-1a",
"DBInstanceClass": "db.t2.micro",
"DBName": "wordpress",
"Engine": "mariadb",
"EngineVersion": "10.2.21",
"MultiAZ": 1,
"Tags": [
{
"Key": "Name",
"Value": "wordpressdb"
}
]
},
"DependsOn": [
"wordpressdbSecurityGroup"
]
},
"wordpressdbSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties": {
"VpcId": {
"Ref": "wordpressVPC"
},
"GroupDescription": "Enable access to the db via port 3306.",
"Tags": [
{
"Key": "Name",
"Value": "wordpressdbSecurityGroup"
}
],
"SecurityGroupIngress": [
{
"IpProtocol": "TCP",
"FromPort": "3306",
"ToPort": "3306",
"Description": "Enable HTTP access."
}
]
}
}
},
"Parameters": {
"KeyName": {
"Description": "Name of your EC2 KeyPair to enable SSH access to the instances.",
"Type": "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription": "must be the name of an existing EC2 KeyPair."
},
"YourIp": {
"Description": "The current CIDR IP address of your workstation (x.x.x.x/32). http://checkip.amazonaws.com/",
"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-9]|3[0-2]))$",
"ConstraintDescription": "Must be a valid IP CIDR range of the form x.x.x.x/x."
},
"AMI": {
"Description": "The EC2 instance AMI",
"Type": "String",
"Default": "ami-00dc79254d0461090"
},
"DBName": {
"Description": "Name of the database",
"Type" : "String",
"Default": "wordpress"
},
"DBUser": {
"Default": "admin",
"NoEcho": "false",
"Description" : "The WordPress database admin account user name",
"Type": "String",
"MinLength": "1",
"MaxLength": "16",
"AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*"
},
"DBPassword": {
"NoEcho": "true",
"Description" : "The password of the database.",
"Type": "String",
"MinLength": "1",
"MaxLength": "16",
"AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*"
}
},
"Outputs": {
"web1PublicIp": {
"Value": {"Fn::GetAtt": ["web1","PublicIp"]},
"Description": "web1 public IP"
},
"we2PublicIp": {
"Value": {"Fn::GetAtt": ["web2","PublicIp"]},
"Description": "web2 public IP"
},
"mgmt1PublicIp": {
"Value": {"Fn::GetAtt": ["mgmt1","PublicIp"]},
"Description": "mgmt1 public IP"
}
}
}
Because CloudFormation is case sensitive. Your vpc resource is called wordpressVpc, but in some places you are using wordpressVPC.
Recommend trying the CloudFormation Linter in VSCode to see some of these errors inline while authoring templates along with autocompletion and documentation links:
E3005 DependsOn should reference other resources at Resources/webserverlb/DependsOn/0
E1012 Ref wordpressVPC not found as a resource or parameter
E1012 Ref wordpressVPC not found as a resource or parameter
E3002 Invalid Property Resources/wordpressdb/Properties/VpcId
E3003 Property DBSecurityGroupIngress missing at Resources/wordpressdbSecurityGroup/Properties
E1012 Ref wordpressVPC not found as a resource or parameter
E3002 Invalid Property Resources/wordpressdbSecurityGroup/Properties/VpcId
E3002 Invalid Property Resources/wordpressdbSecurityGroup/Properties/SecurityGroupIngress
E1010 Invalid GetAtt mgmt1.PublicIp for resource mgmt1PublicIp
I am trying to create an Amazon EC2 instance then create an Amazon EBS volume and attach it to the instance. I am using a CloudFormation template for this. Unfortunately the stack creation is failing when attaching newly created volume to the instance with the following error:
Instance 'i-01eebc8c9c492c035' is not 'running'. (Service: AmazonEC2; Status Code: 400; Error Code: IncorrectState; Request ID: 635572fd-dd25-4a02-9306-6e22f88e13dc)
What I do not understand is, when the instance creation is complete, that means the instance is up and running. How can this error be possible?
I am using the following CloudFormation template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "single instance template",
"Parameters": {
"InstanceType": {
"Type": "String",
"Default": "t2.micro"
},
"InstanceName": {
"Type": "String",
"Default": "test_CFT"
},
"RootVolumeSize": {
"Type": "String",
"Default": "50"
},
"Volume1Size": {
"Type": "String",
"Default": "8"
},
"Region": {
"Type": "String",
"Default": "us-east-2"
},
"AMIID": {
"Type": "String",
"Default": "ami-8c122be9"
},
"SubnetIds": {
"Type": "CommaDelimitedList",
"Default": "subnet-595e7422"
},
"SecurityGroupIDs": {
"Type": "CommaDelimitedList",
"Default": "sg-082faee8335351537"
}
},
"Resources": {
"Instance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": {
"Ref": "AMIID"
},
"InstanceType": {
"Ref": "InstanceType"
},
"KeyName": "thehope",
"NetworkInterfaces": [
{
"AssociatePublicIpAddress": "false",
"DeviceIndex": "0",
"SubnetId": {
"Fn::Select": [
0,
{
"Ref": "SubnetIds"
}
]
},
"GroupSet": {
"Ref": "SecurityGroupIDs"
}
}
],
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"VolumeSize": {
"Ref": "RootVolumeSize"
},
"DeleteOnTermination": "true",
"VolumeType": "gp2"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": {
"Ref": "InstanceName"
}
}
]
}
},
"Volume1": {
"DeletionPolicy": "Delete",
"Properties": {
"AvailabilityZone": {
"Fn::GetAtt": [
"Instance",
"AvailabilityZone"
]
},
"Encrypted": "False",
"Size": {
"Ref": "Volume1Size"
},
"Tags": [
{
"Key": "Name",
"Value": "New_volume"
}
],
"VolumeType": "gp2"
},
"Type": "AWS::EC2::Volume"
},
"VolumeAttachment1": {
"Properties": {
"Device": "/dev/xvdb",
"InstanceId": {
"Ref": "Instance"
},
"VolumeId": {
"Ref": "Volume1"
}
},
"Type": "AWS::EC2::VolumeAttachment"
}
},
"Outputs": {
"InstanceId": {
"Description": "InstanceId of the instance",
"Value": {
"Ref": "Instance"
}
},
"AZ": {
"Description": "Availability Zone of the instance",
"Value": {
"Fn::GetAtt": [
"Instance",
"AvailabilityZone"
]
}
},
"PrivateIP": {
"Description": "PrivateIP of the instance",
"Value": {
"Fn::GetAtt": [
"Instance",
"PrivateIp"
]
}
}
}
}
What am I doing wrong?
Since you are creating new volumes, it would be easier to simply specify the volumes as part of the instance rather than specifying an Amazon EBS volume and then attaching it to the instance.
From Amazon EC2 Block Device Mapping Property - AWS CloudFormation:
This example sets the EBS-backed root device (/dev/sda1) size to 50 GiB, and another EBS-backed device mapped to /dev/sdm that is 100 GiB in size.
"BlockDeviceMappings" : [
{
"DeviceName" : "/dev/sda1",
"Ebs" : { "VolumeSize" : "50" }
},
{
"DeviceName" : "/dev/sdm",
"Ebs" : { "VolumeSize" : "100" }
}
]
That was quite fascinating, seeing how the instance stops!
When using Amazon Linux 2, it can be fixed by changing:
"DeviceName": "/dev/sda1",
into:
"DeviceName": "/dev/xvda",
Or, it can be fixed by using Amazon Linux (version 1) with /dev/sda1.
However, this doesn't fix your VolumeAttachment issue.
I was facing the same issue until I changed the AMI in my template. Initially, I was testing with Linux AMI in the N.Virginia region where it failed but when I used a CENTOS AMI that I had subscribed to it works.
I am trying to setup a cloud formation template to deploy ubuntu 16.04. The template deploys fine and I can SSH to the server., but the extra packages I defined, like apache and php modules will not install. I can't seem to figure out why that is? I looked at several code sniplets online, but can't seem to get it to work properly. Can some one tell me what I am doing wrong here?
The Code:
{
"Description" : "Staging single instance",
"Outputs": {
"InstanceID": {
"Description": "The WWW instance id",
"Value": { "Ref": "StageInstance" }
}
},
"Parameters": {
"AMI": {
"Description": "The Amazon Ubuntu AMI",
"Type": "String",
"Default": "ami-996372fd"
},
"EBSVolumeSize": {
"Description": "The size of the EBS volume for the transcoder",
"Type": "String",
"Default": "20"
},
"InstanceType": {
"AllowedValues": [
"t2.micro",
"t2.small",
"t2.medium",
"t2.large",
"c4.large",
"c4.xlarge",
"c4.2xlarge",
"c4.4xlarge",
"c4.8xlarge"
],
"ConstraintDescription": "must be a valid EC2 instance type",
"Default": "t2.micro",
"Description": "EC2 instance type",
"Type": "String"
},
"KeyName": {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to NAT instances.",
"Type": "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription" : "Must be the name of an existing EC2 KeyPair." },
"Subnet": {
"Description": "The subnet to place the instance in...",
"Type": "AWS::EC2::Subnet::Id",
"ConstraintDescription" : "Must be a valid Subnet."
},
"VPC": {
"Description": "The VPC to deploy to...",
"Type": "AWS::EC2::VPC::Id",
"ConstraintDescription" : "Must be a valid VPC."
}
},
"Resources": {
"StageSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"VpcId": {"Ref": "VPC"},
"GroupDescription": "Allow SSH, HTTP, and HTTPS access",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "443",
"ToPort": "443",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"StageInstance": {
"Type" : "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"config": {
"packages": {
"apt": {
"awscli": [ ],
"apache2": [ ],
"php7.0": [ ],
"libapache2-mod-php7.0": [ ],
"php7.0-cli": [ ],
"php7.0-common": [ ],
"php7.0-mbstring": [ ],
"php7.0-gd": [ ],
"php7.0-intl": [ ],
"php7.0-xml": [ ],
"php7.0-mysql": [ ],
"php7.0-mcrypt": [ ],
"php7.0-zip": [ ]
}
}
}
}
},
"Properties": {
"BlockDeviceMappings" : [{
"DeviceName" : "/dev/sda1",
"Ebs" : {"VolumeSize" : {"Ref" : "EBSVolumeSize"}}
}],
"SecurityGroupIds": [{"Ref": "StageSecurityGroup"}],
"KeyName": {"Ref": "KeyName" },
"ImageId": {"Ref": "AMI"},
"SubnetId": {"Ref": "Subnet"},
"InstanceType": {"Ref": "InstanceType"},
"Tags": [
{"Key" : "Name", "Value" : "Ldn_Svr_Stage_Web"}
],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -x\n",
"apt-get update\n",
"apt-get install -y python-pip\n",
"pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
"cfn-init -v –resource StageInstance",
" –stack ",
{
"Ref": "AWS::StackName"
},
" –region ",
{
"Ref": "AWS::Region"
},
"\n",
"cfn-signal -e $? –resource StageInstance",
" –stack ",
{
"Ref": "AWS::StackName"
},
" –region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
}
}
}
}
}
Here is the working code for a simple example....
{
"Description": "stack descripton.....",
"Parameters": {
"AMI": {
"Default": "ami-996372fd",
"Description": "The Amazon Ubuntu AMI",
"Type": "String"
},
"EBSVolumeSize": {
"Default": "20",
"Description": "The size of the EBS volume",
"Type": "String"
},
"InstanceName": {
"Default": "My instance name",
"Description": "EC2 Instance Name",
"Type": "String"
},
"InstanceType": {
"AllowedValues": [
"t2.micro",
"t2.small",
"t2.medium",
"t2.large",
"c4.large",
"c4.xlarge",
"c4.2xlarge",
"c4.4xlarge",
"c4.8xlarge"
],
"ConstraintDescription": "must be a valid EC2 instance type",
"Default": "t2.micro",
"Description": "EC2 instance type",
"Type": "String"
},
"KeyName": {
"ConstraintDescription": "Must be the name of an existing EC2 KeyPair.",
"Description": "Name of an existing EC2 KeyPair to enable SSH access to NAT instances.",
"Type": "AWS::EC2::KeyPair::KeyName"
},
"Subnet": {
"ConstraintDescription": "Must be a valid Subnet.",
"Description": "The subnet to place the instance in...",
"Type": "AWS::EC2::Subnet::Id"
},
"VPC": {
"ConstraintDescription": "Must be a valid VPC.",
"Description": "The VPC to deploy to...",
"Type": "AWS::EC2::VPC::Id"
}
},
"Resources": {
"Instance": {
"Metadata": {
"AWS::CloudFormation::Init": {
"config": {
"packages": {
"apt": {
"awscli": [],
"ruby": [],
"unzip": []
}
},
"files": {
"/tmp/sample.conf": {
"content": {
"Fn::Join": [
"",
[
"write a sample file to OS and give permissions.... \n"
]
]
},
"mode": "000644",
"owner": "root",
"group": "root"
}
},
"commands": {
"01update_pkgs": {
"command": "apt-get update && apt-get upgrade -y"
},
"02next_command": {
"command": "echo the numbering here has to be in order... 01, 02, 03 and so on... last item is not comma'd"
}
}
}
}
},
"Properties": {
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"VolumeSize": {
"Ref": "EBSVolumeSize"
}
}
}
],
"ImageId": {
"Ref": "AMI"
},
"InstanceType": {
"Ref": "InstanceType"
},
"KeyName": {
"Ref": "KeyName"
},
"SecurityGroupIds": [
{
"Ref": "SecurityGroup"
}
],
"SubnetId": {
"Ref": "Subnet"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Ref": "InstanceName"
}
}
],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -xe\n",
"apt-get install -y python-setuptools\n",
"mkdir -p /opt/aws/bin\n",
"wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
"easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-latest.tar.gz\n",
" apt-get update\n",
"/opt/aws/bin/cfn-init --region ",
{
"Ref": "AWS::Region"
},
" -s ",
{
"Ref": "AWS::StackName"
},
" -r Instance\n"
]
]
}
}
},
"Type": "AWS::EC2::Instance"
},
"EIPAddress": {
"Type": "AWS::EC2::EIP"
},
"IPAssoc": {
"Type": "AWS::EC2::EIPAssociation",
"Properties": {
"InstanceId": {
"Ref": "Instance"
},
"EIP": {
"Ref": "EIPAddress"
}
}
},
"SecurityGroup": {
"Properties": {
"GroupDescription": "Allow SSH, HTTP, and HTTPS access",
"SecurityGroupIngress": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "22",
"IpProtocol": "tcp",
"ToPort": "22"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"IpProtocol": "tcp",
"ToPort": "443"
}
],
"VpcId": {
"Ref": "VPC"
}
},
"Type": "AWS::EC2::SecurityGroup"
}
}
}
Create a apache.json file :
{
"Resources" :
{
"WebServer":{
"Type": "AWS::EC2::Instance",
"Properties":{
"ImageId" : "ami-9a7724c8",
"KeyName" : "demo",
"InstanceType":"t1.micro",
"SecurityGroups" : [ "demo" ],
"UserData" : {"Fn::Base64" : {"Fn::Join" : ["", [
"#!/bin/bash\n",
"# Launching Instance",
"apt-get -y install apache2 \n",
"apt-get -y install php php5-mysql \n"
] ] } }
}
}
},
"Outputs":{
"WebsiteURL" : {
"Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [
"WebServer", "PublicDnsName" ]}]] },
"Description" : "URL for newly created apache server "
}
}
}
Then create a cloud formation stack using this json file.
Kindly validate the json file before saving it.
Hope it will help !
Could somebody help me point what wrong am I doing here. I am failing to understand how the meta data part uses the authentication resource, In the AWS::CloudFormation::Authentication part I've mentioned the role same as the one attached to the instance, Yet I'm unable to create the file "some.txt"
{
"Parameters": {
"SecurityGroupId": {
"Description": "Security group for instance",
"Type": "AWS::EC2::SecurityGroup::Id"
}
},
"Resources": {
"MyInstance": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"configsets": {
"InstallIt": ["config1"]
},
"config1": {
"files": {
"/home/ec2-user/some.txt": {
"content": "This is my name ",
"encoding": "base64",
"mode": "000644",
"owner": "root",
"group": "root"
}
}
}
},
"AWS::CloudFormation::Authentication": {
"HelpMe": {
"type": "S3",
"buckets": "poc-bucket",
"roleName": "EC2andS3"
}
}
},
"Properties": {
"KeyName": "GoldenImage-NV-Anant",
"DisableApiTermination": "false",
"ImageId": "ami-0b33d91d",
"InstanceType": "t2.micro",
"Monitoring": "false",
"SubnetId": "subnet-73487a59",
"SecurityGroupIds": [{
"Ref": "SecurityGroupId"
}],
"IamInstanceProfile": {
"Ref": "MyInstanceProfile"
},
"Tags": [{
"Key": "Name",
"Value": "GeicoUserDataPocInstance"
}],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"", [
"#!/bin/bash -ex \n",
"echo \"hello dudes\" > /home/ec2-user/hello.txt \n",
"yum update -y aws-cfn-bootstrap\n",
"/opt/aws/bin/cfn-init -v",
" --stack ", {
"Ref": "AWS::StackId"
},
" --resource MyInstance ",
" --configsets InstallIt ",
" --region ", {
"Ref": "AWS::Region"
}, "\n",
"echo \"bye dudes\" > /home/ec2-user/bye.txt", "\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ", {
"Ref": "AWS::StackId"
},
" --resource MyInstance ",
" --region ", {
"Ref": "AWS::Region"
}, "\n"
]
]
}
}
},
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT90M",
"Count": "1"
}
}
},
"MyInstanceProfile": {
"Description": "Instance profile for the instance",
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": ["EC2andS3"]
}
}
}
}
configsets should be configSets with capital S:
"configSets": {
"InstallIt": ["config1"]
},
buckets property needs to be a list of strings (this might not be necessary, the documentation is a bit unclear):
"buckets": ["poc-bucket"]
AWS::CloudFormation::Authentication resource shouldn't be necessary unless the source of your file is an S3 bucket. Even then, it still shouldn't be necessary when using an attached instance profile, since it will use the instance profile for authentication by default.
Create Amazon RDS Master and read replica cluster using cloudformation template.
We can create Amazon Aurora RDS using below cloudformation template. Just we need to pass our parameters while creating stack.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Aurora Db Stack",
"Parameters": {
"EnvironmentName": {
"Description": "The string that will be prefixed to each instance name",
"Type": "String",
"MinLength": "3",
"MaxLength": "6",
"AllowedPattern": "[a-z0-9]*",
"ConstraintDescription": "Environment names must be 3-6 characters and contain only a-z and 0-9."
},
"DbUsername": {
"Description": "App Db Username",
"Type": "String",
"MinLength": "5",
"MaxLength": "15",
"AllowedPattern": "[a-zA-Z][a-zA-Z0-9]*",
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters."
},
"DbPassword": {
"Description": "App Db Password",
"NoEcho": "true",
"Type": "String",
"MinLength": "15",
"MaxLength": "41",
"AllowedPattern": "[a-zA-Z0-9]*",
"ConstraintDescription": "App Db Password must be 15-41 characters and contain only alpha numeric characters."
},
"DbType": {
"Description": "App Db server RDS instance type",
"Type": "String",
"Default": "db.r3.large",
"AllowedValues": [
"db.r3.large",
"db.r3.xlarge",
"db.r3.2xlarge",
"db.r3.4xlarge",
"db.r3.8xlarge"
],
"ConstraintDescription": "must be a valid RDS instance type."
},
"DBIdentifierNameMaster": {
"Description": "The string that will be prefixed to each instance name",
"Type": "String",
"MinLength": "3",
"MaxLength": "10",
"AllowedPattern": "[a-z0-9]*",
"ConstraintDescription": "Identifier names must be 3-6 characters and contain only a-z and 0-9."
},
"DBIdentifierNameReplica": {
"Description": "The string that will be prefixed to each instance name",
"Type": "String",
"MinLength": "3",
"MaxLength": "10",
"AllowedPattern": "[a-z0-9]*",
"ConstraintDescription": "Identifier names must be 3-10 characters and contain only a-z and 0-9."
},
"Subnets": {
"Type": "CommaDelimitedList",
"Default": "subnet-8ec5b8e6,subnet-1edcc277",
"Description": "The list of SubnetIds where the stack will be launched"
},
"DBSecurityGroupName": {
"Type": "String",
"Description": "Security Group id"
}
},
"Resources": {
"DBSubnetGroup": {
"Type": "AWS::RDS::DBSubnetGroup",
"Properties": {
"DBSubnetGroupDescription": "Dev DB subent groups",
"SubnetIds":
{
"Ref": "Subnets"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"",
[
"PROJECT_NAME-",
{
"Ref": "EnvironmentName"
},
"-db"
]
]
}
}
]
}
},
"DBCluster": {
"Type": "AWS::RDS::DBCluster",
"Properties": {
"Engine": "aurora",
"MasterUsername": {
"Ref": "DbUsername"
},
"MasterUserPassword": {
"Ref": "DbPassword"
},
"DBSubnetGroupName": {
"Ref": "DBSubnetGroup"
},
"VpcSecurityGroupIds": [
{
"Ref": "DBSecurityGroupName"
}
]
}
},
"RDSinstance": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"DBClusterIdentifier": {
"Ref": "DBCluster"
},
"DBInstanceIdentifier": {
"Ref": "DBIdentifierNameMaster"
},
"DBInstanceClass": {
"Ref": "DbType"
},
"Engine": "aurora",
"DBParameterGroupName": {
"Ref": "DbParameterGroup"
},
"DBSubnetGroupName": {
"Ref": "DBSubnetGroup"
},
"PubliclyAccessible": "true",
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"",
[
"Master Database-",
{
"Ref": "EnvironmentName"
},
"-app-db"
]
]
}
}
]
}
},
"RDSinstance2": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"DBClusterIdentifier": {
"Ref": "DBCluster"
},
"DBInstanceIdentifier": {
"Ref": "DBIdentifierNameReplica"
},
"DBInstanceClass": {
"Ref": "DbType"
},
"Engine": "aurora",
"DBParameterGroupName": {
"Ref": "DbParameterGroup"
},
"DBSubnetGroupName": {
"Ref": "DBSubnetGroup"
},
"PubliclyAccessible": "true",
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"",
[
"Read Replica Database-",
{
"Ref": "EnvironmentName"
},
"-app-db"
]
]
}
}
]
}
},
"DbParameterGroup": {
"Type": "AWS::RDS::DBParameterGroup",
"Properties": {
"Description": "AppDbParameters",
"Family": "aurora5.6",
"Parameters": {
"log_bin_trust_function_creators": "on",
"explicit_defaults_for_timestamp": "0"
}
}
}
}
}