In the past, I’ve typically disabled password login on my servers, used SSH keys, and called that “good enough” security for what I’m doing. Security must be pragmatic – it makes no sense to go to extraordinary lengths to secure things when the value of what you are securing is not all that high. Security is a tradeoff – typically it comes with a loss of convenience.
One of the problems with an SSH port exposed to the Internet is you constantly have people attacking it, trying to get in with various passwords – never mind you disabled password login. The logs are full of this:
Failed password for invalid user jms from 43.153.175.28 port 34778 ssh2
You can move your SSH port to something other than port 22, but hackers eventually figure this out as it is easy to do a port scan.
In the past, VPNs were not all that attractive as they were complex to set up and questionable if they were really more secure than SSH itself – complexity is the enemy of security. However, with Wireguard, this has all changed.
WireGuard has been designed with ease-of-implementation and simplicity in mind. It is meant to be easily implemented in very few lines of code, and easily auditable for security vulnerabilities. Compared to behemoths like *Swan/IPsec or OpenVPN/OpenSSL, in which auditing the gigantic codebases is an overwhelming task even for large teams of security experts, WireGuard is meant to be comprehensively reviewable by single individuals.
So, I’m reading through the Wireguard documentation. In the whitepaper, I learned that Wireguard does not even respond if a packet does not authenticate.
5.1 Silence is a Virtue
One design goal of WireGuard is to avoid storing any state prior to authentication and to not send any responses to unauthenticated packets. With no state stored for unauthenticated packets, and with no response generated, WireGuard is invisible to illegitimate peers and network scanners. Several classes of attacks are avoided by not allowing unauthenticated packets to influence any state.
Therefore, it is not even possible to know if a Wireguard VPN server exists on a machine by probing it, unlike a SSH port which requires the use of stateful TCP (WireGuard by default uses UDP).
Additionally, Wireguard requires the use of keys, so there is no incentive to try passwords. Thinking through this a bit more, closing the external SSH ports and using Wireguard gives you two levels of security:
You have to break through both Wireguard and SSH to gain shell access to the machine. You don’t lose any security by adding Wireguard, other than it might provide access to ports behind your firewall if Wireguard is compromised. Given that Wireguard is relatively easy to set up, I’m starting to think it makes sense.
There are still tradeoffs … one of the biggest risks of advanced security mechanisms, like MFA, is you will lock yourself out. In the case of a Wireguard VPN server, there is now a single point of failure if you have a single VPN server, or rely on a single provider like Tailscale. However, given how reliable cloud servers are at companies like Linode, it seems this risk is small, especially if you back up the keys and configuration. In a pinch, you could also log in through the console (most cloud server hosting providers offer this) and re-enable external SSH access.