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
My instances when created by my cloudformation template do not run yum update or install aws-cfn-bootstrap. I see a timeout in the logs however it works after I login and they have fully booted.
Logs show me they are unable to connect at boot, I think because the natgw hasn't been built yet. It was working yesterday i have been tweaking since but cannot seem to get it to load anymore.
"Parameters": {
"ONtestenv": {
"Description": "env name",
"Type": "String"
},
"ONcidr": {
"Description": "subs for vpc",
"Type": "String",
"Default": "10.0.0.0/16"
},
"pubONsubnet": {
"Description": "pub sub block",
"Type": "String",
"Default": "10.0.0.0/24"
},
"privONsubnet": {
"Description": "priv subn clok",
"Type": "String",
"Default": "10.0.1.0/24"
},
"KeyName": {
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
"Type": "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription": "must be the name of an existing EC2 KeyPair."
},
"SSHLocation": {
"Description": "The IP address range that can be used to SSH to the EC2 instances",
"Type": "String",
"MinLength": "9",
"MaxLength": "18",
"Default": "0.0.0.0/0",
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
"ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
},
"InstanceType": {
"Description": "WebServer EC2 instance type",
"Type": "String",
"Default": "t2.micro",
"AllowedValues": [
"t2.micro",
"m1.small",
"m1.medium",
"m1.large",
"m1.xlarge",
"m2.xlarge",
"m2.2xlarge",
"m2.4xlarge"
],
"ConstraintDescription": "must be a valid EC2 instance type."
}
},
"Mappings": {
"Region2Examples": {
"us-east-1": {
"Examples": "https://s3.amazonaws.com/cloudformation-examples-us-east-1"
},
"ca-central-1": {
"Examples": "https://s3.amazonaws.com/cloudformation-examples-us-east-1"
},
"us-west-2": {
"Examples": "https://s3-us-west-2.amazonaws.com/cloudformation-examples-us-west-2"
},
"us-west-1": {
"Examples": "https://s3-us-west-1.amazonaws.com/cloudformation-examples-us-west-1"
},
"eu-west-1": {
"Examples": "https://s3-eu-west-1.amazonaws.com/cloudformation-examples-eu-west-1"
},
"eu-central-1": {
"Examples": "https://s3-eu-central-1.amazonaws.com/cloudformation-examples-eu-central-1"
},
"ap-southeast-1": {
"Examples": "https://s3-ap-southeast-1.amazonaws.com/cloudformation-examples-ap-southeast-1"
},
"us-east-2": {
"Examples": "https://s3-us-east-2.amazonaws.com/cloudformation-examples-us-east-2"
},
"sa-east-1": {
"Examples": "https://s3-sa-east-1.amazonaws.com/cloudformation-examples-sa-east-1"
},
"cn-north-1": {
"Examples": "https://s3.cn-north-1.amazonaws.com.cn/cloudformation-examples-cn-north-1"
}
},
"AWSInstanceType2Arch": {
"t2.micro": {
"Arch": "64"
},
"m1.small": {
"Arch": "64"
},
"m1.medium": {
"Arch": "64"
},
"m1.large": {
"Arch": "64"
},
"m1.xlarge": {
"Arch": "64"
},
"m2.xlarge": {
"Arch": "64"
},
"m2.2xlarge": {
"Arch": "64"
},
"m2.4xlarge": {
"Arch": "64"
},
"c1.medium": {
"Arch": "64"
},
"c1.xlarge": {
"Arch": "64"
},
"cc1.4xlarge": {
"Arch": "64HVM"
},
"cc2.8xlarge": {
"Arch": "64HVM"
},
"cg1.4xlarge": {
"Arch": "64HVM"
}
},
"AWSRegionArch2AMI": {
"us-east-1": {
"32": "ami-31814f58",
"64": "ami-1b814f72",
"64HVM": "ami-0da96764"
},
"ca-central-1": {
"32": "ami-31814f58",
"64": "ami-b61b96d2",
"64HVM": "ami-b61b96d2"
},
"us-west-2": {
"32": "ami-38fe7308",
"64": "ami-30fe7300",
"64HVM": "NOT_YET_SUPPORTED"
},
"us-west-1": {
"32": "ami-11d68a54",
"64": "ami-1bd68a5e",
"64HVM": "NOT_YET_SUPPORTED"
},
"eu-west-1": {
"32": "ami-973b06e3",
"64": "ami-953b06e1",
"64HVM": "NOT_YET_SUPPORTED"
},
"ap-southeast-1": {
"32": "ami-b4b0cae6",
"64": "ami-beb0caec",
"64HVM": "NOT_YET_SUPPORTED"
},
"ap-northeast-1": {
"32": "ami-0644f007",
"64": "ami-0a44f00b",
"64HVM": "NOT_YET_SUPPORTED"
},
"sa-east-1": {
"32": "ami-3e3be423",
"64": "ami-3c3be421",
"64HVM": "NOT_YET_SUPPORTED"
}
}
},
"Resources": {
"ONtestVPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": {
"Ref": "ONcidr"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Ref": "ONtestenv"
}
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "3321d2b3-88cd-4e8f-bef1-b5d0b853ca46"
}
}
},
"ONIG": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": {
"Ref": "ONtestenv"
}
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "d5878b9e-87f5-4088-8401-1a60d827a01a"
}
}
},
"ONgatewayattach": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"InternetGatewayId": {
"Ref": "ONIG"
},
"VpcId": {
"Ref": "ONtestVPC"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "b654db30-aa3f-4ffe-ab5c-27b9a14be28e"
}
}
},
"natGW": {
"Type": "AWS::EC2::NatGateway",
"Properties": {
"AllocationId": {
"Fn::GetAtt": [
"natEIP",
"AllocationId"
]
},
"SubnetId": {
"Ref": "pubsub"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "b030b414-e088-4733-8d0a-bbe426610828"
}
}
},
"pubsub": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "ONtestVPC"
},
"AvailabilityZone": {
"Fn::Select": [
0,
{
"Fn::GetAZs": ""
}
]
},
"CidrBlock": {
"Ref": "pubONsubnet"
},
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Sub": "${ONtestenv} pub sub"
}
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "dd0e3e42-3b94-4ffe-a8e3-85690934c839"
}
}
},
"privsub": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "ONtestVPC"
},
"AvailabilityZone": {
"Fn::Select": [
0,
{
"Fn::GetAZs": ""
}
]
},
"CidrBlock": {
"Ref": "privONsubnet"
},
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Sub": "${ONtestenv} priv sub"
}
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "4cfc646e-acb2-45ea-a075-596b7453e7d7"
}
}
},
"natEIP": {
"Type": "AWS::EC2::EIP",
"DependsOn": "ONgatewayattach",
"Properties": {
"Domain": "vpc"
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "c3501a25-dec8-4d5b-a8af-4c8ddc2b8c48"
}
}
},
"pubroutes": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "ONtestVPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Sub": "${ONtestenv} pub routes"
}
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "15610e2e-2838-4b07-9ed0-3339a8ee2c6b"
}
}
},
"defaultpubroute": {
"Type": "AWS::EC2::Route",
"DependsOn": "ONgatewayattach",
"Properties": {
"RouteTableId": {
"Ref": "pubroutes"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "ONIG"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "2ccd0372-a83b-42cf-8d24-4bf2937f9db2"
}
}
},
"pubsubrtassoc": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "pubroutes"
},
"SubnetId": {
"Ref": "pubsub"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "871f2e97-ff70-4bcf-a707-07cd7629a070"
}
}
},
"privroutetable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "ONtestVPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Sub": "${ONtestenv} priv routes"
}
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "e3959861-54ef-41eb-8732-644b3302f1a2"
}
}
},
"defaultprivroute": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "privroutetable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"NatGatewayId": {
"Ref": "natGW"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "0bd7af21-8d8c-4bcb-ac8d-b7a0c1bcc7f1"
}
}
},
"privsubrtassoc": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "privroutetable"
},
"SubnetId": {
"Ref": "privsub"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "e4a0e22d-b70f-498f-8269-7569a2a260cc"
}
}
},
"SG": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Enable ping and ssh access via port 22 and ALL from VPC CIDR",
"VpcId": {
"Ref": "ONtestVPC"
},
"SecurityGroupIngress": [
{
"IpProtocol": "icmp",
"FromPort": "8",
"ToPort": "-1",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "icmp",
"FromPort": "-1",
"ToPort": "-1",
"CidrIp": "10.0.0.0/16"
},
{
"IpProtocol": "udp",
"FromPort": "1",
"ToPort": "65535",
"CidrIp": "10.0.0.0/16"
},
{
"IpProtocol": "tcp",
"FromPort": "1",
"ToPort": "65535",
"CidrIp": "10.0.0.0/16"
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "64176529-142e-41de-a97d-b4306dd2c445"
}
}
},
"webAutoscalingGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"LaunchConfigurationName": {
"Ref": "LaunchConfig"
},
"LoadBalancerNames": [
{
"Ref": "ElasticLoadBalancer"
}
],
"MaxSize": 4,
"MinSize": 2,
"VPCZoneIdentifier": [
{
"Ref": "pubsub"
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "a331154a-b1ca-416c-80d3-651425c8ad8e"
}
}
},
"webAutoscalePolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Description": "A policy to expand the size of the pool by 1 instance",
"Properties": {
"AutoScalingGroupName": {
"Ref": "webAutoscalingGroup"
},
"AdjustmentType": "ChangeInCapacity",
"Cooldown": 300,
"ScalingAdjustment": 1
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "77ce9e6f-f50d-4f96-a229-76ffe3bfc32a"
}
}
},
"webAutoScaleAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Description": "When average bandwidth for the instances exceeds a threshold trigger\nthe policy (increasing instance count by 1)\n",
"Properties": {
"AlarmName": {
"Fn::Join": [
"-",
[
{
"Ref": "AWS::StackName"
},
"bytes out alarm"
]
]
},
"AlarmDescription": "This metric monitors network utilization",
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"EvaluationPeriods": 2,
"MetricName": "NetworkIn",
"Namespace": "AWS/EC2",
"Period": 60,
"Statistic": "Average",
"Threshold": 5000,
"Dimensions": [
{
"Name": "AutoScalingGroupName",
"Value": {
"Ref": "webAutoscalingGroup"
}
}
]
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "e04f759b-93b9-4072-8966-484a4e953230"
}
}
},
"LBSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "SSH and HTTP inbound, egress to VPC",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "SSHLocation"
}
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "tcp",
"FromPort": 0,
"ToPort": 65535,
"CidrIp": "0.0.0.0/0"
}
],
"VpcId": {
"Ref": "ONtestVPC"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "f6b443e1-6c3f-4e3c-bcc4-fbccb527b1f1"
}
}
},
"ElasticLoadBalancer": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"Subnets": [
{
"Ref": "pubsub"
}
],
"CrossZone": "true",
"Listeners": [
{
"LoadBalancerPort": "80",
"InstancePort": "80",
"Protocol": "HTTP"
}
],
"HealthCheck": {
"Target": "HTTP:80/",
"HealthyThreshold": "3",
"UnhealthyThreshold": "5",
"Interval": "30",
"Timeout": "5"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "33772321-0e4d-4a0e-bfc6-e4196b7cdead"
}
}
},
"InstanceSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "SSH inbound, port 80 inbound from the load balancer",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": {
"Ref": "SSHLocation"
}
},
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "SSHLocation"
}
}
],
"VpcId": {
"Ref": "ONtestVPC"
}
},
"Metadata": {
"AWS::CloudFormation::Designer": {
"id": "9bed003f-7101-4f65-a41c-175bfa579c08"
}
}
},
"LaunchConfig": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Metadata": {
"Comment": "Install a simple application",
"AWS::CloudFormation::Init": {
"config": {
"packages": {
"yum": {
"httpd": []
}
},
"files": {
"/var/www/html/index.html": {
"content": {
"Fn::Join": [
"\n",
[
"<img src=\"",
{
"Fn::FindInMap": [
"Region2Examples",
{
"Ref": "AWS::Region"
},
"Examples"
]
},
"/cloudformation_graphic.png\" alt=\"AWS CloudFormation Logo\"/>",
"<h1>Congratulations, you have successfully launched the AWS CloudFormation sample.</h1>"
]
]
},
"mode": "000644",
"owner": "root",
"group": "root"
},
"/etc/cfn/cfn-hup.conf": {
"content": {
"Fn::Join": [
"",
[
"[main]\n",
"stack=",
{
"Ref": "AWS::StackId"
},
"\n",
"region=",
{
"Ref": "AWS::Region"
},
"\n"
]
]
},
"mode": "000400",
"owner": "root",
"group": "root"
},
"/etc/cfn/hooks.d/cfn-auto-reloader.conf": {
"content": {
"Fn::Join": [
"",
[
"[cfn-auto-reloader-hook]\n",
"triggers=post.update\n",
"path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init\n",
"action=/opt/aws/bin/cfn-init -v ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource LaunchConfig ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n",
"runas=root\n"
]
]
}
}
},
"services": {
"sysvinit": {
"httpd": {
"enabled": "true",
"ensureRunning": "true"
},
"cfn-hup": {
"enabled": "true",
"ensureRunning": "true",
"files": [
"/etc/cfn/cfn-hup.conf",
"/etc/cfn/hooks.d/cfn-auto-reloader.conf"
]
}
}
}
}
},
"AWS::CloudFormation::Designer": {
"id": "fb6eab98-3a1b-426a-945f-14c25bb99862"
}
},
"Properties": {
"KeyName": {
"Ref": "KeyName"
},
"ImageId": {
"Fn::FindInMap": [
"AWSRegionArch2AMI",
{
"Ref": "AWS::Region"
},
{
"Fn::FindInMap": [
"AWSInstanceType2Arch",
{
"Ref": "InstanceType"
},
"Arch"
]
}
]
},
"SecurityGroups": [
{
"Ref": "InstanceSecurityGroup"
}
],
"InstanceType": {
"Ref": "InstanceType"
},
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -xe\n",
"yum update -y aws-cfn-bootstrap\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource LaunchConfig ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource WebServerGroup ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
}
}
}
},
"Outputs": {
"VPC": {
"Description": "A reference to the created VPC",
"Value": {
"Ref": "ONtestVPC"
}
},
"PublicSubnet": {
"Description": "public subnet",
"Value": {
"Fn::Join": [
",",
[
{
"Ref": "pubsub"
}
]
]
}
},
"PrivateSubnet": {
"Description": "private subnet",
"Value": {
"Fn::Join": [
",",
[
{
"Ref": "privsub"
}
]
]
}
}
}
}```
I am hoping it will install the simple httpd server but it does not. I am able to run the exact same command ```yum update -y``` after it's booted and I login to it.
You can put a DependsOn condition on the Auto Scaling group referencing the natGW, so that it won't launch instances until the NAT Gateway is ready.
See: DependsOn Attribute - AWS CloudFormation
CloudFormation normally figures out "depends on" linkages automatically, based on references from one resource to another (eg a Subnet references a VPC, so CloudFormation waits for the VPC to be ready before creating the Subnet).
However, not all relationships are obvious such as between your Auto Scaling group and the NAT Gateway. For these situations, you can manually add a DependsOn.
It can also be beneficial to use multiple stacks. This reduces the number of resource dependencies that need to be specified.
Key things like a NAT Gateway should be in one of the first stacks and then if you put things like an autoscaling group in a stack added later the dependency doesn't have to be specified as the NAT Gateway will already be up from the earlier stack.
I'm using Cloudformation to automate instance creation. I'm using an auto scaling group to build a variable number dependent on what i need. However there is a reoccurring issue where at least 1 instance fails to run when i build 2+ instances from this script.
For Example: I state 7 instances for cloudformation to build, 6 will work perfectly but there is always 1 that will not work. There is no error, it just seems to ignore commands. In the userdata section of this script i launch dockers to run in the instance.
I get this error: rpc error code = 13 desc = transport is closing
Can someone take a look to see if doing something wrong or I'm missing a step?
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Test",
"Parameters": {
"InstanceType": {
"Type": "String",
"Default": "t2.large"
},
"NoOfInstances": {
"Type": "String",
"ConstraintDescription": ""
},
"RoleName": {
"Type": "String",
"Default": "**",
"ConstraintDescription": ""
},
"VPCParameter": {
"Type": "AWS::EC2::VPC::Id",
"Default": "**"
},
"SubnetsParameter": {
"Type": "List<AWS::EC2::Subnet::Id>",
"Default": "**"
},
"KeyName": {
"Type": "AWS::EC2::KeyPair::KeyName",
"Default": "**",
"ConstraintDescription": ""
}
},
"Mappings": {
"AWSInstanceType2Arch": {
"t2.large": {
"Arch": "HVM64"
}
},
"AWSRegionArch2AMI": {
"**": {
"HVM64": "**"
}
}
},
"Resources": {
"LaunchConfig": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Properties": {
"KeyName": {
"Ref": "KeyName"
},
"IamInstanceProfile": {
"Ref": "RoleName"
},
"SecurityGroups": [{
"Ref": "WebServerSecurityGroup"
}],
"ImageId": {
"Fn::FindInMap": ["AWSRegionArch2AMI",
{
"Ref": "AWS::Region"
}, {
"Fn::FindInMap": ["AWSInstanceType2Arch", {
"Ref": "InstanceType"
}, "Arch"]
}
]
},
"InstanceType": {
"Ref": "InstanceType"
},
"UserData": {
"Fn::Base64": {
"Fn::Join": ["", [ ** ]]
}
}
}
},
"AutoScalingServerGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"LaunchConfigurationName": {
"Ref": "LaunchConfig"
},
"MinSize": "1",
"MaxSize": "30",
"Cooldown": "300",
"VPCZoneIdentifier": {
"Ref": "SubnetsParameter"
},
"DesiredCapacity": {
"Ref": "NoOfInstances"
},
"Tags": [ ** ]
}
},
"WebServerSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "**",
"VpcId": {
"Ref": "VPCParameter"
},
"SecurityGroupIngress": [{
"IpProtocol": "tcp",
"CidrIp": "**",
"FromPort": "**",
"ToPort": "**"
}, ]
}
},
"WebServerScaleUpPolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Properties": {
"AdjustmentType": "ChangeInCapacity",
"AutoScalingGroupName": {
"Ref": "AutoScalingServerGroup"
},
"Cooldown": "60",
"ScalingAdjustment": "1"
}
},
"WebServerScaleDownPolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Properties": {
"AdjustmentType": "ChangeInCapacity",
"AutoScalingGroupName": {
"Ref": "AutoScalingServerGroup"
},
"Cooldown": "60",
"ScalingAdjustment": "-1"
}
}
}
}
You could be hitting EC2 instance limits - https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-resource-limits.html
You could also look at the Activity History tab for the Auto Scaling Group. See if it has any useful information.
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 !
I extracted a CloudFormation template from a stack created by cfncluster. I'm trying to simplify and group the parameters so that the mandatory parameters are grouped together and are non-redundant. The default subnet-related parameters include MasterSubnetId, AvailabilityZone, ComputeSubnetId, and ComputeSubnetCidr. The template uses these to calculate several conditions and also to set AvailabilityZone properties on several resources:
"CreateComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
}
]
},
"UseComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
}
]
}
]
},
"UseMasterSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
},
I want to simplify the template to require either MasterSubnetId or AvailabilityZone, but not both. I don't need the option to provide one or the other, it's fine for me to require one or the other. The main problem is I can't figure out how to do that. The various Resources used by the template seem to require both, even though they should be related. I can't use Fn::GetAtt like I want because the first argument cannot come from functions, like this:
"Fn::GetAtt" : [ { "Ref": "MasterSubnetId" }, "AvailabilityZone" ]
Also, I want the compute fleet to always get its own subnet.
Here are the subnet-related parts of the template :
{
...snip...
"Parameters": {
"ComputeSubnetId": {
"Description": "ID of the Subnet you want to provision the Compute Servers into. Set to NONE to use the same subnet as Master Server.",
"Type": "String",
"Default": "NONE"
},
"ComputeSubnetCidr": {
"Description": "CIDR(s) for new backend subnet(s) i.e. 10.0.100.0/24. This is a comma-delimited list and can support multiple CIDR ranges for a multi-AZ cluster. The order and length of this list MUST match the AvailabilityZones parameter. Set to NONE to use the same subnet as Master Server.",
"Type": "String",
"ConstraintDescription": "must be a valid CIDR range of the form x.x.x.x/x.",
"AllowedPattern": "(NONE|(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2}))",
"Default": "NONE"
},
"MasterSubnetId": {
"Description": "ID of the Subnet you want to provision the Master server into",
"Type": "AWS::EC2::Subnet::Id"
},
"AvailabilityZone": {
"Description": "Availability Zone the cluster will launch into. THIS IS REQUIRED",
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"VPCId": {
"Description": "ID of the VPC you want to provision cluster into. Only used with UseVPCBase=false",
"Type": "AWS::EC2::VPC::Id"
},
"UsePublicIps": {
"Description": "Boolean flag to use public IP's for instances. If false, the VPC must be correctly setup to use NAT for all traffic.",
"Type": "String",
"Default": "true",
"ConstraintDescription": "true/false",
"AllowedValues": [
"true",
"false"
]
}
},
"Conditions": {
"CreateComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
}
]
},
"UseComputeSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
},
{
"Fn::Not": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
}
]
}
]
},
"UseMasterSubnetForCompute": {
"Fn::And": [
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetId"
},
"NONE"
]
},
{
"Fn::Equals": [
{
"Ref": "ComputeSubnetCidr"
},
"NONE"
]
}
]
}
},
"Mappings": {
"AWSInstanceType2Capabilites": {
...snip...
},
"AWSRegionOS2AMI": {
...snip...
},
"OSFeatures": {
...snip...
},
"CfnClusterVersions": {
"default": {
"cfncluster": "cfncluster-1.1.0",
"cookbook": "cfncluster-cookbook-1.1.0",
"chef": "12.4.3",
"ridley": "4.3.2",
"berkshelf": "4.0.1",
"ami": "201602192042"
}
},
"AWSRegion2Capabilites": {
...snip...
}
},
"Resources": {
...snip...
"CfnClusterPolicies": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "cfncluster",
"PolicyDocument": {
"Statement": [
{
"Sid": "EC2",
"Action": [
"ec2:AttachVolume",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeInstanceStatus",
"ec2:DescribeInstances"
],
"Effect": "Allow",
"Resource": [
"*"
]
},
...snip...
]
},
"Roles": [
{
"Ref": "RootRole"
}
]
},
"Condition": "CreateEC2IAMRole",
},
"MasterEIP": {
"Type": "AWS::EC2::EIP",
"Properties": {
"Domain": "vpc"
},
"Condition": "MasterPublicIp",
},
"MasterServer": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": {
"Ref": "MasterInstanceType"
},
"BlockDeviceMappings": [
...snip...
],
"KeyName": {
"Ref": "KeyName"
},
"Tags": [
{
"Key": "Application",
"Value": {
"Ref": "AWS::StackName"
}
},
{
"Key": "Name",
"Value": "Master"
}
],
"NetworkInterfaces": [
{
"NetworkInterfaceId": {
"Ref": "MasterENI"
},
"DeviceIndex": "0"
}
],
"ImageId": {
"Fn::If": [
"UseCustomAMI",
{
"Ref": "CustomAMI"
},
{
"Fn::FindInMap": [
"AWSRegionOS2AMI",
{
"Ref": "AWS::Region"
},
{
"Ref": "BaseOS"
}
]
}
]
},
"UserData": {
...snip...
}
}
},
"Metadata": {
"Comment": "cfncluster Master server",
"AWS::CloudFormation::Init": {
"configSets": {
"default": [
"deployConfigFiles",
"getCookbooks",
"chefPrepEnv",
"shellRunPreInstall",
"chefConfig",
"shellRunPostInstall",
"shellForkClusterReadyInstall"
]
},
"deployConfigFiles": {
"files": {
"/tmp/dna.json": {
"mode": "000644",
"owner": "root",
"group": "root",
"content": {
"cfncluster": {
"stack_name": {
"Ref": "AWS::StackName"
},
"cfn_preinstall": {
"Ref": "PreInstallScript"
},
"cfn_preinstall_args": {
"Ref": "PreInstallArgs"
},
"cfn_postinstall": {
"Ref": "PostInstallScript"
},
"cfn_postinstall_args": {
"Ref": "PostInstallArgs"
},
"cfn_region": {
"Ref": "AWS::Region"
},
"cfn_volume": {
"Fn::If": [
"UseExistingEBSVolume",
{
"Ref": "EBSVolumeId"
},
{
"Ref": "SharedVolume"
}
]
},
"cfn_scheduler": {
"Ref": "Scheduler"
},
"cfn_encrypted_ephemeral": {
"Ref": "EncryptedEphemeral"
},
"cfn_ephemeral_dir": {
"Ref": "EphemeralDir"
},
"cfn_shared_dir": {
"Ref": "SharedDir"
},
"cfn_proxy": {
"Ref": "ProxyServer"
},
"cfn_node_type": "MasterServer",
"cfn_cluster_user": {
"Fn::FindInMap": [
"OSFeatures",
{
"Ref": "BaseOS"
},
"User"
]
},
"cfn_ddb_table": {
"Ref": "DynamoDBTable"
},
"cfn_sqs_queue": {
"Fn::GetAtt": [
"SQS",
"QueueName"
]
}
},
"run_list": {
"Fn::If": [
"UseCustomRunList",
{
"Ref": "CustomChefRunList"
},
{
"Fn::Join": [
"",
[
"recipe[cfncluster::",
{
"Ref": "Scheduler"
},
"_config]"
]
]
}
]
}
}
},
...snip...
},
"commands": {
...snip...
}
},
...snip...
},
},
"CreationPolicy": {
"ResourceSignal": {
"Count": "1",
"Timeout": "PT30M"
}
}
},
"ComputeFleet": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"MaxSize": {
"Ref": "MaxQueueSize"
},
"AvailabilityZones": [
{
"Ref": "AvailabilityZone"
}
],
"VPCZoneIdentifier": [
{
"Fn::If": [
"UseMasterSubnetForCompute",
{
"Ref": "MasterSubnetId"
},
{
"Fn::If": [
"CreateComputeSubnetForCompute",
{
"Ref": "ComputeSubnet"
},
{
"Ref": "ComputeSubnetId"
}
]
}
]
}
],
...snip...
},
"DependsOn": "MasterServer",
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT30M",
"Count": {
"Ref": "ComputeWaitConditionCount"
}
}
},
},
"ComputeServerLaunchConfig": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Properties": {
"SecurityGroups": [
{
"Fn::If": [
"CreateSecurityGroups",
{
"Ref": "ComputeSecurityGroup"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"AddAdditionalSG",
{
"Ref": "AdditionalSG"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"UseExistingSecurityGroup",
{
"Ref": "VPCSecurityGroupId"
},
{
"Ref": "AWS::NoValue"
}
]
}
],
...snip...
},
"Metadata": {
"Comment": "cfncluster Compute server",
"AWS::CloudFormation::Init": {
"configSets": {
"default": [
"deployConfigFiles",
"getCookbooks",
"chefPrepEnv",
"shellRunPreInstall",
"chefConfig",
"shellRunPostInstall",
"shellForkClusterReadyInstall",
"signalComputeReady"
]
},
"deployConfigFiles": {
"files": {
"/tmp/dna.json": {
"mode": "000644",
"owner": "root",
"group": "root",
"content": {
"cfncluster": {
"stack_name": {
"Ref": "AWS::StackName"
},
"cfn_preinstall": {
"Ref": "PreInstallScript"
},
"cfn_preinstall_args": {
"Ref": "PreInstallArgs"
},
"cfn_postinstall": {
"Ref": "PostInstallScript"
},
"cfn_postinstall_args": {
"Ref": "PostInstallArgs"
},
"cfn_region": {
"Ref": "AWS::Region"
},
"cfn_scheduler": {
"Ref": "Scheduler"
},
"cfn_encrypted_ephemeral": {
"Ref": "EncryptedEphemeral"
},
"cfn_ephemeral_dir": {
"Ref": "EphemeralDir"
},
"cfn_shared_dir": {
"Ref": "SharedDir"
},
"cfn_proxy": {
"Ref": "ProxyServer"
},
"cfn_sqs_queue": {
"Ref": "SQS"
},
"cfn_master": {
"Fn::GetAtt": [
"MasterServer",
"PrivateDnsName"
]
},
"cfn_node_type": "ComputeFleet",
"cfn_cluster_user": {
"Fn::FindInMap": [
"OSFeatures",
{
"Ref": "BaseOS"
},
"User"
]
}
},
"run_list": {
"Fn::If": [
"UseCustomRunList",
{
"Ref": "CustomChefRunList"
},
{
"Fn::Join": [
"",
[
"recipe[cfncluster::",
{
"Ref": "Scheduler"
},
"_config]"
]
]
}
]
}
}
},
...snip...
},
"commands": {
...snip...
}
},
...snip...
}
},
...snip...
"ComputeSubnet": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPCId"
},
"CidrBlock": {
"Ref": "ComputeSubnetCidr"
},
"Tags": [
{
"Key": "Network",
"Value": "ComputeSubnet"
}
],
"AvailabilityZone": {
"Ref": "AvailabilityZone"
}
},
"Condition": "CreateComputeSubnetForCompute",
},
"ComputeRouteTable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPCId"
},
"Tags": [
{
"Key": "Application",
"Value": {
"Ref": "AWS::StackName"
}
},
{
"Key": "Network",
"Value": "ComputeSubnet"
}
]
},
"Condition": "CreateComputeSubnetForCompute",
},
"ComputeRoute": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "ComputeRouteTable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"NetworkInterfaceId": {
"Ref": "MasterENI"
}
},
"Condition": "CreateComputeSubnetForCompute",
},
"ComputeSubnetRouteTableAssociation": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "ComputeSubnet"
},
"RouteTableId": {
"Ref": "ComputeRouteTable"
}
},
"Condition": "CreateComputeSubnetForCompute",
},
"MasterSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Enable access to the Master host",
"VpcId": {
"Ref": "VPCId"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "AccessFrom"
}
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": {
"Ref": "AccessFrom"
}
}
]
},
"Condition": "CreateSecurityGroups",
},
"MasterSecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"IpProtocol": "-1",
"FromPort": "0",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Ref": "ComputeSecurityGroup"
},
"GroupId": {
"Ref": "MasterSecurityGroup"
}
},
"Condition": "CreateSecurityGroups",
},
"ComputeSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow access to resources in subnets behind front",
"VpcId": {
"Ref": "VPCId"
},
"SecurityGroupIngress": [
{
"SourceSecurityGroupId": {
"Ref": "MasterSecurityGroup"
},
"IpProtocol": "-1",
"FromPort": "0",
"ToPort": "65535"
}
]
},
"Condition": "CreateSecurityGroups",
},
"ComputeSecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"IpProtocol": "-1",
"FromPort": "0",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Ref": "ComputeSecurityGroup"
},
"GroupId": {
"Ref": "ComputeSecurityGroup"
}
},
"Condition": "CreateSecurityGroups"
},
"MasterENI": {
"Type": "AWS::EC2::NetworkInterface",
"Properties": {
"Description": "cfncluster Master Server",
"SubnetId": {
"Ref" : "MasterSubnetId"
},
"SourceDestCheck": "false",
"GroupSet": [
{
"Fn::If": [
"CreateSecurityGroups",
{
"Ref": "MasterSecurityGroup"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"AddAdditionalSG",
{
"Ref": "AdditionalSG"
},
{
"Ref": "AWS::NoValue"
}
]
},
{
"Fn::If": [
"UseExistingSecurityGroup",
{
"Ref": "VPCSecurityGroupId"
},
{
"Ref": "AWS::NoValue"
}
]
}
]
},
},
"SharedVolume": {
"Type": "AWS::EC2::Volume",
"Properties": {
"AvailabilityZone": {
"Ref": "AvailabilityZone"
},
"VolumeType": {
"Ref": "VolumeType"
},
"Size": {
"Fn::If": [
"UseEBSSnapshot",
{
"Ref": "AWS::NoValue"
},
{
"Ref": "VolumeSize"
}
]
},
...snip...
},
...snip...
},
...snip...