digitalspeed logo

How to Connect Securely to a Private Server from a Bastion Server(Host) using SSH

Bastion host private server architecture

Connecting to a secure virtual server from a bastion host offers enhanced security by limiting direct access to the private server. Utilizing a bastion host acts as a gateway, providing controlled access to the private server, thus reducing the attack surface.  

This method strengthens network security protocols and prevents unauthorized access to critical infrastructure, ensuring safer and more controlled server management but the security of your architecture can be impacted by how you manage the connection keypair. I’ll demonstrate various methods of handling security keys and evaluate their effectiveness to ensure optimal security measures are in place. 

Before we start, I would like to clear some terms here, 

A secure virtual server typically resides in a private subnet, which means it is not directly accessible from the internet. It has a private IP address which it uses for internal communication but not a public IP address. 

A bastion host is a secure computer on a network that acts as a gateway for access to other private servers. It serves as a single point of entry, helping to protect internal systems from unauthorized access. 

In most cases, the bastion host only allows access from the user IP address and that’s what we will implement here. 

Implement the network from the architecture

We would be using AWS but you can use Azure, GCP, or any other cloud provider. I wouldn’t go into much detail on implementing the network but I will link resources below for you to get more clarifications on this part; 

Connecting to an ec2 instance in a private subnet on AWS | by Harry Daniels | Towards Data Science 

Create your VPC, internet gateway, NAT gateway, private and public subnet

A VPC (Virtual Private Cloud) is a virtual network where you create, group, and manage your AWS resources. You can create more than one VPC for your account and use it to group certain resources together. 

  • Go to your VPC dashboard 
  • Create a VPC and give it a CIDR block of 10.10.0.0/16 

The Internet gateway enables communication between the VPC and the Internet, it is the entry point for data coming from the Internet into the VPC. 

  • Select internet gateway from the options at the left of the VPC page 
  • Create the internet gateway and attach it to the VPC you just created 

Subnets are a way to group resources according to their IP range. Subnets have two major types of public and private. Private subnets require a NAT gateway for it to have access to the internet while public subnets do not. 

  • Select subnet from the options on the left of the VPC page 
  • Create the following subnet connected to the VPC you created earlier (your working VPC) 

Private-subnet | 10.10.2.0/24
Public-subnet | 10.10.1.0/24 

In practice, you should create multiple private and public subnets and put them in different availability zones for resiliency.

Route tables determine how data moves within your VPC. We are creating one route table for the private subnets to route traffic to the NAT gateway and the public subnet to route traffic to the internet gateway. 

The route table for the public subnet is given below, it simply routes traffic to the Internet gateway 

The route table for the private subnet is shown below, it simply routes traffic to the NAT gateway which will be created next. 

Remember to associate your route table to the appropriate subnet. Select the route table, select Subnet Association below. 

Nat is a technology used to allow internet access to private subnets. Its main function is to carry out private IP address translation to public IP address and vice versa. The NAT Gateway is an AWS-managed service for the NAT instance. 

  • Select NAT gateway from the options at the left of the VPC page. 
  • Create the NAT gateway, select the ID of your public subnet for the subnet of the NAT gateway when creating it. 

We have completed the VPC, subnet, and NAT gateway. 

Create EC2 instance for bastion host 

Create an EC2 instance in the public subnet, and allow only SSH connection to the instance from your IP address. 

  • Locate the EC2 instance page, select instances, and click Create instance 
  • Use any of the base images, use the t2micro instance type, use a new key pair .pem file, or create a new one 
  • For VPC select your working VPC, select the public subnet 
  • Select Create a new security group, and add a rule that allows only SSH from your IP address as shown in the screenshot below. 
  • Create the instance 

Create EC2 instance for secure server

Create an EC2 instance in the private subnet, and create its security group to allow only SSH connection from the security group of the bastion host instance. 

  • Locate the EC2 instance page, select instances, and click Create instance 
  • Use any of the base images, use the t2micro instance type, use the same key pair .pem file as used with the bastion host 
  • For VPC select your working VPC, select the private subnet 
  • Select Create a new security group, and add a rule that allows only SSH from the security group of the bastion host as shown in the screenshot below.
  • Create the instance

After creating the architecture, you need to connect to your bastion host then to your private instance, here are the ways you can do it; 

Connect to your private instance through agent forwarding 

Connect to your bastion host from your local computer through SSH but first you have to configure agent forwarding. 

ssh-agent bash
ssh-add keypair.pem
ssh-add -1 

The command above adds the keypair file to the chain so you can use it connect to both your bastion host and then to your private server. Replace keypair with the actual directory to your keypair i.e ./keypair.pem 

Use the command below to connect 

ssh –A  ec2-user@BASTION-HOST-IP

