Create VPC and Private Public Subnet Using AWS Cloudformation

Today we will learn, how to create AWS Cloudformation script. So in this script, we will create a VPC and two subnets. One public subnet and one private subnet.

First, we have to define the script Cloudformation template format version.

1{
2    "AWSTemplateFormatVersion": "2010-09-09",
3    "Description" : "Create 8 private subnet for servers and 1 public subnet for NAT gateway. ",
4
5}

Note: You don't have to change anything except the "Description". In Description, you can give the detail about the template.

We will now create a Parameters group, Where end-user can put their inputs and spin up the infrastructure.

Now, Create a parameter for VPC. So that, user can define VPC CIDR and VPC name:

 1"Parameters": {
 2      "myVPCcidr": {
 3                  "Description": "Enter VPC CIDR",
 4            "Type": "String",
 5            "MinLength": "9",
 6            "MaxLength": "18",
 7            "Default": "10.0.0.0/16",
 8            "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
 9            "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
10                },
11      "myVPCName":{
12             "Description":"Enter the name of  Your VPC",
13               "Type":"String",
14           "ConstraintDescription": "This name is will assign to Name tag"
15            }
16      }

Similarly, we will create the private subnet parameters in "Parameters":

 1"myPrivateSubnetCIDR" : {
 2     "Description": "Enter your private subnet CIDR here",
 3     "Type": "String",
 4     "MinLength": "9",
 5     "MaxLength": "18",
 6     "Default": "10.0.1.0/24",
 7     "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
 8     "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
 9 },
10 "myPrivateSubnetName":{
11      "Description":"Enter the name of Private Subnet",
12      "Type":"String",
13      "ConstraintDescription": "This name is will assign to Name tag"
14   },
15"myPrivateSubnetAZ" : {
16       "Description":"Select the AZ in which you want to create the Private subnet:",
17       "Type": "AWS::EC2::AvailabilityZone::Name"
18     }

Now for public subnet:

 1"myPublicSubnetCIDR" : {
 2     "Description": "Enter your public subnet CIDR here",
 3     "Type": "String",
 4     "MinLength": "9",
 5     "MaxLength": "18",
 6     "Default": "10.0.1.0/24",
 7     "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
 8     "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
 9 },
10 "myPublicSubnetName":{
11      "Description":"Enter the name of Public Subnet",
12      "Type":"String",
13      "ConstraintDescription": "This name is will assign to Name tag"
14   },
15"myPublicSubnetAZ" : {
16       "Description":"Select the AZ in which you want to create the Public subnet:",
17       "Type": "AWS::EC2::AvailabilityZone::Name"
18     }

So, we will declare the parameter for RouteTable (public and private both), Internet Gateway (IGW), NAT Gateway and EIP (this will be attached to NAT Gateway). Here we will ask the Name for all the resources, which will be associated with "Name" tag:

 1"myPrivateRouteName":{
 2         "Description":"Enter the name of Private RouteTable ",
 3         "Type":"String"
 4      },
 5"myPublicRouteName":{
 6         "Description":"Enter the name of Public RouteTable name",
 7         "Type":"String"
 8      },
 9"myIGWName":{
10         "Description":"Enter the name of IGW",
11         "Type":"String"
12      },
13"myNATName":{
14         "Description":"Enter the name of Private RouteTable",
15         "Type":"String"
16      },
17"myNATEIPName":{
18         "Description":"Enter the name of NAT EIP",
19         "Type":"String"
20      }
So, now all parameters is defined.

Let's do the formatting of parameters:

 1"Metadata" : {
 2  "AWS::CloudFormation::Interface" : {
 3       "ParameterGroups" : [ {
 4        "Label" : { "default" : "VPC Details" },
 5        "Parameters" : [ "myAWSVpcId" ]
 6      },
 7      {
 8        "Label" : { "default" : "Private Subnet Details" },
 9        "Parameters" : [ "myPrivateSubnetCIDR","myPrivateSubnetAZ","myPrivateSubnetName" ]
10      },
11      {
12        "Label" : { "default" : "Public Subnet Details" },
13        "Parameters" : [ "myPublicSubnetCIDR","myPublicSubnetAZ","myPublicSubnetName" ]
14      }]
15
16    }
17  }
Formatting is also done.

Let's start attaching the resources:

 1"Resources" : {
 2        "myVPC" : {
 3               "Type" : "AWS::EC2::VPC",
 4               "Properties" : {
 5                    "CidrBlock" : { "Ref" : "myVPCcidr" },
 6                    "EnableDnsSupport" : "true",
 7                    "EnableDnsHostnames" : "true",
 8                    "InstanceTenancy" : "default",
 9                    "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myVPCName" }} ]
10                  }
11                }
12
13              }

