Scenario:
- Create a vpc
- Add 3 subnets to vpc [Refer to previous classes screenshots]
- Create and attach internet gateway to vpc
- Create a Route table with route to internet gateway
- Create subnet associations to new route table for 2 out 3 subnets
- Create a Key value pair [manual] and security group [manual]
- Create an ec2 instance in subnet1 and other ec2 instance in subnet2 [last step] and ensure this solution works on us-west-2, us-east-1 and ap-south-1
- With every region in aws Image id /AMI id changes
- AWS has a reference {‘Ref’: "AWS::Region" } which gives you current region
- AWS supports Mappings Refer Here
- The cloud formation template looks as shown below
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template is written for learning and it creates s3 bucket and ec2 instance",
"Parameters": {
"keypair": {
"Description": "key pair for ec2 instance",
"Type": "AWS::EC2::KeyPair::KeyName"
},
"instancetype": {
"Type": "String",
"AllowedValues": [
"t2.micro",
"t2.nano"
]
},
"subnet1AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"subnet2AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"subnet3AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
}
},
"Mappings": {
"AMIRegionMap": {
"us-west-2": {
"ubuntu18": "ami-003634241a8fcdec0"
},
"us-west-1": {
"ubuntu18": "ami-0f56279347d2fa43e"
},
"us-east-2": {
"ubuntu18": "ami-07c1207a9d40bc3bd"
},
"us-east-1": {
"ubuntu18": "ami-085925f297f89fce1"
},
"ap-south-1": {
"ubuntu18": "ami-0b44050b2d893d5f7"
}
}
},
"Resources": {
"mynetwork": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.10.0.0/16",
"Tags": [
{
"Key": "Name",
"Value": "my network"
}
]
}
},
"subnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet1AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.0.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet1"
}
]
}
},
"subnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet2AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.1.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet2"
}
]
}
},
"subnet3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet3AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.2.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet2"
}
]
}
},
"myigw": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": "myigw"
}
]
}
},
"AttachGateway": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "mynetwork"
},
"InternetGatewayId": {
"Ref": "myigw"
}
}
},
"myroutetable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "mynetwork"
},
"Tags": [
{
"Key": "Name",
"Value": "my rt"
}
]
}
},
"routeName": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "myroutetable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "myigw"
}
}
},
"routeTableAssocName": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "subnet1"
},
"RouteTableId": {
"Ref": "myroutetable"
}
}
},
"InstanceSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow ssh to client host",
"VpcId": {
"Ref": "mynetwork"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"CidrIp": "0.0.0.0/0"
}
]
}
},
"myweb": {
"Type": "AWS::EC2::Instance",
"Properties": {
"KeyName": {
"Ref": "keypair"
},
"ImageId": {
"Fn::FindInMap": [
"AMIRegionMap",
{
"Ref": "AWS::Region"
},
"ubuntu18"
]
},
"InstanceType": {
"Ref": "instancetype"
},
"NetworkInterfaces": [
{
"AssociatePublicIpAddress": "true",
"DeviceIndex": "0",
"GroupSet": [
{
"Ref": "InstanceSecurityGroup"
}
],
"SubnetId": {
"Ref": "subnet1"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": "myweb"
}
]
}
}
}
}
- Now use this template to create stacks in atleast two regions
CloudFormation Functions
- Refer Here
- Lets try to show the public ip address of the ec2 machine in the outputs
- To do this we need to use Fn::GetAtt function and also look into the reference and Fn::GetAtt section of any resource
- using GetAtt function as defined over here
- Lets add the following to the template written above
,
"Outputs": {
"publicip": {
"Value": {
"Fn::GetAtt": [
"myweb",
"PublicIp"
]
}
},
"privateip": {
"Value": {
"Fn::GetAtt": [
"myweb",
"PrivateIp"
]
}
}
}
- The complete template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template is written for learning and it creates s3 bucket and ec2 instance",
"Parameters": {
"keypair": {
"Description": "key pair for ec2 instance",
"Type": "AWS::EC2::KeyPair::KeyName"
},
"instancetype": {
"Type": "String",
"AllowedValues": [
"t2.micro",
"t2.nano"
]
},
"subnet1AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"subnet2AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"subnet3AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
}
},
"Mappings": {
"AMIRegionMap": {
"us-west-2": {
"ubuntu18": "ami-003634241a8fcdec0"
},
"us-west-1": {
"ubuntu18": "ami-0f56279347d2fa43e"
},
"us-east-2": {
"ubuntu18": "ami-07c1207a9d40bc3bd"
},
"us-east-1": {
"ubuntu18": "ami-085925f297f89fce1"
},
"ap-south-1": {
"ubuntu18": "ami-0b44050b2d893d5f7"
}
}
},
"Resources": {
"mynetwork": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.10.0.0/16",
"Tags": [
{
"Key": "Name",
"Value": "my network"
}
]
}
},
"subnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet1AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.0.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet1"
}
]
}
},
"subnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet2AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.1.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet2"
}
]
}
},
"subnet3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet3AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.2.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet2"
}
]
}
},
"myigw": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": "myigw"
}
]
}
},
"AttachGateway": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "mynetwork"
},
"InternetGatewayId": {
"Ref": "myigw"
}
}
},
"myroutetable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "mynetwork"
},
"Tags": [
{
"Key": "Name",
"Value": "my rt"
}
]
}
},
"routeName": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "myroutetable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "myigw"
}
}
},
"routeTableAssocName": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "subnet1"
},
"RouteTableId": {
"Ref": "myroutetable"
}
}
},
"InstanceSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow ssh to client host",
"VpcId": {
"Ref": "mynetwork"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"CidrIp": "0.0.0.0/0"
}
]
}
},
"myweb": {
"Type": "AWS::EC2::Instance",
"Properties": {
"KeyName": {
"Ref": "keypair"
},
"ImageId": {
"Fn::FindInMap": [
"AMIRegionMap",
{
"Ref": "AWS::Region"
},
"ubuntu18"
]
},
"InstanceType": {
"Ref": "instancetype"
},
"NetworkInterfaces": [
{
"AssociatePublicIpAddress": "true",
"DeviceIndex": "0",
"GroupSet": [
{
"Ref": "InstanceSecurityGroup"
}
],
"SubnetId": {
"Ref": "subnet1"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": "myweb"
}
]
}
}
},
"Outputs": {
"publicip": {
"Value": {
"Fn::GetAtt": [
"myweb",
"PublicIp"
]
}
},
"privateip": {
"Value": {
"Fn::GetAtt": [
"myweb",
"PrivateIp"
]
}
}
}
}
- For the conditions we have a set of functions Refer Here
Scenario
- Write a template to create an vpc ec2 instance and when the user chooses an option to Dev from the environment parameter create an extra ec2 machine and when the user chooses to Test from the environment parameter create an extra subnet
- Look into conditions section, Resources "extraweb" and "subnet" and outputsection
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template is written for learning and it creates s3 bucket and ec2 instance",
"Parameters": {
"environment": {
"Description": "choose",
"Type": "String",
"AllowedValues": [
"Dev",
"Test"
]
},
"keypair": {
"Description": "key pair for ec2 instance",
"Type": "AWS::EC2::KeyPair::KeyName"
},
"instancetype": {
"Type": "String",
"AllowedValues": [
"t2.micro",
"t2.nano"
]
},
"subnet1AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"subnet2AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
},
"subnet3AZ": {
"Type": "AWS::EC2::AvailabilityZone::Name"
}
},
"Conditions": {
"CreateDev": {
"Fn::Equals": [
{
"Ref": "environment"
},
"Dev"
]
},
"CreateTest": {
"Fn::Equals": [
{
"Ref": "environment"
},
"Test"
]
}
},
"Mappings": {
"AMIRegionMap": {
"us-west-2": {
"ubuntu18": "ami-003634241a8fcdec0"
},
"us-west-1": {
"ubuntu18": "ami-0f56279347d2fa43e"
},
"us-east-2": {
"ubuntu18": "ami-07c1207a9d40bc3bd"
},
"us-east-1": {
"ubuntu18": "ami-085925f297f89fce1"
},
"ap-south-1": {
"ubuntu18": "ami-0b44050b2d893d5f7"
}
}
},
"Resources": {
"mynetwork": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.10.0.0/16",
"Tags": [
{
"Key": "Name",
"Value": "my network"
}
]
}
},
"subnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet1AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.0.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet1"
}
]
}
},
"subnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet2AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.1.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet2"
}
]
}
},
"subnet3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet3AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.2.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet3"
}
]
}
},
"subnet4": {
"Type": "AWS::EC2::Subnet",
"Condition": "CreateTest",
"Properties": {
"AvailabilityZone": {
"Ref": "subnet3AZ"
},
"VpcId": {
"Ref": "mynetwork"
},
"CidrBlock": "10.10.2.0/24",
"Tags": [
{
"Key": "Name",
"Value": "subnet4"
}
]
}
},
"myigw": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": "myigw"
}
]
}
},
"AttachGateway": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "mynetwork"
},
"InternetGatewayId": {
"Ref": "myigw"
}
}
},
"myroutetable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "mynetwork"
},
"Tags": [
{
"Key": "Name",
"Value": "my rt"
}
]
}
},
"routeName": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "myroutetable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "myigw"
}
}
},
"routeTableAssocName": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "subnet1"
},
"RouteTableId": {
"Ref": "myroutetable"
}
}
},
"InstanceSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow ssh to client host",
"VpcId": {
"Ref": "mynetwork"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"CidrIp": "0.0.0.0/0"
}
]
}
},
"myweb": {
"Type": "AWS::EC2::Instance",
"Properties": {
"KeyName": {
"Ref": "keypair"
},
"ImageId": {
"Fn::FindInMap": [
"AMIRegionMap",
{
"Ref": "AWS::Region"
},
"ubuntu18"
]
},
"InstanceType": {
"Ref": "instancetype"
},
"NetworkInterfaces": [
{
"AssociatePublicIpAddress": "true",
"DeviceIndex": "0",
"GroupSet": [
{
"Ref": "InstanceSecurityGroup"
}
],
"SubnetId": {
"Ref": "subnet1"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": "myweb"
}
]
}
},
"extraweb": {
"Type": "AWS::EC2::Instance",
"Condition": "CreateDev",
"Properties": {
"KeyName": {
"Ref": "keypair"
},
"ImageId": {
"Fn::FindInMap": [
"AMIRegionMap",
{
"Ref": "AWS::Region"
},
"ubuntu18"
]
},
"InstanceType": {
"Ref": "instancetype"
},
"NetworkInterfaces": [
{
"AssociatePublicIpAddress": "true",
"DeviceIndex": "0",
"GroupSet": [
{
"Ref": "InstanceSecurityGroup"
}
],
"SubnetId": {
"Ref": "subnet1"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": "myweb"
}
]
}
}
},
"Outputs": {
"publicip": {
"Value": {
"Fn::GetAtt": [
"myweb",
"PublicIp"
]
}
},
"privateip": {
"Value": {
"Fn::GetAtt": [
"myweb",
"PrivateIp"
]
}
},
"publicipextra" : {
"Value" : {
"Fn::GetAtt": [
"extraweb",
"PublicIp"
]
},
"Condition": "CreateDev"
}
}
}