SSH Tunneling
SSH allows tcp port forwarding between ssh client and ssh server as part of the encrypted ssh connection.
Server → Client (local)
A socket on the server (source) gets forwarded to the client (target).
ssh user@host -L target_ip:target_port:source_ip:source_port
Use case 1: Admin software
Server socket with port 9000 will be available on client machine at port 5000.
ssh user@host -L 127.0.0.1:5000:127.0.0.1:9000
Useful if admin software is only accessible on the server (localhost binding) and not exposed to the network.
Use Case 2: Quick demo
Server socket with port 9000 will be accessible at client network on port 8080 of the client machine.
ssh user@host -L 8080:127.0.0.1:9000
ssh user@host -L 0.0.0.0:8080:127.0.0.1:9000
Useful for a quick demo of a service running in a different network (e.g. cloud) to multiple participants in the same network (e.g. company).
Use case 3: Jump Host
Server can reach host with ip addr 192.168.1.15. Service on 192.168.1.15:8080 will be available on client machine at port 8081.
ssh user@host -L 127.0.0.1:8081:192.168.1.15:8080
Hop to hop forwarding of hosts accessible in the server network(s).
Client → Server (remote)
A socket on the client (source) gets forwarded to the server (target).
ssh user@host -R target_port:source_ip:source_port
Use case 1: Microservice development
Service on port 8000 of the client machine will be available on server at port 8081. Unless GatewayPorts
is set
to yes
in sshd config (default no
) the serverside bind will always be localhost (127.0.0.1).
ssh user@host -R 8081:127.0.0.1:8000
Useful to integrate a microservice on developer machine into a foreign environment (e.g. test cluster). Also works with
other source addresses than 127.0.0.1
.
Use case 2: TLS terminating web proxy as a service
Client starts a http server on local machine on port 8000. That service will be available as https://server.tld
ssh user@host -R 8001:127.0.0.1:8000
Processing order:
- Webbrowser (User Agent) requests https://server.tld
- Reaches a reverse proxy on port 443
- does tls termination
- and proxying, nginx:
proxy_pass 127.0.0.1:8001;
- SSH Tunnel
- local machine port 8000 http server
SSH Config
port forwarding can also be specified on the client in ~/.ssh/config
:
Host server-01
HostName 192.168.1.2
Port 22
User clusteradm
LocalForward localhost:9001 localhost:9000
RemoteForward 8001 localhost:8000
KeepAlive yes
IdentitiesOnly yes
IdentityFile ~/.ssh/server_01_clusteradm
Config format is (Local|Remote)Forward target source
connect via $ ssh server-01
Persistent connections
Just use the autossh
command in place of ssh
. AutoSSH uses heartbeats to check if the connection is still open and
open another one otherwise automatically and fully transparent.
Dedicated tunneling server
It’s possible to run a standalone ssh server which just allows port forwarding and no remote command execution. Setup:
mkdir -p /jail
adduser --gecos "" --no-create-home --shell /bin/false --disabled-password --uid 1000 sshtunnel
Excerpt from /etc/ssh/sshd_config
:
# AllowUsers list all users which should be able to login
AllowUsers sshtunnel
Match User sshtunnel
PermitTTY no
Banner none
X11Forwarding no
AllowAgentForwarding no
# AllowTcpForwarding: yes (= local+remote), local, remote, no
AllowTcpForwarding local
GatewayPorts no
PermitTunnel no
ChrootDirectory /jail
ForceCommand /bin/false
PermitOpen 127.0.0.1:8730
Start sshd in foreground: $ sshd -D -e
Connect client: $ ssh -N -L 127.0.0.1:8730:127.0.0.1:8730 sshtunnel@localhost
Flag -N
prevents the spawning of a shell (which would result in a connection abortion otherwise).
Rsync tunneling (also sftp)
rsync
can copy (sync) files between hosts. Therefore, it can use ssh as a transfer protocol. But that implies running
the rsync command on the server:
rsync -av -e ssh user@host:/backup/ /datadir/
That won’t work with a tunneling only ssh server. Luckily rsync can also be operated with a standalone server, so the rsync protocol can be tunneled via ssh.
Server Setup
adduser --gecos "" --no-create-home --shell /bin/false --disabled-password --uid 1001 rsyncbackup
sudo mkdir -p /jail/backup
sudo chown -R root:root /jail # user cannot have write permission to chroot dir
sudo chown -R rsyncbackup:rsyncbackup /jail/backup
sudo chmod -R 755 /jail/backup
Excerpt from /etc/ssh/sshd_config
:
# allow sftp connections
Subsystem sftp internal-sftp
# AllowUsers list all users which should be able to login
AllowUsers rsyncbackup
Match User rsyncbackup
PermitTTY no
Banner none
X11Forwarding no
AllowAgentForwarding no
# AllowTcpForwarding: yes (= local+remote), local, remote, no
AllowTcpForwarding local
GatewayPorts no
PermitTunnel no
ChrootDirectory /jail
ForceCommand internal-sftp
PermitOpen 127.0.0.1:8730
In addition to rsync this config also allows file browsing via sftp in the /jail
dir.
Rsync server config in /etc/rsyncd.conf
:
use chroot = true
hosts allow = 127.0.0.1/32
port = 8730
timeout = 300
max connections = 2
reverse lookup = no
log file = /dev/stdout
log format = %h %o %f %l %b
pid file = /var/run/rsyncd.pid
[backup_sink]
comment = Backup
path = /jail
read only = no
list = yes
uid = rsyncbackup
gid = rsyncbackup
Start rsync server: $ rsync --daemon --config /etc/rsyncd.conf
Client Setup
Record in .ssh/config
:
Host backup-conn
HostName 192.168.1.32
Port 2201
User rsyncbackup
KeepAlive yes
LocalForward 127.0.0.1:8730 127.0.0.1:8730
Run a rsync job:
ssh -N backup-conn & # no tty possible, either use pubkey-auth or use sshpass to submit the password
pid=$!
sleep 3
time rsync bigfile rsync://localhost:8730/backup_sink/backup
kill $pid
Check that /jail/backup/bigfile
has been created on the server.