Launch an EC2 instance in an existing VPC using CloudFormation
In this post, I will help you launch an EC2 instance in an existing VPC using CloudFormation. I will also share the template in YAML as well as JSON for your convenience.
Don’t want to miss any posts from us? join us on our Facebook group, and follow us on Facebook, Twitter, LinkedIn, and Instagram. You can also subscribe to our newsletter below to not miss any updates from us.
Prerequisite
- An AWS Account: See how to set up a free tier AWS account in right way
- Basic Knowledge of EC2 and CloudFormation
- Basic Knowledge of YAML/JSON
To be honest, I have seen many people asking this question on various online forums.
There is so much confusion around launching an EC2 in a VPC. And confusion is so obvious, especially for beginners. So why not start with the confusion itself? 🙂
Why Confusion?
Well, If you have launched an EC2 instance from the AWS EC2 console. You might remember that, In the network, we get to select a VPC and then subnet in the VPC in which you would like to launch the instance.
However, there is no VPC or VpcId parameter for AWS::EC2::Instance resource in CloudFormation.
You might wonder, How do we create an instance in a VPC then?
Don’t worry It’s simple.
SubnetId represents a VPC when creating an EC2 instance using Cloud Formation. Therefore need to specify the SubnetId parameter to launch the instance in VPC.
What’s even more confusing?
There are two places where SubnetId can be specified in a AWS::EC2::Instance resource.
- On Instance Level
- On the Network Interface level
Let’s understand with an example for each one of these.
Instance Level SubnetId in an AWS::EC2::Instance resource
DemoInstance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
AvailabilityZone: !Ref AvailabilityZone
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref DemoSecurityGroup
SubnetId: !Ref SubnetId
or
Network Interface Level SubnetId in an AWS::EC2::Instance resource
DemoInstance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
AvailabilityZone: !Ref AvailabilityZone
KeyName: !Ref KeyName
NetworkInterfaces:
- DeviceIndex: 0
AssociatePublicIpAddress: true
DeleteOnTermination: true
SubnetId: !Ref SubnetId
GroupSet:
- !Ref DemoSecurityGroup
Where to specify SubnetId?
Have you got the requirement to attach a network interface to your instance?
Yes? -> Use SubnetId on the interface level
No? -> Use SubnetId on the instance level
Please note that only one out of two can be specified. If you try to use SubnetId on the instance level as well as the network interface level. You will get the below error.
Network interfaces and an instance-level subnet ID may not be specified on the same request (Service: AmazonEC2; Status Code: 400; Error Code: InvalidParameterCombination)
The same applies to security groups.
- Using Network Interface -> Use GroupSet parameter on the network interface level
- Not using Network Interface -> Use SecurityGroupIds parameter on instance level
If you try to use it at both places, you will get errors like
Network interfaces and an instance-level security groups may not be specified on the same request (Service: AmazonEC2; Status Code: 400)
Don’t worry much. I am going to share a fully working template for both cases below.
Template Example to Launch an EC2 instance in an existing VPC using CloudFormation in YAML
Please note that as we discussed above, we will be having two templates here.
- Without Network Interface
- With Network Interface
Without Network Interface:
AWSTemplateFormatVersion: '2010-09-09'
Description: Template to Create an EC2 instance in a VPC
Parameters:
ImageId:
Type: String
Description: 'Linux 2 AMI for Ireland eu-west1 Region'
Default: 'ami-0fc970315c2d38f01'
VpcId:
Type: String
Description: VPC id
Default: vpc-012b3456f0123456f4
SubnetId:
Type: String
Description: Subnet in which to launch an EC2
Default: subnet-0123ec12fd9af123b
AvailabilityZone:
Type: String
Description: Availability Zone into which instance will launch
Default: eu-west-1c
InstanceType:
Type: String
Description: Choosing t2 micro because it is free
Default: t2.micro
KeyName:
Description: SSH Keypair to login to the instance
Type: AWS::EC2::KeyPair::KeyName
Default: demokeypair
Resources:
DemoInstance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
AvailabilityZone: !Ref AvailabilityZone
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref DemoSecurityGroup
SubnetId: !Ref SubnetId
DemoSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
VpcId: !Ref VpcId
GroupDescription: SG to allow SSH access via port 22
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: '0.0.0.0/0'
Tags:
- Key: Name
Value: SSH-SG
Outputs:
DemoInstanceId:
Description: Instance Id
Value: !Ref DemoInstance
With Network Interface:
AWSTemplateFormatVersion: '2010-09-09'
Description: Template to Create an EC2 instance in a VPC
Parameters:
ImageId:
Type: String
Description: 'Linux 2 AMI for Ireland eu-west1 Region'
Default: 'ami-0fc970315c2d38f01'
VpcId:
Type: String
Description: VPC id
Default: vpc-012b3456f0123456f4
SubnetId:
Type: String
Description: Subnet in which to launch an EC2
Default: subnet-0123ec12fd9af123b
AvailabilityZone:
Type: String
Description: Availability Zone into which instance will launch
Default: eu-west-1c
InstanceType:
Type: String
Description: Choosing t2 micro because it is free
Default: t2.micro
KeyName:
Description: SSH Keypair to login to the instance
Type: AWS::EC2::KeyPair::KeyName
Default: demokeypair
Resources:
DemoInstance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
AvailabilityZone: !Ref AvailabilityZone
KeyName: !Ref KeyName
NetworkInterfaces:
- DeviceIndex: 0
AssociatePublicIpAddress: true
DeleteOnTermination: true
SubnetId: !Ref SubnetId
GroupSet:
- !Ref DemoSecurityGroup
DemoSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
VpcId: !Ref VpcId
GroupDescription: SG to allow SSH access via port 22
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: '0.0.0.0/0'
Tags:
- Key: Name
Value: SSH-SG
Outputs:
DemoInstanceId:
Description: Instance Id
Value: !Ref DemoInstance
Template Example to Launch an EC2 instance in an existing VPC using CloudFormation in JSON
Same as YAML here also we have two templates. By the way, if you have got a template in YAML or JSON, you can convert in to JSON or YAML. Here is a post on How to Convert a CloudFormation Template from YAML to JSON.
Without Network Interface:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Template to Create an EC2 instance in a VPC",
"Parameters": {
"ImageId": {
"Type": "String",
"Description": "Linux 2 AMI for Ireland eu-west1 Region",
"Default": "ami-0fc970315c2d38f01"
},
"VpcId": {
"Type": "String",
"Description": "VPC id",
"Default": "vpc-012b3456f0123456f4"
},
"SubnetId": {
"Type": "String",
"Description": "Subnet in which to launch an EC2",
"Default": "subnet-0123ec12fd9af123b"
},
"AvailabilityZone": {
"Type": "String",
"Description": "Availability Zone into which instance will launch",
"Default": "eu-west-1c"
},
"InstanceType": {
"Type": "String",
"Description": "Choosing t2 micro because it is free",
"Default": "t2.micro"
},
"KeyName": {
"Description": "SSH Keypair to login to the instance",
"Type": "AWS::EC2::KeyPair::KeyName",
"Default": "demokeypair"
}
},
"Resources": {
"DemoInstance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": {
"Ref": "ImageId"
},
"InstanceType": {
"Ref": "InstanceType"
},
"AvailabilityZone": {
"Ref": "AvailabilityZone"
},
"KeyName": {
"Ref": "KeyName"
},
"SecurityGroupIds": [
{
"Ref": "DemoSecurityGroup"
}
],
"SubnetId": {
"Ref": "SubnetId"
}
}
},
"DemoSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"VpcId": {
"Ref": "VpcId"
},
"GroupDescription": "SG to allow SSH access via port 22",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "0.0.0.0/0"
}
],
"Tags": [
{
"Key": "Name",
"Value": "SSH-SG"
}
]
}
}
},
"Outputs": {
"DemoInstanceId": {
"Description": "Instance Id",
"Value": {
"Ref": "DemoInstance"
}
}
}
}
With Network Interface:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Template to Create an EC2 instance in a VPC",
"Parameters": {
"ImageId": {
"Type": "String",
"Description": "Linux 2 AMI for Ireland eu-west1 Region",
"Default": "ami-0fc970315c2d38f01"
},
"VpcId": {
"Type": "String",
"Description": "VPC id",
"Default": "vpc-012b3456f0123456f4"
},
"SubnetId": {
"Type": "String",
"Description": "Subnet in which to launch an EC2",
"Default": "subnet-0123ec12fd9af123b"
},
"AvailabilityZone": {
"Type": "String",
"Description": "Availability Zone into which instance will launch",
"Default": "eu-west-1c"
},
"InstanceType": {
"Type": "String",
"Description": "Choosing t2 micro because it is free",
"Default": "t2.micro"
},
"KeyName": {
"Description": "SSH Keypair to login to the instance",
"Type": "AWS::EC2::KeyPair::KeyName",
"Default": "demokeypair"
}
},
"Resources": {
"DemoInstance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": {
"Ref": "ImageId"
},
"InstanceType": {
"Ref": "InstanceType"
},
"AvailabilityZone": {
"Ref": "AvailabilityZone"
},
"KeyName": {
"Ref": "KeyName"
},
"NetworkInterfaces": [
{
"DeviceIndex": 0,
"AssociatePublicIpAddress": true,
"DeleteOnTermination": true,
"SubnetId": {
"Ref": "SubnetId"
},
"GroupSet": [
{
"Ref": "DemoSecurityGroup"
}
]
}
]
}
},
"DemoSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"VpcId": {
"Ref": "VpcId"
},
"GroupDescription": "SG to allow SSH access via port 22",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "0.0.0.0/0"
}
],
"Tags": [
{
"Key": "Name",
"Value": "SSH-SG"
}
]
}
}
},
"Outputs": {
"DemoInstanceId": {
"Description": "Instance Id",
"Value": {
"Ref": "DemoInstance"
}
}
}
}
Steps to Create a Stack
Once you have got your required template from above. Change the parameter value such as SubnetId, VpcId etc. as per your requirement. Save it with .yml or .json as per the template and follow the below steps.
- Login to AWS Management Console, navigate to CloudFormation and click on Create stack
- Click on “Upload a template file”, upload ec2instance.yml or ec2instance.json and click Next
- Enter the stack name and click on Next. In the configuration, keep everything as default and click on Next.
- In the events tab of the stack, you can view the status.
- Once the stack is successfully created, go to the Resources tab(Right next to Event) and click on your instance resource.
- It will take you to your instance. You can verify all the details there.
If you like doing it via CLI, checkout my post on how to deploy a CloudFormation template in AWS using CLI.
Conclusion
Let’s sum up what we did in this post.
- We discussed why launching an EC2 instance in a VPC becomes confusing at times
- We also saw how to correctly create an EC2 instance in VPC
- Finally, I shared a working template in YAML as well as JSON
I hope you found this post helpful.
Enjoyed the content?
Subscribe to our newsletter below to get awesome AWS learning materials delivered straight to your inbox.
Don’t forget to motivate me by-
- Adding a comment below on what you liked and what can be improved.
- Follow us on
- Subscribe to our newsletter to get notified each time we post new content
- Share this post with your friends
Suggested Read:
- Understand IAM PassRole to Secure your AWS Infrastructure
- How to Create S3 Bucket using CloudFomation
- Most Common types of Cyber Attacks in 2020
- Create AWS Lambda using Java- Step by Step
- Provision ACM certificate using CloudFormation
- Create SSM Parameter using CloudFormation
- Create API Gateway Custom Domain using CloudFormation
- Basics of Serverless Computing
2 thoughts on “How to launch an EC2 instance in an existing VPC using CloudFormation”
Thanks for a great template! I appreciated information on launching EC2 instance with existing VPC. I see a lot of templates where it’s being launched with a new VPC (nothing wrong with that).
Keep up the great work and hope to see more!
Thank you EU for the feedback. We will keep trying to write ore and more 🙂