Creating VPC and using bastion host for private subnet using terraform

What is Terraform ?

Use Infrastructure as Code to provision and manage any cloud, infrastructure, or service. Terraform users define infrastructure in a simple, human-readable configuration language called HCL (HashiCorp Configuration Language). Users can write unique HCL configuration files or borrow existing templates from the public module registry.

What is VPC ?

Amazon Virtual Private Cloud (Amazon VPC) lets you provision a logically isolated section of the AWS Cloud where you can launch AWS resources in a virtual network that you define. You have complete control over your virtual networking environment, including selection of your own IP address range, creation of subnets, and configuration of route tables and network gateways. You can use both IPv4 and IPv6 in your VPC for secure and easy access to resources and applications.

Task details to be performed are as follows :-

Perform task-3 with an additional feature to be added that is NAT Gateway to provide the internet access to instances running in the private subnet.

Performing the following steps:
1. Write an Infrastructure as code using terraform, which automatically create a VPC.
2. In that VPC we have to create 2 subnets:
a) public subnet [ Accessible for Public World! ]
b) private subnet [ Restricted for Public World! ]
3. Create a public facing internet gateway for connect our VPC/Network to the internet world and attach this gateway to our VPC.
4. Create a routing table for Internet gateway so that instance can connect to outside world, update and associate it with public subnet.
5. Create a NAT gateway for connect our VPC/Network to the internet world and attach this gateway to our VPC in the public network
6. Update the routing table of the private subnet, so that to access the internet it uses the nat gateway created in the public subnet
7. Launch an ec2 instance which has Wordpress setup already having the security group allowing port 80 so that our client can connect to our wordpress site. Also attach the key to instance for further login into it.
8. Launch an ec2 instance which has MYSQL setup already with security group allowing port 3306 in private subnet so that our wordpress vm can connect with the same. Also attach the key with the same.

Note: Wordpress instance has to be part of public subnet so that our client can connect our site.
mysql instance has to be part of private subnet so that outside world can’t connect to it.
Don’t forgot to add auto ip assign and auto dns name assignment option to be enabled.

=> So stepwise explanation and output from the above task details is below :-

Firstly, we would be creating Iam User on AWS website, if you dont know how to create this user, kindly refer to this medium story, here I have breifly explained how to create Iam user, as it is used to access AWS in CLI amd configure it using “aws configure” command.

After logging in using CLI, now we have to write a code for our deployment, I have written this and will be sharing the github link for this terraform code file named “”.

Create a folder with your desired name and in this folder, create a file with any name but with an extension as .tf . and usind cd commands take your cmd to the folder where you created it.

→ Initially, in this file, we have to add a provider like here we are using AWS as our provider as AWS is providing resources to us and we are accessing theirs.

→ Now, we will create a key pair, which will be used for authentication for our instance, if we try to do ssh and access this instance.

→ Now, we will create a VPC which is NAAS in AWS and our instanve will be created in this customized VPC created accordind to our used cases.

  • In this VPC, all instance created will be in cidr_block’s IP Range, no instance can go out of this range in terms of IP; these IP, we will be specifying more when we create subnets in this VPC.

→ Now, we will create 2 subnets in this VPC , one private and one public

  • Wordpress Instance will be created in public subnet and mysql instance will be created in private subnet.
  • Public Subnet means that all instances in this subnet will be available in world and accessible to internet with both SNATing and DNATing. Here, IP range in this subnet is specified with to , but AWS uses 5 IP’s for its own use, so only 51 IP’s are available to us. We have specified availability zone in this subnet like all instances must be ap-south-1a.
  • Whereas Private Subnet means that all instances in this subnet will only accessible to a team or organization and we will be hidden from outside world, it means that anyone from outside world will be unable to access the instances created in this subnet. Here, IP range in this subnet is specified with to , here also only 51 IP’s are available to us. We have specified availability zone in this subnet like all instances must be ap-south-1b.

→ So, now we will create Elastic IP which is a permanent public IPv4 address which remains same whenever we restart our AWS Instance.

