Recipe: Forward insecure TCP-based protocol
Some protocols are hard to use securely and privately. This is often caused by a lack of a standardized and secure encryption layer, incomplete/broken implementations or local deployment hurdles.
Such protocols can be tunneled though SSH to add the desired properties. A prime example (which we will use in this chapter) is the VNC protocol.
Example scenario
Users want to access the machine lab01
which is running some VNC server as
well as an OpenSSH server.
Generate dedicated port forwarding ssh key
OpenSSH CLI client
Create a dedicated ssh key for connection tunneling on your local machine (see
man ssh-keygen
for all options):
ssh-keygen -C 'ssh port forwarding only (you full name or email address)' \
-t ed25519 -f ~/.ssh/portforwarding
PuTTY(gen)
Run PuTTYGen. Pick a sensible key type (we recommend EdDSA with the Ed25519 curve). Press Generate to create a new key.
Edit the key comment. Save the private key using the Save private key button. Copy the public key in OpenSSH format from the textbox and save it in a textfile.
Load the private key into PuTTY’s ssh agent Pageant (simply doubleclick the secret key file on Windows). Create a link in the Startup folder to load the key on every login.
Serverside Setup
We will consider two variations:
- Enforced: Usage of SSH tunneling is mandatory and (if possible) enforced by system administration. Setup requires administrator level access to the server.
- Voluntary: Usage of SSH tunneling is not enforced but desired by the users themselved. This only requires user access to the server.
Pick the variant that matches your environment.
Enforced
To prevent (accidential) insecure access to the VNC server bind its socket only
to the loopback interface. Please refer to your VNC servers documentation for
details. You may check this by listing all listening sockets and filtering for
those of interest (subsitute ss
with netstat
on legacy systems):
ss -tlpn | grep vnc
LISTEN 0 32 127.0.0.1:5900 *:* users:(("x11vnc",pid=.....,fd=4))
LISTEN 0 32 [::]:5900 [::]:* users:(("x11vnc",pid=.....,fd=5))
Socket values of 127.0.0.1
, ::1
, [::1]
, and localhost
indicate local
listeners only. Public IP addresses and hostnames, *
, ::
or [::]
indicate a
potentially publicly accessible service.
Another option to prevent remote access is to disable external access using the local firewall. Please refer to your distributions documentation for details.
Create a dedicated system user called portforwarding
:
# CentOS/RHEL/Fedora:
adduser --comment "port forwarding only" --system --shell /usr/bin/false portforwarding
# Debian/Ubuntu:
adduser --gecos "port forwarding only" --system --shell /usr/bin/false portforwarding
Create ~portforwarding/.ssh/authorized_keys
file with the correct permissions:
mkdir -p ~portforwarding/.ssh
touch ~portforwarding/.ssh/authorized_keys
chown 700 ~portforwarding/.ssh
chown -R portforwarding: ~portforwarding/.ssh
chmod 600 ~portforwarding/.ssh/authorized_keys
Add public keys of every user that needs VNC access to
~portforwarding/.ssh/authorized_keys
.
Edit /etc/ssh/sshd_config
and add the following section:
Match User portforwarding
AllowAgentForwarding no
AllowTcpForwarding local
AuthenticationMethods publickey
Compression no
ForceCommand /usr/bin/sleep 36500d
LogLevel VERBOSE
PasswordAuthentication no
PermitOpen localhost:*
PermitOpen 127.0.0.1:*
PermitOpen [::1]:*
PermitTTY no
X11Forwarding no
See man sshd_config
for details and explanations. Restart sshd
.
Voluntary
(This assumes that the user has a local account on lab01
).
Log into lab01
and paste your port forwarding public key into
~/.ssh/authorized_keys
. Prepend this string (don’t miss the single space at
the end):
restrict,no-pty,port-forwarding,permitopen=localhost:*,permitopen=127.0.0.1:*,permitopen=[::1]:*,command="/usr/bin/sleep 36500d"
(See the sshd
-manpage under “authorized_keys file format” for details).
Clientside setup
The setup on the client is the same for both variants.
OpenSSH CLI Client
All examples will forward TCP port 5900 from the remote side (lab01
) to port
5900 locally. Edit according to your local use case.
Add these two snippets to your local SSH client configuration in ~/.ssh/config
.
The first one is a generic template for all tunnel setups.
# generic tunnel settings
Host tunnel_*
ExitOnForwardFailure yes
IdentityFile ~/.ssh/portforwarding
User portforwarding
RequestTTY no
This snippet describes a concrete host.
Host tunnel_lab01
Hostname lab01.enter-fqhn-here
LocalForward 127.0.0.1:5900
Simply open a tunnel with
ssh -v tunnel_lab01
TODO: systemd-unit
PuTTY