
SSH forwarding methods
By David WORMS
Nov 11, 2024
- Categories
- DevOps & SRE
- Tags
- Bash
- DevOps
Never miss our publications about Open Source, big data and distributed systems, low frequency of one email every two months.
For teaching purposes at Adaltas, we provide isolated container for our students. Students are provided with a common SSH connection and are redirected to a dédicated container running inside one of our servers accessible from the internet. For example, the gollum
user connect with SSH to the middle.land.org
public server and ends up inside the misty-mountains
container.
There are multiple methods to forward the SSH connection from one host to another. But after researching for some instructions, we noticed that there were surprisingly few pages covering this subject.
Four different methods of SSH forwarding are presented to enable secure remote access through an intermediary server: direct SSH chaining, sshd configuration, Bash startup files, and SSH tunneling.
Network scheme
In the article, we will consider a network scheme where the client connects from a local host to a target host in a private network via a remote host exposed to the internet.
Below, we use the REMOTE_USER
, REMOTE_HOST
, TARGET_USER
, and TARGET_HOST
variables for the remote and the target user and host accordingly. It is also assumed, the SSH identity keys are correctly configured on all the hosts.
REMOTE_USER="<to_be_completed>"
REMOTE_HOST="<to_be_completed>"
TARGET_USER="<to_be_completed>"
TARGET_HOST="<to_be_completed>"
Method 1 - Running SSH over SSH in a single command
The ssh
command supports the optional command
argument. When provided, the command is executed on the remote host instead of prompting a login shell. To run SSH over SSH, simply run the command like this:
ssh -t $REMOTE_USER@$REMOTE_HOST ssh $TARGET_USER@$TARGET_HOST
When an SSH connection to the remote host is established, it executes the next ssh
command. The -t
flag forces pseudo-tty allocation. In case you don’t specify it, you will be prompted with the warning Pseudo-terminal will not be allocated because stdin is not a terminal.
and your terminal will not be working properly.
This command is equivalent to running ssh
commands sequentially.
ssh $REMOTE_USER@$REMOTE_HOST
ssh $TARGET_USER@$TARGET_HOST
You can even make a chain of multiple SSH forwardings. Every ssh
command besides the last one must be called with the -t
flag:
ssh \
-t $REMOTE_USER@$REMOTE_HOST ssh \
-t $TARGET_USER@$TARGET_HOST ssh \
$NEXT_TARGET_USER@$NEXT_TARGET_HOST
Pros and cons
This is the most straightforward method to redirect the SSH connection. For the end-user, it requires knowledge of the internal network and providing it to the command.
Method 2 - Running SSH over SSH configuring sshd_config
sshd_config
is sshd
server system-wide configuration file. Usually, it is located in the /etc/ssh/
directory.
The ForceCommand
keyword forces execution of a command in the argument. It is executed on the remote host after the SSH authentication. To apply this rule only to a specific user, you can use the Match
keyword to introduce a conditional block with the User
criteria.
On the remote host, enrich the /etc/ssh/sshd_config
configuration or create a new file inside the /etc/ssh/sshd_config.d/
directory. Restart the sshd
service to apply the configuration:
# Configuration
cat <<CONF | sudo tee /etc/ssh/sshd_config.d/forwarding.conf
Match User $REMOTE_USER
ForceCommand ssh $TARGET_USER@$TARGET_HOST
CONF
# Changes application
sudo systemctl restart sshd
Now, to access to the target host from the local one, you can simply run the basic SSH command.
ssh $REMOTE_USER@$REMOTE_HOST
Pros and cons
Using this method allows simplifying the command for the end-user to connect to the target host. However, it requires modifications of the global configuration file, which might be overwhelming when you configure such rules for multiple users and connecting them to different target hosts.
Method 3 - Running SSH over SSH configuring Bash startup files
When Bash is invoked as a login shell, it first reads and executes commands from the Bash startup files. The order of these files execution is described in the documentation manual.
The ~/.bash_login
file is one of those Bash startup files. It can be used to proceed with an SSH connection to the target host, after SSH login to the remote host. You can create it and put the ssh
command like:
ssh $TARGET_USER@$TARGET_HOST
To access to the target host, like in the previous method, you only need to run on your local host the basic ssh
command.
ssh $REMOTE_USER@$REMOTE_HOST
Pros and cons
Comparing to others, this method is easier to use and manage. All the settings are made in the user’s home directories on the remote host. This involves less managing efforts when you provision and de-provision access for multiple users.
It also gives automation capabilities. For any provisioning purpose, you can extend the script in a Bash startup file. For example, you can create a Docker container on the fly and then enter inside it. The example bash script in ~/.bash_login
can look like this:
# Export container name
export CONTAINER=$USER-container
if [ ! "$(docker ps -aqf name=$CONTAINER)" ]
then
# Run container if not exists
docker run -it --name $CONTAINER IMAGE
else
# Start container if not running
docker start -i $CONTAINER
fi
# Exit SSH session on container exit
exit
Here, we are constructing a container name basing on the name of the user exported by $USER
. Then, we are checking if a container with the given name already exists. In case of not existing, we are creating, starting, and entering inside it using the -it
options to allocate pseudo-TTY and to attach STDIN. Otherwise, we are just starting it by attaching STDIN with the -i
option.
Finally, when the end-user connects to the remote host via SSH, he is forwarded to an isolated virtual environment running in a Docker container.
Method 4 - SSH local port forwarding (also known as SSH tunneling)
SSH local port forwarding (also referred to as SSH tunneling) allows you to forward a port on the local host to a port on the remote host, which is then forwarded to a port on the target host.
To create a local port forwarding, pass the -L
option to the ssh
command:
ssh -L [$LOCAL_HOST:]$LOCAL_PORT:$TARGET_HOST:$TARGET_PORT $REMOTE_USER@$REMOTE_HOST
In addition to TARGET_HOST
, REMOTE_USER
, REMOTE_HOST
introduced above, the options used are as follows:
[LOCAL_HOST:]LOCAL_PORT
: the local IP address and the port number. WhenLOCAL_HOST
is omitted, the defaultlocalhost
value is used. Any port number greater than1024
asLOCAL_PORT
can be used. Ports numbers less than1024
are privileged ports and can be used only byroot
.TARGET_PORT
: the port of the target host, by default is22
.
Additionally, it is useful to add the following options to the ssh
command:
-N
: not to execute a remote command when connecting toREMOTE_HOST
which is a login shell.-f
: tells thessh
command to run in the background to don’t lock the terminal window.
The complete command will look like this:
ssh -N -f -L \
[$LOCAL_HOST:]$LOCAL_PORT:$TARGET_HOST:$TARGET_PORT \
$REMOTE_USER@$REMOTE_HOST
After the SSH local port forwarding is created, you can access the target host running ssh
with the -p
option with the LOCAL_PORT
specified above:
ssh $TARGET_USER@localhost -p $LOCAL_PORT
Pros and cons
This method is way more verbose and difficult to use. The end-user must run non-trivial commands and keep the additional process of SSH tunnel running on his local host.
Conclusion
This article presents 4 different methods to forward SSH connection. Some of them are convenient to use as ad hoc commands, others are suitable for automation.