Using bastion host in AWS environment

One of the ways how you connect and maintain your Linux EC2 instances in AWS VPC is connecting to them using SSH protocol. You can ssh to any EC2 instance which is in a public subnet and corresponding security group and network access control list allow that. The downside of connecting using ssh to your Internet facing / web hosting EC2 instance is that it has multiple open ports (like 80 and/or 443 for web layer servers), so in addition to ssh connection you should pay attention to securing / patching anything related to services running on these ports. Using a bastion host in your VPC allows to deny ssh connections to any other EC2 instance except for bastion host outside of VPC. Moreover, it will also allow to ssh to EC2 instances in private subnets! In this post I will guide you through setting up a bastion host.

Setting up a bastion host

First what we should do is to create a new EC2 instance in a VPC, where all other instances are hosted and you would like to connect to. There are no strict requirements in terms of performance related to a bastion host. Basically it could be the least powerful instance available, for example, t2.nano. It just need to be powerful enough to serve multiple input/output ssh connections.

It is a good practice to host a bastion host in a separate subnet, so you can apply very strict NACL (network access control list) rules. As a reminder, you should explicitly specify which inbound / outbound connections are allowed. So before creating a bastion host, create a new subnet in the same VPC you would like to securely ssh to. Once it is done, create a new NACL and the only inbound / outbound ALLOW rule should be related to SSH with a particular IP (or IP range) from where you will connect. Please refer to a screenshot below.

If it is not possible to limit source / destination to one IP address, try to be as specific as possible to limit it to a particular subnet your site / office belongs to. If possible, try not to use any destination (

Security group for bastion host

The same idea as for NACL applies to security group (SG) as well – be as strict as possible defining ALLOW rules. One thing to keep in mind here – in opposite to NACL, response traffic is always allowed in SG, you don’t need to define a separate rule for a return traffic. Also, there is no deny rule available in SG – you can only define allow rule. The traffic which does not match any allow rule, will be blocked – there is an implicit deny rule in the end of each SG. The example how SG inbound rule should look like is on the screenshot below.

The outbound rule of this SG should allow ssh traffic for all destinations inside your VPC.
With this configuration of bastion host related things is over and we can proceed to NACLs and SGs of your EC2 instances configuration / re-configuration.

Changes in NACLs and SGs of other EC2 instances

Now we should make adjustments in NACLs and SGs which we use for our EC2 instances we would like to connect to. We should edit the rules related to ssh and as source / destination we should point the PRIVATE IP address of our bastion host. Using a private IP address ensures that traffic will be routed inside VPC and will not go through Internet. For SG as alternative, we can mention also the name of SG of bastion host instead of private IP address. If SG is pointed as a source / destination, the corresponding traffic from ANY instance using this SG will be allowed.

Once all configuration is done, try to connect (ssh) to your any of your EC2 instance. You should get a timeout error, since ssh traffic to any instance from Internet except for bastion host is blocked now by SG/NACL. So a bastion host now is the only EC2 instance you can reach directly from Internet.

Connection to EC2 instances using a bastion host

SSH relay allows you to use ssh keys which are stored locally on your laptop to be cached and used for connecting from one chained machine to another, where this key is not actually available. For example, you want from your laptop A connect to EC2 instance B and from EC2 instance B you want to connect to EC2 instance C. But the problem is that for B->C connection you need an ssh key, which does not present on machine B. However, this ssh key is available on laptop A. By using ssh relay, you can connect from B to C using an ssh key, which is not physically located on B. This is a huge security improvement, that you don’t need to store ssh keys on each EC2 instance. We will take in more details about security aspects of ssh relay in one of the upcoming posts dedicated to bastion host. So the prerequisite to connect to an EC2 instance in a private subnet is to have an EC2 instance in a public subnet. Then, using this public instance, we can connect to an instance in a private subnet.

Assuming you are using Putty and Windows 10, let’s see how we can setup ssh key forwarding.

Locate an ssh key, which should be used to authenticate ourselves on an EC2 instance. Double-click on it. Putty will add it as an available ssh key for authentication. Then, open Putty, enter our EC2 instance from public subnet details (IP, login), under Connection ->SSH->Auth check the option “Allow agent forwading”. That’s it!.

Allow agent forwarding

Now you should be able to connect to an EC2 instance and through it to our EC2 instance in a private subnet.

In the next post we will discuss how you can connect to a EC2 instance located in a private subnet without using a bastion host. Stay turned!

Leave a Reply