22 June 2023
In this article, I'll show you how to set up an SSH bastion host on the cloud using sshuttle for secure access to internal resources. You'll learn about the differences between using a classic virtual machine or managed service and how to implement a bastion host on the AWS console.
The simplest most common way to secure your cloud infrastructure: the bastion host
What is a bastion?
An SSH Bastion host is a server that acts as a gateway to other servers on a network. It is typically used to provide secure access to internal resources while being exposed to the internet. It allows users to connect to internal resources on a network using the SSH protocol, providing a secure and encrypted connection.
When it comes to implementing an SSH Bastion host on the cloud, there are two main options: using a classic virtual machine (VM) or using a managed service.
Using a classic VM is the traditional approach and requires creating and configuring a virtual machine on a cloud provider such as AWS, Azure, or Google Cloud. This approach gives you full control over the configuration and management. You can install and configure SSH, set up firewall rules, and configure user access.
On the other hand, managed services such as AWS Systems Manager Session Manager or Azure Bastion, provide a more streamlined approach to implementation. These services are fully managed by the cloud provider, it is less configurable but can suit you if you don’t want to manage your bastion. It will most likely be a better choice if you don’t have a full technical background.
In this blog article, I will introduce you to the bastion ssh technology and to sshuttle which is a tool I love using to manage my access to my cloud infrastructure.
How ssh can be used to secure your infrastructure?
SSH, or Secure Shell, is a protocol that allows for secure and encrypted communication between two computers. It is commonly used to remotely access and manage servers, as well as to transfer files securely.
One of the key features of SSH is its ability to create a secure connection between two computers. This is known as SSH tunneling. SSH tunneling works by creating an encrypted connection between two computers, with the ability to forward traffic through the tunnel. This allows for secure access to your infrastructure's internal resources, such as servers and databases. These tunnels allow you to communicate securely from any place with your cloud (or on-premise) infrastructure.
To access internal resources through the bastion host, a user could either connect using SSH and access the resources from it. However, the advantage of tunneling is that it is possible to just open tunnels when communicating with specific ports on your machine. The user can then access the internal resource they wish on the remote infrastructure.
The following diagram illustrates this process:
In this example, a user is attempting to access a database server located on an internal network. Without the use of a bastion host and SSH tunneling, the database server would be directly exposed to the internet, making it more vulnerable to attacks.
By using a bastion host and SSH tunneling, the user is able to secure and encrypt any resource on a distant infrastructure. To open a tunnel with ssh you can use the following command:
ssh -N -L 8080:remote.example.com:80 user@personal.server.com
Easily access your services behind the bastion: the magic of sshuttle
What is sshuttle?
Sshuttle is a simple and easy-to-use tool that makes tunneling through a bastion host easier. It allows you to use a unique command to connect to your infrastructure. It also eliminates the need for complex configuration and management and allows for easy and secure access to your resources. Additionally, it is designed to minimize the overhead of encryption and tunneling, resulting in faster network speeds and making it an ideal solution for accessing internal resources on a cloud infrastructure.
How to use sshuttle?
Sshuttle can be easily installed on most operating systems. You can use any package managers such as apt, yum, or pip, or it can be downloaded from the official sshuttle website.
For example instead of running a command to open a tunnel to each service like this:
# To access a database postgre
ssh -N -L 5432:pgsql.database.admin:5432 user@personal.server.com
# To access your cluster kubernetes
ssh -N -L 8080:eks.cluster.admin:443 user@personal.server.com
Sshuttle can open all these tunnels with a single command:
sshuttle -r [username]@[bastion_host_IP] [internal_network_range]
--r flag is used to specify the remote host (bastion host) to connect to.
For example, if you want to route all traffic to the internal network range of 192.168.0.0/24 through the bastion host with IP address 10.0.0.1 and the username is “user”, you would use the following command:
sshuttle -r user@personal.server.com 192.168.0.0/24
It is also possible to specify a subnet range or wildcard, for example, to route all traffic to the domain example.com.
In my case, my sshuttle command usually looks like this:
sshuttle -vvv --daemon --pidfile={pid_file_path} \
--ssh-cmd 'ssh -i ~/.ssh/my-key.pem' --remote={bastion_host} -N
—vvv: sets the verbosity level to 3, which provides the most detailed output for debugging purposes.
—daemon: runs sshuttle as a background daemon process. –pidfile={pid_file_path}: specifies the path to a file where the process ID of the sshuttle daemon will be stored.
—ssh-cmd ‘ssh -i ~/.ssh/my-key.pem’: specifies the ssh command to use, here it is the path to the custom private key file. Generally speaking, it is a useful argument to specify a customized ssh command within your sshuttle command.
—remote={bastion_host}: specifies the remote host (bastion host) to connect to.
—N: sk the server which subnets it thinks we should route, and route those automatically. The suggestions are taken automatically from the server’s routing table.
Thanks to the use of the argument —pidfile, when you want to close the sshuttle process you just need to use the command: pkill -F pid-file.pid
⚠️ On Mac, you cannot be connected to a VPN client and use sshuttle at the same time. Be sure to turn off your VPN before you use sshuttle.
Sshuttle kind of works like a VPN through SSH, it is really useful when you have multiple services to which you would like to open a tunnel, but it is too painful to open them all.
How to implement an ssh bastion host and sshuttle easily ?
Why is it important to know how to set up a classic bastion?
You may now see many alternatives to implement technologies such as bastions like SSM or Azure Bastions. However, knowing how to implement a classical one is basic when working in the cloud. Moreover, for a small to medium size infrastructure, the implementation through a VM may be more cost-effective than using cloud-managed services.
You can implement your SSH bastion from the management console of AWS as well as with an infrastructure as code (IAC) tool such as terraform. Once implemented, we will be able to access and enjoy its purpose easily using sshuttle.
How to implement the bastion on the AWS console?
Let’s create our bastion host from the AWS console:
Go to your AWS account and select EC2, from this window select launch instance. You will end up on the virtual machine (EC2) creation, check the screenshot below:
Give a name to your EC2, in my case I chose “SSH Bastion”.
The second step is to choose an AMI to use. You can whatever Linux distribution you want, in my case I used amazon Linux 2 but if you are more comfortable with ubuntu it works as well. Sshuttle is compatible with most ssh servers implemented on a linux distribution.
The next step is to choose an instance type. This basically defines the power of the machine you will allocate for your bastion. This will really depend on the traffic going through it. If only one person needs to access the infrastructure, the traffic will most likely be low. If you do not expect much traffic, you can use a t2.micro instance as it is low cost, with moderate performance, and enough to host a bastion. You can refer to Romain’s article from Padok to help you to choose the right aws instance.
In general, it’s a good idea to assess your specific requirements and choose the instance type that best fits your needs.
The key pair definition is the next and one of the most important steps. It allows you to create or define an ssh key pair that will help you to connect to your instance. It is a must-have for secure access to your ssh instance. By using the authentication via key pair and not via username/password you improve the secure access to your host by assuming that only the people allowed connecting possess the private ssh key pair. If you do not already have a key pair, you can create one with the button on the right. Once it is created do not forget to download it and implement it in your ssh folder on your machine, by default in ~/.ssh :
To secure access to your bastion, you will need to implement security groups. This will basically allow you to authorize - or not - access to your cluster from some IP addresses (Whitelisting). I advise you to authorize access to SSH only to your IP address or to the IP range of your company’s VPN for more :
Last but not least, you will need to select the VPC and subnet on which to implement the bastion. In my case, I deliberately chose a subnet that has access to the public internet. I also checked the option to enable auto-assign public IP. This is to be able to access the bastion from outside the VPC.
Once you made sure everything is ok, you can create the bastion. Wait for a few minutes, and then you can access easily your bastion with sshuttle.
First, try:
ssh -i ~/.ssh/my-key.pem ec2-user@<bastionIP>
If it works, you can enjoy the use of sshuttle with the command below as seen previously in the article :
sshuttle -vvv --daemon --pidfile={pid_file_path} \
--ssh-cmd 'ssh -i ~/.ssh/my-key.pem' --remote=ec2-user@<bastionIP> -N
Conclusion
In conclusion, using sshuttle with bastion hosts is a secure and convenient method for accessing resources in a remote network. By creating a VPN-like connection through SSH, sshuttle enables users to access internal resources without exposing them to the public internet.
With the additional security of a bastion host serving as a gateway, remote users can connect to the internal network with confidence that their traffic is secure and protected.
References and Resources
- sshuttle documentation
- AWS EC2 documentation
- Azure Bastion documentation
- AWS Systems Manager Session Manager documentation
Thank you for reading this article on bastion host and sshuttle. I hope you found this guide helpful and that you feel more confident in setting up a bastion host to secure your cloud infrastructure.