→ So now, we will create a NAT Gateway.

NAT Gateway: also known as Network Address Translation Gateway, is used to enable instances present in a private subnet to help connect to the internet or AWS services. In addition to this, the gateway makes sure that the internet doesn’t initiate a connection with the instances.

→ Now, we will create a Internet Gateway for network connection in public subnet, like all instances in this subnet can connect to outside world and can get public IP.

→ Now, Routing Table is used to connect this Internet Gateway to our subnet, hence we will now create a Routing Table which keeps all the information of the source and destination of the packets.

  • Resource “aws_route_table” creates the routing table in the given VPC.
  • Resource “aws_route” keeps the information of the packet like from where the packet will go and where it will be received. In our case,

Destination is set to means packet can goto anywhere without any exception IP.

And Internet Gateway ID is provided, as packet will be sent from this router.

  • Resource “aws_route_table_association” is used to attach/associate the required subnet to this table.

Now, Network setup is done and the only setup left is “Creating a Instance and accordingly a Security Group for this instance”.

So now creating Wordpress Instance and a security group for this to set rules for this instance :

  • We have given ssh and http (for webserver).

— Instance for Webserver

  • We created this instance in public subnet

→ Now, same case for Mysql Instance and its security group.

  • We have allowed 3306 port to access mysql instance and 22 port to do ssh.
  • This Instance will be created in private subnet.

So, now we have created our code and now we will deploy it.

  1. Use command

#terraform init

  • This will install plugins for terraform, so that it can check the commands and code format.

2. Now, we will deploy code, so use command-

# terraform apply

And then enter yes to approve the deployment.

→ So, now you can see all services are created in AWS Console :

So now main task was to access Mysql instance with SSH and provide a Internet connectivity to it, if we want to install a package in it.

— We have given port 22 to do SSH, lets try if SSH is possible or not :

— As you can see SSH is not possible as this IP is private IP and we can’t access PrivateIP with PublicIP (We as a client/user always have PublicIP, whenever we have a Internet Connectivity). For Security Reasons, we dont provide PublicIP to our instance. So again challenge is same and for this, we have a solution -

Solution to Problem 1 (SSH) :

Bastion host : A bastion host is a server whose purpose is to provide access to a private network from an external network, such as the Internet. Because of its exposure to potential attack, a bastion host must minimize the chances of penetration.

— We have a PublicIP for our Wordpress Instance, so we can do SSH to our Wordpress Instance.

— As Wordpress and Mysql Instance are in same environment, so they have internal Connectivity and both have private IP, so they can communicate to each other and this technique is called Bastion Host.

So now we will try to do ssh using Wordpress Instance and for this we will transfer the key pair “key1.pem” to this Instance for authentication using WinSCP :

After that, use a command to change permissions :

# chmod 400 key1.pem

(Use your key pair name instead of key1.pem)

— Now we will try to do SSH of Mysql Instance using Wordpress Instance:

First Challenge is completed now and now the time for Internet Connectivity.

Solution to Problem 2 (Internet Connectivity) :

The NAT Gateway we associated to our Private Subnet is the solution to it and we have already provided it in our subnet. We have attached Elastic IP to our NAT Gateway, which will give us permanent PublicIP . So lets check internet connectivity .

So now, task given to us is complete and is working properly and the output of our Wordpress is below :

→ So, now we will destroy our terraform code using command :

#terraform destroy

and again enter yes to approve the destruction.

— All resources have been destroyed from AWS also.

— Github Link to see code file(See for reference) :

— See for reference of the codes.

— See Terraform docs for more detailed attributes and reference.

“I have practiced and gained all knowledge of this project(task) under the mentorship of Mr. VIMAL DAGA Sir during the Hybrid Multi Cloud Training by Linux World India.”

I hope this article is Informative and Explanatory. Hope you like it !!!

For any suggestions or if any reader find any flaw in this article, please email me to “”

Thank You Readers!!!



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store