Installing Wireguard
I’ve written blog posts about the network I maintain before. As I’ve implemented things, I’ve not just listed out things as a series of instructions, but included details about problems I’ve encountered that are specific to my environment. Now my last blog post on the subject of my network covered the migration from towers to Intel NUCs, I’ve talked about the Mastodon instance, and I’ve covered a bit of detail about a couple of servers. I’ve even talked about configuring SSH. Today I will discuss Wireguard, and while it can be as simple as most other instructions found on the Internet (there are numerous online resources), it isn’t always as straight forward when it comes to the real world.
History
Remote shell access to the NMRC mail server has always been needed for NMRC members. Originally this was done with a combination of SSH and firewall rules. Maintenance of this was kind of a pain in the ass, and frankly it was not ideal. However virtually all of the members had static IP addresses so it wasn’t that terrible for many years, but there were increasingly rough times for administering and/or accessing if one were mobile. Eventually Duo Security for Linux was implemented, and this strengthened things considerably. If you combined this with SSH keys you had the basis for a fairly decent secure connection.
However one of the things that has opened up, so to speak, was when you have the SSH port available to the public, you were subject to your logs filling up with dictionary attacks. Yes there were ways to mitigate against some of that behavior with tools like Fail2Ban (which has been used in the past) although this still involves leaving the SSH port open, and I wanted to come up with something that would allow me to prevent from exposing the SSH port to the world in the first place.
As a temporary solution, I was using Cloudflare tunneling as it was initially free for the features I wanted to use, and it seemed to function fine. However the domain I had registered for use with Cloudflare failed to automatically self-register (as a result of a mistake on my part), and therefore tunneling was down for a few hours. After the domain was re-registered, I tried testing the Cloudflare tunnel process and was disappointed in that I could not use the original setup I had before, and if I were to go ahead and continue forward it would require actually paying for it. I wasn’t thrilled using a cloud provider anyway, so I got rid of Cloudflare and decided on the Wireguard route.
As a side note, this is the danger of using some new tool or feature that is provided “free” by a for-profit vendor - in some cases, they might change things slightly, and all of the sudden you have to pay for things if you wish to continue using them. At least Wireguard is open source and well supported.
Risks
I had considered Wireguard before, and even did a threat model, but had been putting off setting things up as I had other projects I was working on. So first thing I did was revisit the overall risk - particularly if there are public-facing assets involved. There is the over-arching NMRC Threat Model Eval which is periodically updated, but for Wireguard there was a separate threat model completed. The biggest threats based upon existing monitoring is run-of-the-mill phishing, attacks against open services (mail and web services), and nation station sponsored attacks along multiple fronts.
I also didn’t like something I was seeing in most of the online examples of configuration. It basically states that as the admin I should create the configuration file and then send that to the end user for loading into their client. That’s fine, but the issue is that I am generating and sending them their keys. To put it simply, if the message that I was sending to them was intercepted by a third party, that third party could then access Wireguard as them. Granted they would still have to supply a login and password (or an SSH key) plus out-of-band MFA via Duo Security, but still. I didn’t like it, I wanted this to be a good added layer of security with as little risk as possible.
Setup
Before we begin, let me state that the server itself at the time of this blog post being published is running Ubuntu LTS Server 22.04, so if you’re running on another distribution there might be a few things different, but this should give you a basic idea.
First I set up the server itself. These were the steps I used:
$ sudo apt install wireguard $ wg genkey | sudo tee \ /etc/wireguard/private.key $ sudo chmod go= \ /etc/wireguard/private.key $ sudo cat /etc/wireguard/private.key | \ wg pubkey | sudo tee \ /etc/wireguard/public.key
I edited /etc/sysctl.conf and added the needed network routing support for Wireguard:
# For wireguard server support, # added 27Apr2024 net.ipv4.ip_forward=1
After I adding the above (and yes I add comments to config files as a reminder of what I did and when I did it), I ran the following to add the changes to the running system:
$ sudo sysctl -p
I needed to know the name of the main interface of the server, so I ran the following command (the response is for my server, to give you an idea of what to look for):
$ sudo ip route list default default via 162.196.226.78 dev enp100s0 proto static
On many systems the default interface is eth0, but on this system the interface (between dev and proto) is enp100s0. Time to edit the server’s /etc/wireguard/wg0.conf file:
$ sudo nvim /etc/wireguard/wg0.conf
I added the following text to it:
[Interface] Address = 10.66.6.1/24 SaveConfig = true PostUp = ufw route allow in on wg0 out on enp100s0 PostUp = iptables -t nat -I POSTROUTING -o enp100s0 -j MASQUERADE PreDown = ufw route delete allow in on wg0 out on enp100s0 PreDown = iptables -t nat -D POSTROUTING -o enp100s0 -j MASQUERADE ListenPort = 51820 PrivateKey = <add contents of /etc/wireguard/private.key here>
In the wg0.conf file, the Address is the IP address of the Wireguard server interface. SaveConfig means that after a peer has been added from the command line, its information will be added automatically to the config file. In the above example the PostUp and PreDown statements (with my interface of enp100s0) are wrapped for easier viewing in the blog post, but those are just four lines in the config file. The PostUp statements set up the firewall properly after the Wireguard server daemon has started, and the PreDown are executed during daemon shutdown right before it exits. The ListenPort is the UDP port the Wireguard server daemon listens on, typically the default is 51820 but feel free to change it to whatever you want. The PrivateKey is as you might have guessed, the contents of the server’s /etc/wireguard/private.key file.
Now we’re ready to get things running. A few more commands, first to allow UDP port 51820, and a few commands to make sure the Wireguard server will start after a reboot automatically:
$ sudo ufw allow 51820/udp $ sudo ufw reload $ sudo systemctl enable \ wg-quick@wg0.service $ sudo systemctl start \ wg-quick@wg0.service $ sudo systemctl status \ wg-quick@wg0.service $ sudo wg
For each NMRC member, I sent them a nearly-complete config file with the server’s public key and their IP address already assigned. I had also added in the server’s public key. Here’s an example of a nearly-complete config that was sent:
[Interface] PrivateKey = <add private key> Address = 10.66.6.2/32 [Peer] PublicKey = <server public key> AllowedIPs = 10.66.6.0/24 Endpoint = 162.196.226.75:51820
The plan was each NMRC member would get the same config file, except under the [Interface] section each member would have to add their own private key and they’d get a unique IP address, and in the [Peer] section I had added the server’s public key. Additionally I gave them rough instructions like telling them that they could set up the client on whatever platform they wanted, and this example config file had enough needed info in it to get them up and running. However before it would work, they’d need to send me a copy of their public key.
I obviously tried it out on myself with a laptop first, and it didn’t work out of the box. At first it I was scratching my head, but finally it dawned on me after checking logs that my firewall rules were still blocking access. Duh, of course. I had to add some firewall rules for the private IP address range to access the SSH port. I also added access to ports for retrieval and sending of email, allowing them to check NMRC mail remotely. This to me was a big one, as most of the access needed is for email, and that made it slightly less painful. So this is what I did on the server end:
$ sudo ufw status numbered $ sudo ufw insert <num> allow from \ 10.66.6.0/24 to any port 22 \ proto tcp $ sudo ufw insert <num> allow from \ 10.66.6.0/24 to any port 587 \ proto tcp $ sudo ufw insert <num> allow from \ 10.66.6.0/24 to any port 993 \ proto tcp
I ran the ufw command with the status numbered option to show me the list of firewall rules, mainly to allow me to put the new rules exactly where I wanted to in the list via the insert option. Once that was done, the client worked fine.
Wait! I did have to tell the server a bit about the client, or “peer” as it is often referred to. After I had the client’s public key, this is what I had to type in on the server to get the client set up:
$ sudo wg set wg0 peer \ peer-public-key \ allowed-ips 10.66.6.2
What did I do on the client side? My personal daily driver currently runs Pop!_OS, so I did the following:
$ sudo apt update $ sudo apt install wireguard $ wg genkey | sudo tee \ /etc/wireguard/private.key $ sudo chmod go= \ /etc/wireguard/private.key $ sudo cat /etc/wireguard/private.key \ | wg pubkey | sudo tee \ /etc/wireguard/public.key
I copied the contents of the private key file to the example /etc/wireguard/wg0.conf file I had created earlier, and then after I had populated the client’s [Peer] section with the public key of the server, all I had to do on my laptop was this:
$ sudo wg-quick up wg0
It should be obvious to disconnect I could re-run the command and substitute down for up. But that got me going, and it worked just fine.
Security Problem
Not long after I had this up and op, a couple of researchers put out a research paper for a flaw they had dubbed “Tunnel Vision”. On the server end, I was fine. However on the client end (where the meat of the flaw existed) this required some additional steps. Instead of detailing all of those steps, I am simply going to link to the Wireguard documentation on configuring and using network namespaces, which mitigates the Tunnel Vision attack. Granted I also have a travel router as well, so by connecting to that first which allows me to get an IP address from the travel router directly and not something from the Tunnel Vision attacker at the coffee shop (or wherever), I am protected that way as well. I’ve informed the rest of the NMRC members as well, and imagine as security nerds they will handle mitigations just fine.
Edit: In /etc/dhcp/dhcpclient.conf you can comment out the line that starts with “option rfc3442-classless-static-routes” and remove “rfc3442-classless-static-routes” from the list of options associated with “request” and this solves the Tunnel Vision problem, at least on Linux. (hat tip Dragos Ruiu).
Final Thoughts
This is a freeware solution, so a lot of the fancy bells and whistles (particularly for managing users, especially non-technical ones) are simply not there. As far as deployment goes, since the NMRC members are rather technical and security-minded, I can just provide them the sample config and ask for their public key when they have it, and they’re smart enough to find an appropriate Wireguard client, configure it, and get it up and running.
This doesn’t add significant risk, although it is another service exposed to the Internet, so there is that danger, as exemplified by Tunnel Vision. Most likely I’ll be adding Fail2Ban to function on Wireguard’s UDP port, but I want to get familiar with the traffic first before I start setting that up. That said, I feel like I’ve increased security instead of just adding a step. Years ago when all this NMRC stuff started, there wasn’t a need for mobile flexibility for clients, but now everyone (including myself) is on laptops and other mobile devices, connecting from anywhere and everywhere. At least I can accommodate mobility needs for my fellow NMRC members without introducing huge risks.