Replace BASTION-HOST-IP with the actual IP of your bastion host. When you are connected, use the similar command below to connect to your private server. 

ssh ec2-user@PRIVATE-SERVER-IP 

You should be connected now to the private server, confirm that the IP on the hostname is same as the private server IP. 

Check out this video for more info  https://www.youtube.com/watch?v=SjvAoL8iiQs 

Using SSH Config file 

Using an SSH config file simplifies connecting to remote servers by defining connection parameters like host, username, and private key. Instead of typing lengthy commands, users can use custom aliases, improving efficiency and reducing errors. The config file enhances security and streamlines SSH access for frequent connections. 

In this case, it further simplifies the process by enabling seamless connectivity between the bastion host and the private server. 

Create a .ssh/config file in your root directory. 

Copy the data below and paste on the file, make the changes to the actual values you have below; 

Host bastion-instance 
   HostName <Bastion Public IP> 
   User ec2-user
   
   IdentityFile /path/keypair.pem

Host private-instance 
   HostName <Private IP> 
   User ec2-user 
   ProxyCommand ssh -q -W %h:%p bastion-instance 

Use the name you want for bastion-instance and bastion-host 
Change the hostname to your instance IP for both the bastion host and the private server 
Change the user argument to the your user value; ubuntu, root, bitnami, etc. 
Change the the proxy argument bastion-host to your host details actual name 
Change the path to file accordinlgy 

Run the command to start ssh connection to your private server directlyalthough it passes through the bastion host first has indicated in the config file 

ssh private-instnace 

Copy your keypair file directly from your local computer into your bastion host 

Unlike the other two methods above, this method is not very secure and is not recommended because if your bastion host is compromised, the hacker can quickly get to your private server because your keypair file is available at the bastion host. 

Use the command below to copy the file from your local directory to your bastion host 

scp –i ./path/keypair.pem  ./path/file-to-copy ec2-user@IP-bastion-HOST:./ 

It copies the keypair file to your root directory of the bastion host 

Connect from the bastion host to your private server 

ssh ./path/keypair.pem ec2-user@IP-PRIVATE-SEVRER 

Check out this article for more about this, How to copy files remotely using SSH (simplified.guide) 

Upload your keypair file to a private S3 bucket and download or copy the file from S3 to EC2 

This method is also not very secure and is not recommended because if your bastion host is compromised, the hacker can quickly get to your private server because your keypair file is available at the bastion host. 

To do this you would need to make a private S3 bucket or make the S3 object of the file private so it isn’t accessible to the public internet. 

Give your ec2 instance an iam role to access object from s3. 

Connect to your EC2 instance through SSH 

ssh –i ./path/keypair.pem ec2-user@BASTION-HOST-IP 

Confirm ec2 can access S3 

Copy file from s3 to bastion host using the object S3 URL

aws s3 cp <object S3 URL>   ./ 

I wrote an article about retrieving objects from private S3 buckets to EC2 instances, you can find out more from it https://www.digitalspeed.online/all-articles/how-to-enable-aws-ec2-access-to-your-s3-bucket/

Upload keypair file to public S3 bucket or any other provider where the file can be downloaded from the URL

This a highly insecure way of accessing a private server, actually it defies the aim of making a server private, which for optimal security, with this approach anyone can download your keys if they have the URL, so caution. You could also delete the file from the bucket when you are done.

If you would try this, make sure it’s on a personal project or demonstration where you would delete the resources immediately and not for production. 

Connect to your Bastion host remotely 

ssh –i ./path/keypair.pem ec2-user@BASTION-HOST-IP 

You can then download the keypair file to your Bastion host using the command 

wget   KEYPAIR-URL 

Your keypair file is downloaded to your root folder, you can confirm with the command ls 

You see your keypair file shown in this directory that’s if the download was successful 

Connect to your private server  

ssh -i ./path/key-pair ec2-user@Private-server-IP

Conclusion 

The first two methods, utilizing SSH agent or SSH config files, are the most secure and recommended approaches as they avoid exposing your keypair file. 

Conversely, copying directly from S3 or the local computer is not advisable due to security risks; if a bad actor gains access to the bastion host, they could also access your private server with the keypair file available there.

Remember to delete the resources you have created; delete the EC instances, delete the VPC and subnets, delete the NAT gateway and internet gateway.

The fifth method is only suitable for practice or demonstration purposes.  

Share your thoughts below, what difficulty did you face.

Please share this article at the top of the page under the share this button. Thanks

Recent Post

Send Us A Message

Related Post

Join our newsletter to stay updated

digitalspeed-logo

At DIGITALSPEED, you can get updates, reviews and learn about new digital tools and features on existing tools. check us on social media.

Get In Touch

Lagos, Nigeria

DIGITALSPEED © All Rights Reserved.

2025

Scroll to Top

Seach for Articles