Highly Available Bastion Hosts with Route53

Instances in a private subnet don’t have a public IP address, and without a VPN or a DirectConnect option, Bastion Host (JumpBox) is the expected mechanism to reach your servers. Therefore, we should make it Highly Available.

In this quick post, I will show you how to setup a Highly Available Bastion Hosts with the following targets :

  • Bastion hosts will be deployed in two Availability Zones to support immediate access across the VPC & withstand an AZ failure.
  • Elastic IP addresses are associated with the bastion instances to make sure the same trusted Elastic IPs are used at all times.
  • Bastion Hosts will be reachable via a permanent DNS entry configured with Route53.

In order to easily setup the infrastructure described above, I used Terraform:

Note: I did a tutorial on how to the setup a VPC with Terraform so make sure to read it for more details.

Update the variables.tfvars file with your SSH Key Pair name and an existing Hosted Zone ID. Then, issue the following command:

That will bring up the VPC, and all the necessary resources:

Now in your AWS Management Console you should see the resources created:

EC2 Instances:

DNS Record:

Finally, create an SSH tunnel using the DNS record to your private instance:

Once done, you should now be able to access to your private instances via SSH:

Take it further ? instead of defining number of bastion hosts, we could use a bastion host inside an autoscaling group with min target set to 1.

Install MEAN Stack Using CloudFormation

AWS CloudFormation is a service that helps you model, setup and replicate your AWS resources. It uses a template file to bring up a collection of resources together as single stack.

To create templates we use a JSON file or AWS CloudFormation Designer. For this tutorial I opted the first solution.

Note: The template is available on my Github 😎.

We start with a basic template that defines a single EC2 instance with a security group that allows SSH traffic on port 22, MongoDB traffic on port 27017, and the NodeJS app on port 3000 from anywhere, as shown below:

In addition to that, we create two input parameters that specify the instance type and a Key Pair for SSH access. Then, we use UserData property to provide a set of shell commands to install MongoDB, NodeJS and bootstrap a simple MEAN application. Finally the output section print the public URL of the MEAN application.

Now we defined our template. Go to AWS Management Console then navigate to CloudFormation Dashboard and click on “Create Stack“:

Upload the JSON file and click on “Next“:

Assign a name to the stack, and choose your instance type and key pair you will use to ssh to the instance. Then, click on “Next“:

Left all fields unchanged and click on “Next“, then “Create

Once launched, you will get the following screen with launching process events:

After a while, you will get the CREATE_COMPLETE message in the status tab.

If you point your browser to the URL shown in the Outputs tab, you should see: a simple HTML message:

If we change the endpoint we should see a JSON response:

Congratulation ! ✨🎉 you have deployed your MEAN Stack application.

Go to EC2 Dashboard, you should see your instance there:

Verify the security group is setup as configured in the template:

To verify all packages and dependencies has been installed correctly, we can connect to the server via SSH:

To terminate the instance we can delete the stack from the CloudFormation Wizard, Deleting the stack will terminate all the instances launched by the stack:


Manage AWS VPC as Infrastructure as Code with Terraform

In this tutorial, I will show you how to setup a VPC as described in the network diagram below in less than 1 min ⏱ using Terraform:

