Securely Accessing Private Subnets in AWS Using a Bastion Host: A Step-by-Step Guide

What is Bastion Host/Jump Server?

In AWS, a public subnet has direct internet access via an Internet Gateway, allowing resources like web servers to be publicly accessible. A private subnet has no direct internet access, making it ideal for sensitive resources like databases or backend servers. So, how do you access a private subnet? The answer is a bastion host. A Bastion Host is a secure, publicly accessible server used to access instances in a private subnet. It acts as an intermediary, removing the need for direct public access to private resources.

Step-by-Step Guide to Setting Up a Bastion Host

Enough theory—let's set up our own bastion host.

Create VPC

  • Navigate to the AWS VPC console

  • Create a new VPC

  • Define a CIDR block (e.g., 10.0.0.0/16)

Create Subnets & Route tables & Other VPC configurations

go to subnets section on aws VPC console and go to create subnet

  • associate with the vpc that you have created earlier
  • Public Subnet:

    • Create a public subnet with subnet CIDR bock ( 10.0.1.0/24)
  • Private Subnet:

    • Create a private subnet with subnet CIDR bock ( 10.0.2.0/24)

now click on add new subnet

Now navigate to Internet gateway on VPC console create Internet gateway to allow public traffic into your subnet

now click on “attach to a vpc” on success message and attach with the vpc.

Now move to NAT gateway section on VPC console to allow private resources to access the internet securely. Now we can enable elastic Ip to provide a static Ip for our NAT gateway.

Now move to create route tables in vpc console

  • create a public route table

For our public subnet route table, we need to connect it with internet gateway so our public subnet can be accessible to internet traffic.

now create another route table for our private subnet

Now edit the route table and map the NAT gateway so our private instance can access the internet.

Now we need to map our route tables to our subnets. by clicking on selected subnet and “Edit subnet association

  • First, our public subnet route table will be mapped to public subnet

  • Second, our private subnet route table will be mapped to private subnet

Deploying the Bastion Host (Public EC2 Instance)

now navigate to EC2 in AWS console and launch EC2 instance

  • go to edit network settings and click on edit. Next choose the VPC and map it to our public subnet.

  • Enable auto-assign public IP address

  • Configure Security Groups:

    • Allow only SSH access (port 22) from trusted IPs (this should be the Ip of users that want to access the bastion host; for simplicity, I have allowed all traffic)
  • and create Key Pair setup for SSH access

Deploying the Private instance ( Private EC2 Instance)

now navigate to EC2 in AWS console and launch EC2 instance

  • go to edit network settings and click on edit. Next, choose the VPC and map it to our private subnet.

  • Configure Security Groups:

    • Allow SSH access only from the Bastion Host’s Security group (not from the internet)
  • and create Key Pair setup for SSH access

Accessing the Private Instance Using the Bastion Host

Now for the most exciting part, let's test if we can access our private instance using our bastion host. Moving forward, there are several ways to do this. In this tutorial, I will use SSH proxy configuration.

First, in your terminal, navigate to “~/.ssh” (Windows users can use Git Bash for this).

Create a “config” file if it’s not there and edit it with vi ~/.ssh/config.

To edit, press the “i” key, and after making changes to the config file, save it with “ESC” + “:wq”.

Host bastion
    HostName <PUBLIC_IP_OF_BASTION_HOST>  # Replace with Bastion Host's public IP
    User ec2-user
    IdentityFile "<PATH_TO_YOUR_KEY_PAIR>"  # Replace with the path to your key pair

Host private-instance
    HostName <PRIVATE_IP_OF_PRIVATE_INSTANCE>  # Replace with Private Instance's private IP
    User ec2-user
    IdentityFile "<PATH_TO_YOUR_KEY_PAIR>"  # Use the same key pair if applicable
    ProxyCommand ssh bastion -W %h:%p

Now, after saving it, run

ssh private-instance

voilà, we are successfully inside our private instance.

Conclusion

setting up a bastion host in AWS is a crucial step for securely accessing private subnets. By following this step-by-step guide, you can effectively create a secure environment that allows you to manage and access your private instances without exposing them to the public internet. This approach not only enhances security but also ensures that sensitive resources remain protected while still being accessible for necessary administrative tasks. Implementing a bastion host is a best practice for maintaining a robust security posture in your AWS infrastructure.

1
Subscribe to my newsletter

Read articles from Irshit mukherjee directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Irshit mukherjee
Irshit mukherjee

Currently, I am in my exploring phase, learning something new Every day. I love to write blogs about what I have learned and share them with others.