#+TITLE: Creating a VPN Gateway with OpenBSD 6.7 #+DATE: 2020-07-11T13:48:25-04:00 #+DRAFT: true #+DESCRIPTION: #+TAGS[]: openbsd openvpn #+KEYWORDS[]: openbsd openvpn #+SHOWTOC: true #+SLUG: #+SUMMARY: * The Problem Say you have an account with a VPN provider. Maybe there are a limit to how many connections you can have with one account, and you want to put more machines than you have connections on the account. Or maybe you want to put a large number of machines of the connection, including maybe FreeBSD Jails, LXC containers, or VMs, and you don't want to download the VPN profiles, sign in and configure them all individually. * The Solution The solution I came up with to this problem is to setup a VPN gateway on my network using [[https://www.openbsd.org/faq/pf/][OpenBSD]]. Any device that sets that machine as it's gateway will automatically get its traffic tunneled through the VPN connection. It's also setup such that if the VPN connection ever drops or gets killed for any reason, the traffic will stop and won't be able to reach the internet. Thanks to this I don't have to worry about the traffic ever leaking out through my residential gateway should OpenVPN decide to close the connection. Sort of like a "kill switch", as some companies market it. * Our Network In this post the machine will have a single network interface called =vio0= with a desired static IP of =192.168.0.11= and a =/24= subnet, although the interface and IP in your case will be differ. * Hardware To replicate my setup you'll need a dedicated machine running OpenBSD. You'll have to choose an appropriate host, taking into consideration how much traffic you plan to put through it, the speed of you VPN connection, and the speed of your home internet connection. Anything from a virtual machine or a low power single board PC will do in most cases, as home internet connections generally aren't the fastest. If your internet connection is fast enough though, you may consider [[https://blog.lambda.cx/posts/installing-openbsd-on-pcengines/][installing OpenBSD]] on a [[https://blog.lambda.cx/posts/pcengines-comparison/][PC Engines APU2]], as they're affordable, have gigabit Ethernet, and great OpenBSD driver support. In my case I created a virtual machine on a server in my house running [[https://www.proxmox.com/en/][Proxmox]]. In my case, the machine only has 1 vCPU and 512 MB RAM, which is more than enough for my needs. * Documentation I highly recommend you check out the man pages for the firewall configuration file format [[https://man.openbsd.org/man5/pf.conf.5][=pf.conf(5)=]], and the pf control command [[https://man.openbsd.org/man8/pfctl.8][ =pfctl(8)=]] if you plan on setting something like this up. They're all very well written and explain a lot of what I'm doing in very clear detail. You should also read the excellent [[https://www.openbsd.org/faq/pf/][PF FAQ]] from the OpenBSD website, which covers many more PF configuration examples. * Install OpenBSD I won't be covering installing OpenBSD here, although it's extremely simple and straight forward. You can pick up the disk =.iso= image or USB =.fs= image from the [[https://www.openbsd.org/faq/faq4.html#Download][download]] page on OpenBSD website. If this is your first time installing OpenBSD, you should check out the [[https://www.openbsd.org/faq/faq4.html#Download][ installation guide]], which goes over the process in detail. * Configuring a Static IP The most important thing is to set a static IP, so it can be set as the gateway for client machines. We'll set this first. Setting a static IP in OpenBSD couldn't be simpler. For each interface on the machine, you can create a [[http://man.openbsd.org/man5/hostname.if.5][=hostname.if(5)=]] file with the name =/etc/hostname.=, where == is the name of the interface. Since we want to set a configure the interface =vio0=, the file we want is =/etc/hostname.vio0=. If your box was configured with DHCP, the file might contain =dhcp=. We want to give the interface the static IP =192.168.0.11= with a =/24= subnet. We use [[https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing][CIDR notation]] here for convenience. We open the file and replace its contents with the following. #+BEGIN_SRC inet 192.168.0.11/24 #+END_SRC Now we run [[https://man.openbsd.org/man8/netstart.8][=netstart(8)=]] to reconfigure the interface according to the file we've just edited. #+BEGIN_SRC shell dosa sh /etc/netstat vio0 #+END_SRC Now if we check [[http://man.openbsd.org/man8/ifconfig.8][=ifconfig(8)=]], we should see the interface has the correct IP. #+BEGIN_SRC shell ifconfig vio0 #+END_SRC #+RESULTS: : vio0: flags=8843 mtu 1500 : lladdr AA:BB:CC:DD:EE:FF : index 1 priority 0 llprio 3 : groups: egress : media: Ethernet autoselect : status: active : inet 192.168.0.11 netmask 0xffffff00 broadcast 192.168.0.255 * Configuring OpenVPN ** Installation First we have to install [[https://openvpn.net/][OpenVPN]], which is provided by the OpenBSD package manager. Normally we would install the =openvpn= package, but due to an [[{{< ref "openvpn-issues-openbsd" >}}][issue with libressl]], we'll be installing the =mbedtls= version. This problem should hopefully be resolved soon, so we'll likely be able to use regular =openvpn= in the future. #+BEGIN_SRC shell doas pkg_add openvpn--mbedtls #+END_SRC Note: The =--mbedtls= is required to get the =mbedtls= flavour of the =openvpn= package. ** VPN Profile Let's assume the VPN profile we've downloaded from our provider exists in =/root/profile.ovpn=. This could have been downloaded using [[https://man.openbsd.org/man1/ftp.1][=ftp(1)=]] or transferred on using [[https://man.openbsd.org/man1/sftp.1][=sftp(1)=]]. Let's say it also requires a username and password supplied by the user, as most commercial VPN providers authenticate users in this way. For this example, the username is =user@example.com= and the password is =password=. To allow OpenVPN to login to the VPN without the us having to enter our password, we can add the =auth-user-pass= directive to our =profile.ovpn= file. This will allow us run OpenVPN as a daemon, and restart it without having to type our username and password in. To do this we can create a file called =/root/vpnpasswd.txt= containing our username, followed my our password on a separate line. #+BEGIN_SRC user@examples.com password #+END_SRC We then edit our VPN profile, adding the following line somewhere. #+BEGIN_SRC auth-user-pass vpnpass.txt #+END_SRC Now we change their permissions to make sure they cannot be read or modified by other users on the system. #+BEGIN_SRC shell doas chmod 600 profile.ovpn vpnpasswd.txt #+END_SRC ** rcctl We can now set the OpenVPN daemon to launch at boot with our modified profile using =rcctl=. =rcctl= is a tool that comes with OpenBSD which modifies =/etc/rc.conf.local= on your behalf to ensure it's done properly. The use of =rcctl= is not strictly required, but highly recommended. #+BEGIN_SRC shell doas rcctl set openvpn flags --config /root/profile.ovpn doas rcctl enable openvpn doas rcctl start openvpn #+END_SRC - =rcctl set openvpn flags --config /root/profile.ovpn= tells =rcctl= to set the launch flags to the =openvpn= daemon to =--config /root/profile.ovpn=. This is an OpenVPN option that tells it to load its config from =/root/profile.ovpn=. - =rcctl enable openvpn=, enables the daemon at boot. - =rcctl start openvpn= starts the =openvpn= daemon. If things are configured correctly, you should now see a =tun= device in your =ifconfig=.