VPC is created. Similar way, Let's start creating Subnet:

 1
 2  "myVPCprivateSubnet": {
 3            "Type": "AWS::EC2::Subnet",
 4            "Properties": {
 5                "VpcId": {
 6                    "Ref": "myVPC"
 7                },
 8                "CidrBlock": { "Ref" : "myPrivateSubnetCIDR" },
 9                "AvailabilityZone": { "Ref" : "myPrivateSubnetAZ" },
10                "Tags": [{
11                    "Key": "Name",
12                    "Value": { "Ref" : "myPrivateSubnetName" }
13                }]
14            }
15        },
16    "myVPCpublicSubnet": {
17                "Type": "AWS::EC2::Subnet",
18                "Properties": {
19                    "VpcId": {
20                        "Ref": "myVPC"
21                    },
22                    "CidrBlock": { "Ref" : "myPublicSubnetCIDR" },
23                    "AvailabilityZone": { "Ref" : "myPublicSubnetAZ" },
24                    "Tags": [{
25                        "Key": "Name",
26                        "Value": { "Ref" : "myPublicSubnetName" }
27                    }]
28                }
29            }

Till now, we have written the script for VPC and subnet. Now we will write the script to create two Route Table (one for Private Subnet and another for Public Subnet).

 1"myPublicRoute" : {
 2               "Type" : "AWS::EC2::RouteTable",
 3               "Properties" :
 4                 {
 5                    "VpcId" : { "Ref" : "myVPC" },
 6                    "Tags" : [ { "Key" : "Name", "Value" : { "Ref" : "myPublicRouteName" } }]
 7                 }
 8                },
 9  "myPrivateRoute" : {
10                "Type" : "AWS::EC2::RouteTable",
11                "Properties" :
12                  {
13                   "VpcId" : { "Ref" : "myVPC" },
14                   "Tags" : [ { "Key" : "Name", "Value" : { "Ref" : "myPublicRouteName" } }]
15                  }
16              }

Route Table is created, So now we have to associate it with the subnet. Let associate it:

 1  "PublicSubnetRouteTableAssociation" : {
 2                       "Type" : "AWS::EC2::SubnetRouteTableAssociation",
 3                       "Properties" :
 4                       {
 5                          "SubnetId" : { "Ref" : "myVPCpublicSubnet" },
 6                          "RouteTableId" : { "Ref" : "myPublicRoute" }
 7                       }
 8                    },
 9  "PrivateSubnet1RouteTableAssociation" : {
10                       "Type" : "AWS::EC2::SubnetRouteTableAssociation",
11                       "Properties" : {
12                          "SubnetId" : { "Ref" : "myVPCprivateSubnet"},
13                          "RouteTableId" : { "Ref" : "myPrivateRoute" }
14                       }
15                    }

Now, Route table is also associated with the subnet. Let's create an IGW ( Internet Gateway ) and attached it to the public route table.

 1
 2"myInternetGateway" : {
 3                      "Type" : "AWS::EC2::InternetGateway",
 4                      "Properties" : {
 5                        "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myIGWName" }}]
 6                      }
 7                },
 8        "AttachIGWGateway" : {
 9                       "Type" : "AWS::EC2::VPCGatewayAttachment",
10                       "Properties" : {
11                          "VpcId" : { "Ref" : "myVPC" },
12                          "InternetGatewayId" : { "Ref" : "myInternetGateway" }
13                        }
14                },
15        "AttachedtoPublicRoute" : {
16                   "Type" : "AWS::EC2::Route",
17                   "DependsOn" : "myInternetGateway",
18                   "Properties" : {
19                      "RouteTableId" : { "Ref" : "myPublicRoute" },
20                      "DestinationCidrBlock" : "0.0.0.0/0",
21                      "GatewayId" : { "Ref" : "myInternetGateway" }
22                   }
23            }

Now let's create NAT Gateway and associate it with private Route table:

 1"myAWSVPCNAT" : {
 2       "Type" : "AWS::EC2::NatGateway",
 3       "Properties" : {
 4          "AllocationId" : { "Fn::GetAtt" : ["EIP", "AllocationId"]},
 5          "SubnetId" : { "Ref" : "myVPCpublicSubnet"},
 6          "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myNATName" } } ]
 7         }
 8    },
 9    "EIP" : {
10       "Type" : "AWS::EC2::EIP",
11       "Properties" : {
12          "Domain" : "vpc",
13          "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myNATEIPName" } } ]
14       }
15    },
16    "AttachNATtoPrivateRoute" : {
17       "Type" : "AWS::EC2::Route",
18       "Properties" : {
19          "RouteTableId" : { "Ref" : "myPrivateRoute" },
20          "DestinationCidrBlock" : "0.0.0.0/0",
21          "NatGatewayId" : { "Ref" : "myAWSVPCNAT" }
22       }
23    }