The VPC topology above is the best demonstration of what will be implemented:

  • The private subnet is inaccessible to the internet (both in and out)
  • The public subnet is accessible and all traffic ( is routed directly to the internet Gateway

Before we dive in, all the code used in this demo is available at my Github.

Note: I already did a tutorial on how to get started with Terraform so make sure to read it for more details.

1 – Global variables

This file contains environment specific configuration like region name, CIDR blocks, and AWS credentials …

2 – Configure the AWS provider

3 – Create a VPC

4 – Create Subnets

To make the public subnet addressable by the Internet, we need an Internet Gateway:

 5 – Internet Gateway

To allow traffics from the public subnet to the internet throught the NAT Gateway, we need to create a new Route Table.

6 – Route Table

Next, we will create a security group for each subnet.

7 – Security Groups

7 .1 – WebServer SG

This Security Group allows HTTP/HTTPS and SSH connections from anywhere.

7.2 – Database SG

This Security Group enable MySQL 3306 port, ping and SSH only from the public subnet.

Now we will deploy the EC2 instances, but before that we need to create a key pair in order to connect later to the instances via SSH.

8 – Key Pair

9 – EC2 Instances

9.1 – WebServer Instance

This instance will play the role of a webserver. Therefore, we pass to the instance userdata a shell script install.sh which contains commands to install an Apache Server:

9.2 – Database Instance

Once you’ve defined all the required templates, make sure to set the AWS credentials variables as an envrionment variables:

Note: You can always use your root user which has access permission to everything, but for security perspective, its recommended to use only a limited permissions user account. So create a new one using AWS IAM.

To see how terraform plans to create the resources type “terraform plan“. To create the infrastructure type “terraform apply“:

That will bring up the VPC, and all the necessary resources. Now in your AWS Management Console you should see the resources created:

If you click on the “Subnets” menu, you should see the public & private subnets:

The same goes for the Route Tables:

And the Internet Gateway:

Security Groups also:

WebServer Security group:

Database Security Group:

And finally the EC2 Instances:

WebServer Instance:

Database Instance:

Don’t forget to destroy the resources if they are not needed by typing “terraform destroy“:


Getting started with AWS VPC

We use Virtual Private Cloud (VPC) ☁ to define our own network and how the AWS resources (EC2, EB, RDS …) inside the network, are exposed to the Internet 🌎.

As promised before, today I will show you guys how to create a VPC and how to:

  • Create a Public Subnet with a couple of WebServers and a NAT instance.
  • Create a Private Subnet with a Database instance.
  • Configure AWS Flow logs to store VPC traffic and metrics in CloudWatch.
  • Configure Network Access Control List(ACL), Route Table & Security Groups … 

1 – Create a VPC

Go to the AWS Management Console and navigate to the VPC Dashboard then click on “Create VPC”:

Give a name to your VPC, and assign a private IPv4 CIDR block (of /16 or smaller) from the following ranges :

  • – (65,536 IP addresses)
  • – (1,048,576 IP addresses)
  • – (16,777,216 IP addresses)

Left the default settings unchanged and click on “Yes, Create”. When the work completes, you should see something as below:

Note: When you create a VPC a main Route Table, default ACL, and a default Security Group is created automatically.

As show in our network diagram, we need to create two subnets spanning two Availability Zones (AZ). Each AZ will have one subnet.

2 – Public Subnet

Click on the subnets menu on the left, then click on “Create Subnet”:

Populate the fields as above. Make sure yout select the VPC we created earlier. Then, click on “Yes, Create“. Once created, you should see:

Note: We used a CIDR block of this would give us 251 usable IPs

5 IP’s are reserved (2 for Network address and Broadcast, and 3 are reserved by default by Amazon)

That being said, let’s visualize what we have done so far:

3 – Private Subnet

We similarly create the private subnet:


Now, we have a VPC with two Subnets:

In order to make the first subnet ( publically accessible by the Internet, we need to create an Internet Gateway (IGW).

4 – Internet Gateway

So click on “Internet Gateway” menu on the left, then click on “Create Internet Gateway” and give it a name:

Then Attach it to the VPC we created earlier by clicking on “Attach to VPC” button:

So far we created :

5 – Route Table

We will now create a new Route Table that allows instances inside the Public Subnet to direct all traffic to the Internet Gateway so that the Gateway can direct it out to the InternetSo, go to the “Route Tables” menu on the left, and click on “Create Route Table”. Give it a name and select our VPC:

Then click on “Yes, Create”, click on “Routes” tab and “Edit” button. Add new route that redirects all traffic ( to the Internet Gateway that we created:

As last step we associate this route table to the public subnet:

Then “Save”. Let’s see what we have created so far:

Now the is a public subnet as we associated a route table with IGW rule. We can now launch an instance to the public subnet which can be accessed over the Internet.

6 – EC2 Instances

Note:  In order to automatically assign a public IP address for every EC2 instance created in the public subnet, we need to enable “Auto-assign IP” on the public subnet:

6.1 – Webserver Instance

So now, lets go ahead and deploy a new EC2 instance. I already did a tutorial on how to do that, there are few ways you want differ from the tutorial:

  • On the configuration page, select the VPC we created earlier and the public subnet:

  • This instance will play the role of a webserver, so we need to install an Apache Server. Add the following script to the instance user data:


  • Don’t forget to assign a label to the instance, and enable HTTP port on the security group page:

Your instance is now launching and that may take a few minutes. Click the View your instances on the Instances page link and you will be redirected to your “My Instances” page, where you can monitor and configure your EC2 instance:

Now, if you point your browser to the instance public IP:

You can now use the instance key pair to connect to the server via SSH:

Awesome 😎, so we have successfuly created an EC2 instance inside a public subnet:

6.2 – Database Instance

We will follow the same steps like the previous section, except this time the instance will be inside the private subnet :

We will also enable access to MySQL 3006 port, SSH, and Ping only from the public subnet.

Once created:

As you can see our database server has a private ip address so we wont be able to SSH it 😕. But dont get sad 🙂, we will use the webserver instance in the public subnet as a bastion server (jump box)

So first connect to the webserver instance via SSH and copy over the key pair using sftp or copy past the key pair content into a new file in the webserver. Then by using the database private ip address we can now connect to the server:

As I mentioned before, the private subnet has no access to the Internet, therefore our database server cannot talk to the Internet:

Fortunately, if we want the private subnet instances to be addressable to Internet, we have two solutions:

7.1 – NAT Instance

We need to create a NAT instance inside the public Subnet and configure the private subnet route table so all the subnet traffic should be routed through the NAT instance for Internet access.

So let’s launch a t1.micro NAT instance. AWS has public linux NAT AMI’s. So choose the first one:

In the launch configuration select the appropriate VPC and the public subnet ( you configured. Make sure all the configurations are correct as below and launch the instance:

Once created, go back to “your instances” page, you should see:

Next, we will update the private subnet route table and add a new route that redirects all traffic ( towards the NAT Instance.

The current VPC diagram:

So now the database server can access the internet via a NAT instance for tasks such as installing MySQL or downloading updates or security patches:

7.2 – NAT Gateway

On the “NAT Gateways” menu on left, click on “Create NAT Gateway“. Provide the necessary details, like the public subnet ( and Elastic IP. and create the NAT Gateway.

Once created you will see this:

Now lets edit the route table to send the traffic destined for the internet toward the gateway.

Which one to choose ?

Nat Instance is a single point of failure, in case it went down, our EC2 instances in the private subnet wont be able to talk to the internet. Of course you can always put it inside an autoscalling group and set the minimum of running NAT instance to 1. But you will need to have an automated script configured and ready to redirect communication from the private instances within the old NAT instance to the new NAT instance.

But using AWS’s new managed NAT Gateway, things work differently. Instead of configuring, running, monitoring, and scalling a cluster of EC2 NAT instances, it’s a matter  of couple clicks and you are all set. In short, all the configurations that were once the responsibility of the Ops team, will now be handled invisibly by AWS (You won’t need to apply security patches)

8 – Flow Logs & CloudWatch

In order to capture and log data about network traffic in our VPC, Flow Logs records information about the IP data going to and from network interfaces, storing this raw data in Amazon CloudWatch where it can be retriever, filtred, and viewed.

Browse to your VPC Dashboard and follow the setup wizard to create a new flow log:

In the dialog box, complete the following information:

  • Filter: Select whether the flow log should capture rejected traffic, accepted traffic or all traffic.
  • Role: Specify the name of an IAM role that has permission logs to CloudWatch Logs (Check my previous tutorial on how to create IAM role).
  • Destination Log Group: Enter the name for the log and where to store it in CloudWatch.

To view your VPC log records then go to CloudWatch Console . In the navigation pane, choose Logs, select the log group you created earlier, then create a Log stream:

It may take a few minutes after you’ve created your flow log to see the VPC log records:

9 – Cleaning Up

Make sure to terminates all the AWS resources associated with the VPC such as EC2 instances before deleting the VPC:

That’s it for this tutorial. I hope your learnt something. In my next post, I will show you how to use Infrastructure as Code with Terraform to setup the same VPC architecture in less than 1 min. 😁