Site to Site VPN with Wireguard Between Mikrotik RouterOS and OpenBSD_

🇺🇦 Resources to help support the people of Ukraine. 🇺🇦
Original: March 30, 2022 @21:58 Edited: April 01, 2022 @23:20

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.

RouterOS

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

OpenBSD

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 /etc/hostname.wg0 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 by running /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]

Conclusion

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.

Addendum

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.

Subscribe via RSS. Send me a comment.