Many years ago I starting building out an extended layer 3 network using IPSec tunnels with GRE tunnels on top of them. As technology moved on I transitioned these from Linux to OpenBSD using isakmpd(8) and then eventually iked(8). I automated the various configuration steps using Puppet and all in all I have been very well served by this over the years. I use IPSec to terminate all of my road warrior client connections as well so it means that the complexity serves several needs. I happened to be upgrading some Mikrotik routers from RouterOS 6 to 7 and noticed they added Wireguard support. I had been hoping Ubiquiti would add Wireguard to the UniFi USG so I could try it out since the version of strongSwan they ship is embarrassingly out of date, but it seems like they have mostly abandoned that product. Armed with an excuse I set out to see what it would take to start up a tunnel.
Using the management firewall in my colo, I was able to create a new interface with two simple commands.
/interface wireguard add name=wireguard1 /interface wireguard peers add allowed-address=0.0.0.0/0 endpoint-address=<REDACTED> interface=wireguard1
RouterOS generated a random port to listen on and a random public / private
key pair. I eventually came back and used
openssl rand -base64 32 as
suggested by the OpenBSD ifconfig(8) manpage to generate a PSK to
provide additional confidence in the cryptography. With the interface up
I assigned an address to it, and added the interface and LAN network to the
default OSPF configuration.
/ip address add address=172.17.33.18/28 interface=wireguard1 /routing ospf interface-template add area=backbone-v2 interfaces=wireguard1 add area=backbone-v2 networks=[REDACTED] passive
Finally, I added the input rules to the firewall. I used the GUI for this so
I could drag them next to the other Input rules in the table. The commands
to create the rules from the CLI are as follows. Make sure to replace the
dst-port argument with the port number chosen by RouterOS when you created
the Wireguard interface. You can find this in the UI or by running
/interface/wireguard/print proplist listen-port where name=wireguard1.
/ip firewall filter add action=accept chain=input comment="Accept Input for WireGuard" dst-port=[PORT] protocol=udp add action=accept chain=input comment="Allow Input on wireguard1" in-interface=wireguard1
With the RouterOS side waiting for tunnel traffic all that was left was to
tackle the OpenBSD side. Configuring the tunnel interface was dead easy.
I read the wg(4) manpage and the appropriate section of the
ifconfig(8) manpage and was able to create a
file with the following information. A quick
doas sh /etc/netstart wg0
brought the tunnel up.
inet 172.17.33.17 255.255.255.240 wgkey [REDACTED] wgport [REDACTED] wgpeer [PEER_PUBLIC_KEY] \ wgendpoint [IP_AND_LISTEN_PORT_FOR_ROUTEROS] \ wgpsk [SAME_PSK_USED_ABOVE] wgaip 0.0.0.0/0 up
You can find the generated public key from RouterOS by using the UI or
/interface/wireguard/print proplist public-key where name=wireguard1.
I already have ospfd(8) running for my other tunnels so I simply
added the the new wg0 interface to my existing area in ospfd.conf(5)
and restarted ospfd. Moments later the adjacency was renegotiated and the
prefixes were routable.
Puppet for Extra Credit
Never one to leave well enough alone, and determined to spend the time up front to be lazy later on, I decided to ensure this was managed by Puppet. A quick manifest and template file later and I can now define wg(4) tunnel interfaces using hiera like below. (Note, I use eyaml to store secrets so all the key material is encrypted)
base::openbsd::interface::wg: wg0: descr: 'Wireguard Site Tunnels' inetAddr: '172.17.33.17' inetMask: '255.255.255.240' wgkey: [REDACTED] wgport: [REDACTED] wgpeers: - comment: '[REDACTED]' endpoint: '[REDACTED]' peer: [REDACTED] psk: [REDACTED]
IPSec, GRE, and similar networking technologies can be daunting for new people trying to put together secure networks and while they are widely supported in nearly every operating system they come with a rather steep learning curve. I will continue to use them for many years to come because of their maturity and availability (I can't beat the on-demand VPN tunnel I have configured on my iPhone for example), but having Wireguard working on embedded routers like the Mikrotik RouterBoard gives me another tool to reach for. I will use this when I rebuild my travel router setup and when I replace the UniFi USG at the office.
I went to add another Mikrotik peer to this and while it mostly worked, I had to statically route and configure the prefixes for each tunnel. After a brief exchange on the misc@ mailing list the behavior makes sense. Terminating multiple tunnels to a single wg(4) interface seems to make sense if you are connecting singular endpoints, however; I am building a more complex and dynamic network so I switched to configuring separate interfaces for each connection and everything came up no problem.