Now, all done. Let's combine all the codes and make it one.

  1
  2{
  3    "AWSTemplateFormatVersion": "2010-09-09",
  4    "Description" : "Create a VPC and two subnet (public and private both).",
  5    "Parameters": {
  6                    "myVPCcidr": {
  7                              "Description": "Enter VPC CIDR",
  8                        "Type": "String",
  9                        "MinLength": "9",
 10                        "MaxLength": "18",
 11                        "Default": "10.0.0.0/16",
 12                        "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
 13                        "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
 14                            },
 15                    "myVPCName":{
 16                         "Description":"Enter the name of  Your VPC",
 17                           "Type":"String",
 18                       "ConstraintDescription": "This name is will assign to Name tag"
 19                        },
 20                    "myPrivateSubnetCIDR" : {
 21                         "Description": "Enter your private subnet CIDR here",
 22                         "Type": "String",
 23                         "MinLength": "9",
 24                         "MaxLength": "18",
 25                         "Default": "10.0.1.0/24",
 26                         "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
 27                         "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
 28                      },
 29                    "myPrivateSubnetName":{
 30                          "Description":"Enter the name of Private Subnet",
 31                          "Type":"String",
 32                          "ConstraintDescription": "This name is will assign to Name tag"
 33                       },
 34                    "myPrivateSubnetAZ" : {
 35                           "Description":"Select the AZ in which you want to create the Private subnet:",
 36                           "Type": "AWS::EC2::AvailabilityZone::Name"
 37                         },
 38                    "myPublicSubnetCIDR" : {
 39                             "Description": "Enter your public subnet CIDR here",
 40                             "Type": "String",
 41                             "MinLength": "9",
 42                             "MaxLength": "18",
 43                             "Default": "10.0.1.0/24",
 44                             "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
 45                             "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
 46                         },
 47                    "myPublicSubnetName":{
 48                          "Description":"Enter the name of Public Subnet",
 49                          "Type":"String",
 50                          "ConstraintDescription": "This name is will assign to Name tag"
 51                       },
 52                    "myPublicSubnetAZ" : {
 53                           "Description":"Select the AZ in which you want to create the Public subnet:",
 54                           "Type": "AWS::EC2::AvailabilityZone::Name"
 55                         },
 56                    "myPrivateRouteName":{
 57                     "Description":"Enter the name of Private RouteTable ",
 58                     "Type":"String"
 59                  },
 60                    "myPublicRouteName":{
 61                             "Description":"Enter the name of Public RouteTable name",
 62                             "Type":"String"
 63                          },
 64                    "myIGWName":{
 65                             "Description":"Enter the name of IGW",
 66                             "Type":"String"
 67                          },
 68                    "myNATName":{
 69                             "Description":"Enter the name of Private RouteTable",
 70                             "Type":"String"
 71                          },
 72                    "myNATEIPName":{
 73                 "Description":"Enter the name of NAT EIP",
 74                 "Type":"String"
 75      }
 76    },
 77    "Metadata" : {
 78              "AWS::CloudFormation::Interface" :
 79                  {
 80                   "ParameterGroups" : [ {
 81                    "Label" : { "default" : "VPC Details" },
 82                    "Parameters" : [ "myVPCcidr","myVPCName" ]
 83                  },
 84                  {
 85                    "Label" : { "default" : "Private Subnet Details" },
 86                    "Parameters" : [ "myPrivateSubnetCIDR","myPrivateSubnetAZ","myPrivateSubnetName" ]
 87                  },
 88                  {
 89                    "Label" : { "default" : "Public Subnet Details" },
 90                    "Parameters" : [ "myPublicSubnetCIDR","myPublicSubnetAZ","myPublicSubnetName" ]
 91
 92                  },
 93                  {
 94                    "Label" : { "default" : "Other resources tag name" },
 95                    "Parameters" : [ "myPrivateRouteName","myPublicRouteName","myIGWName","myNATName","myNATEIPName" ]
 96
 97                  }
 98                  ]
 99                }
100
101  },
102  "Resources" : {
103                    "myVPC" : {
104                               "Type" : "AWS::EC2::VPC",
105                               "Properties" : {
106                                    "CidrBlock" : { "Ref" : "myVPCcidr" },
107                                    "EnableDnsSupport" : "true",
108                                    "EnableDnsHostnames" : "true",
109                                    "InstanceTenancy" : "default",
110                                    "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myVPCName" }} ]
111                                  }
112                                },
113                    "myVPCprivateSubnet": {
114                            "Type": "AWS::EC2::Subnet",
115                            "Properties": {
116                                "VpcId": {
117                                    "Ref": "myVPC"
118                                },
119                                "CidrBlock": { "Ref" : "myPrivateSubnetCIDR" },
120                                "AvailabilityZone": { "Ref" : "myPrivateSubnetAZ" },
121                                "Tags": [{
122                                    "Key": "Name",
123                                    "Value": { "Ref" : "myPrivateSubnetName" }
124                                }]
125                            }
126                        },
127                    "myVPCpublicSubnet": {
128                                "Type": "AWS::EC2::Subnet",
129                                "Properties": {
130                                    "VpcId": {
131                                        "Ref": "myVPC"
132                                    },
133                                    "CidrBlock": { "Ref" : "myPublicSubnetCIDR" },
134                                    "AvailabilityZone": { "Ref" : "myPublicSubnetAZ" },
135                                    "Tags": [{
136                                        "Key": "Name",
137                                        "Value": { "Ref" : "myPublicSubnetName" }
138                                    }]
139                                }
140                            },
141                    "myPublicRoute" : {
142                               "Type" : "AWS::EC2::RouteTable",
143                               "Properties" :
144                                 {
145                                    "VpcId" : { "Ref" : "myVPC" },
146                                    "Tags" : [ { "Key" : "Name", "Value" : { "Ref" : "myPublicRouteName" } }]
147                                 }
148                                },
149                    "myPrivateRoute" : {
150                                "Type" : "AWS::EC2::RouteTable",
151                                "Properties" :
152                                  {
153                                   "VpcId" : { "Ref" : "myVPC" },
154                                   "Tags" : [ { "Key" : "Name", "Value" : { "Ref" : "myPublicRouteName" } }]
155                                  }
156                              },
157                    "PublicSubnetRouteTableAssociation" : {
158                                       "Type" : "AWS::EC2::SubnetRouteTableAssociation",
159                                       "Properties" :
160                                       {
161                                          "SubnetId" : { "Ref" : "myVPCpublicSubnet" },
162                                          "RouteTableId" : { "Ref" : "myPublicRoute" }
163                                       }
164                                    },
165                    "PrivateSubnet1RouteTableAssociation" : {
166                                       "Type" : "AWS::EC2::SubnetRouteTableAssociation",
167                                       "Properties" : {
168                                          "SubnetId" : { "Ref" : "myVPCprivateSubnet"},
169                                          "RouteTableId" : { "Ref" : "myPrivateRoute" }
170                                       }
171                                    },
172                    "myInternetGateway" : {
173                                      "Type" : "AWS::EC2::InternetGateway",
174                                      "Properties" : {
175                                        "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myIGWName" }}]
176                                      }
177                                },
178                    "AttachIGWGateway" : {
179                                       "Type" : "AWS::EC2::VPCGatewayAttachment",
180                                       "Properties" : {
181                                          "VpcId" : { "Ref" : "myVPC" },
182                                          "InternetGatewayId" : { "Ref" : "myInternetGateway" }
183                                        }
184                                },
185                    "AttachedtoPublicRoute" : {
186                                   "Type" : "AWS::EC2::Route",
187                                   "DependsOn" : "myInternetGateway",
188                                   "Properties" : {
189                                      "RouteTableId" : { "Ref" : "myPublicRoute" },
190                                      "DestinationCidrBlock" : "0.0.0.0/0",
191                                      "GatewayId" : { "Ref" : "myInternetGateway" }
192                                   }
193                            },
194                    "myAWSVPCNAT" : {
195                       "Type" : "AWS::EC2::NatGateway",
196                       "Properties" : {
197                          "AllocationId" : { "Fn::GetAtt" : ["EIP", "AllocationId"]},
198                          "SubnetId" : { "Ref" : "myVPCpublicSubnet"},
199                          "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myNATName" } } ]
200                         }
201                    },
202                    "EIP" : {
203                       "Type" : "AWS::EC2::EIP",
204                       "DependsOn": "myVPC",
205                       "Properties" : {
206                          "Domain" : "vpc",
207                          "Tags" : [ {"Key" : "Name", "Value" : { "Ref" : "myNATEIPName" } } ]
208                       }
209                    },
210                    "AttachNATtoPrivateRoute" : {
211                       "Type" : "AWS::EC2::Route",
212                       "Properties" : {
213                          "RouteTableId" : { "Ref" : "myPrivateRoute" },
214                          "DestinationCidrBlock" : "0.0.0.0/0",
215                          "NatGatewayId" : { "Ref" : "myAWSVPCNAT" }
216                       }
217                    }
218
219
220    }
221
222}

Lastly, just open your AWS console and then select CloudFormation service. Upload this script on the stack and run the stack.

I :heart: AWS! :smile: Enjoy