After contemplating how I would add 2FA to SSH login, as simply as possible, here’s what I came up with:
I have a couple of VPS’, and I was able to hide their world-accessible ssh ports inside a Wireguard tunnel (on each). So now there is no way to log into those VPS’, except by way of first establishing a Wireguard connection. Why would I do this? Wireguard acts the second factor of authentication I was wanting; as in, Wireguard is my own poor-man’s 2FA for SSH.
To limit SSH’s access to the Wireguard tunnel, I had to add only one line to my /etc/ssh/sshd_config:
ListenAddress 10.11.12.1
… where 10.11.12.1 is the IP address of the VPS within the Wireguard tunnel. Then I SSH to that address, once the tunnel is established, not the public IP address of the VPS.
Should Wireguard not start a boot time, for some strange reason, I have a backdoor to debug it: my hosting provider offers a serial console to these VPS’ over SSH. So two logins are required for that backdoor: once into the serial console server, and then once again on the command line (so I sort of have 2FA there as well, but not involving Wireguard).
This arrangement has been working well for about a month now. I haven’t needed to bail myself out with that serial console back door yet. I only mention this all now, after feeling confident that I can trust this arrangement.
PS: One of the VPS’ is running ISPconfig, which has a web interface for administrative tasks. I hid that web interface inside the Wireguard tunnel as well. From time to time, ISPconfig announces some security vulnerability with that web admin interface, and ISPconfig unfortunately does not upgrade itself thanks to Debian’s “unattended-upgrades” package, which I have installed. Note that I’ve hand-installed ISPconfig (an arrangement I really don’t like, and use as infrequently as possible).
This config was a bit trickier. In the file /etc/nginx/sites-enabled/000-ispconfig.vhost, at the top, I changed
server {
listen 8080 ssl;
listen [::]:8080 ssl ipv6only=on;
…to:
server {
#listen 8080 ssl;
listen 10.11.12.1:8080 ssl;
#listen [::]:8080 ssl ipv6only=on;
…then restarted nginx. This config change unfortunately did not persist across an ISPconfig update, which I hand-installed. I had to put it back again after the ISPconfig update.