Skip to main content

Recently, a customer needed to implement a remote access solution with two-factor authentication, but could not install any third party software. The solution: Putty, two SSH instances, VNC and WiKID. Using two SSH instances allows requiring both radius for WiKID and public keys and using the "permitopen=" directive limits the user to only VNC.

These are the requirements for our VPN setup:

  • We must be able to use a given laptop with a strict policy (ie. we cannot install any third party applications, including VPN clients..).
  • Luckily, putty is an approved application for these laptops.
  • Two factor authentication
  • Full control over which services are available to a VPN user.
  • Log facilities (user logins)
  • .

With these requirements in mind, we decided to implement a solution based on SSH and WiKID.

Our initial plan was to have an SSH server we could log into from an un-trusted network, and then tunnel a connection to an RDP/VNC session on the user's dedicated workstation at the office. In essence, something like this:

Home -> SSH -> Workstation

Since we need full control over what the user's allowed to do on his VPN connection, we can't use a simple 'ssh -L5901:workstation:5901', as the user might attempt to connect to other services (eg. another user's workstation).

So, in order to control what a user wants to forward when connected to a SSH server, we will be using the ~/.ssh/authorized_keys file and the permitopen=-directive, and thus require public key authentication.

However, we were not able to make a single SSH instance require authentication against both PAM and public key. So, we ended up running two SSH-instances - one instance accepting only public keys (eg. on port 22/tcp), and the other (eg. on port 2222/tcp) authenticating only using PAM. In order to force the user to connect to the second SSH instance, we used the command=-directive in authorized_keys. So, now we had something like this:

Home -> SSH (Public Key Auth.) -> SSH (PAM/WiKID Auth.) -> Workstation

The ~/.ssh/authorized_keys for a user would look similar to this:

permitopen="localhost:3010",command="/usr/bin/ssh -p 2222
-L3010:workstation:5901 user@localhost \"echo 'Connected. Press Enter to
close tunnel'; read\"" ssh-rsa AAAAA[...]

The VPN user would set up his forwarding like this:

ssh -L5901:localhost:3010

..which would be the only allowed forwarding, and he should be able to connect to his VNC session at the office workstation using 'vncviewer localhost:1'.

This solution might not scale that well though, as it requires a unique port (such as the localhost:3010) for each service a VPN user should be allowed to access. But, in our case it's sufficient.

Here are some config highlights:

/etc/ssh/sshd_config for SSH accepting only public keys:

Port 22
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
PubkeyAuthentication yes
PasswordAuthentication no
UsePAM no

/etc/ssh-forward/sshd_config for accepting only PAM auth. (radius/wikid)

Port 2222
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
PubkeyAuthentication no
UsePAM yes

We also made a few changes on /etc/pam.d/ssh to make sure the second SSH instance would only accept radius auth. and not fall back on any other mechanism.


# Radius authorization
auth       required           /lib/security/

# Standard Un*x authentication.
#@include common-auth   <---- Disable common-auth

That's pretty much what we did, on a Debian Etch installation. Hopefully, this would be useful to someone else as well :)

The author of this how-to wished to remain anonymous.


Copyright © WiKID Systems, Inc. 2024 | Two-factor Authentication