Projet

Général

Profil

Openbsd wireguard rdomain » Historique » Révision 2

Révision 1 (sacha, 11/11/2020 21:48) → Révision 2/3 (sacha, 11/11/2020 21:49)

--- 
 Title: Setting up a WireGuard® client with routing domains on OpenBSD 
 langs: en 
 Breaks: False 
 --- 

 
 # Setting up a WireGuard® client with routing domains on OpenBSD 

 _Matthieu Herrb - last edited october 24, 2020._ 

 OpenBSD-current recently got native support for the [Wireguard®](https://wireguard.com/) VPN, thanks to the work of Matt Dunwoodie and Jason A. Donefeld. Their code was merged by David Gwynne. 
 This is great, especially since I've been using WireGuard for various purposes already. 
 A local assocative ISP here in Toulouse is offering WireGuard based VPNs for 5€/month. 
 In this note, I'm going to show how to setup a machine running OpenBSD to connect to this kind of VPN, using routing domains to make the VPN the default interface. 

 This configuration can be used to get a fixed public IPv4 and IPv6 address for a self-hosted server to run any kind of internet services. 

 ## General principle 

 The client machine is going to connect to the internet via any kind of LAN that provides IPv4 DHCP auto-configuration. 
 It can be an ADSL or fiber modem at home or some enterprise network. 
 The only serious requirement is that UDP traffic on the WireGuard (51820) port goes out. 
 This connexion is only going to be used to connect to the VPN, and will be setup in routing domain 1. 
 The Wireguard connexion is going to be the _egress_ connexion in the default routing domain (0). 

 In this setup there is no need to provide complicated routing or packet filter configuration. 
 All traffic will go through the VPN "naturally" as the default routing domain only knows about the VPN interface. 

 ### Routing Domains and routing tables 

 For those not familiar with routing domains and tables on OpenBSD, it is recommended to read the [rdomain(4)](https://man.openbsd.org/rdomain.4) manual page. 
 Routing domains are separated network address spaces in the OpenBSD kernel. 
 Each routing domain has at least one routing table, separated from the routing tables of other domains. 
 Network interfaces belong to one domain and are not usable by the others. 
 Also, processes are running inside a routing domain, using by default the default routing table of their domain. 
 So their network traffic can only use the interfaces in this domain. 

 So routing domains and tables are a great way to isolate network trafic between processes. 

 ### WireGuard® at Tetaneutral.net 

 The [Tetaneutral.net](https://www.tetaneutral.net/) non-profit ISP provides WireGuard based VPN connections with one fixed IPv4 address and a /56 IPv6 prefix. 
 When you subscribe to the service, you provide the public key for your end point, and Tetaneutral gives you back the assigned IP adresses and the IP address, port number and public key of the VPN endpoint. 

 It is likely that many other ISP providing WireGuard based VPNs will work approxymately the same as Tetaneutral, and thus this can be expaned easily. 
 You can even setup your own WireGuard VPN service using OpenBSD, but this is out of the scope of this note. 

 ## Let's go ! 

 ### OpenBSD installation 

 OpenBSD is installed as usual on the machine, setting up the network connection for the network on which it is going to have its internet access. 
 In this example the __re0__ interface is going to be used for this. So with DHCP `/etc/hostname.re0` looks like: 

     dhcp 

 ### Obtaining VPN parameters 

 Install the `wireguard-tools` package, to have access to the [wg(8)](https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8) command: 

     $ pkg_add wireguard-tools 

 Now the parameters for the VPN are needed. For this a private key will be generated using the following commands: 

     $ umask 077 
     $ wg genkey > /etc/wg0.key 

 The corresponding public key is displayed by the following command: 

     $ wg pubkey < /etc/wg0.key 

 _Note:_ if you don't want to install the `wireguard-tool` package, the [wg(4)](https://man.openbsd.org/wg.4) manual page describes an alternate way to generate the private key and display the public key using tools in the base system. 

 To obtain the remaining of the parameters, contact the VPN provider and send them the public key shown above. 
 They should reply providing: 

 (the values below are fake examples) 

 - the IP and port number of their endpoint: `198.51.100.116 51820` 
 - the public key of their endpoint: `Qay+wLckmRMr08t/9psjhrltJ0T4xb0m8++gQj0FpEA=` 
 - the IPv4 and IPv6 prefix assigned to your endpoint: `203.0.113.3/32` and `2001:db8:8087:300::/56` respectively. 
 - the addresses of the DNS servers that can be used inside the VPN: `198.31.100.10` and `198.51.100.11` 

 Keep those informations somewhere, to use them later. 

 ### Moving the default interface to rdomain 1 

 Now edit `/etc/hostname.re0` to add a `rdomain` directive to move this interface to rdomain 1: 

     rdomain 1 
     dhcp 

 That's it. If the machine is rebooted at this point, most processes won't have network access since only routing domain 1 has network access. So do not reboot for now. 

 ### Creating the VPN interface 

 A __wg0__ interface for the VPN is going to be setup. For this create the `/etc/hostname.wg0` file, containing (using the fake information form the provider shown above): 

     up 
     wgkey <your wg private key> 
     wgpeer Qay+wLckmRMr08t/9psjhrltJ0T4xb0m8++gQj0FpEA= wgrtable 1 wgendpoint 198.51.100.116 51820 wgaip 0.0.0.0/0 wgaip ::/0 
     inet 203.0.113.3 255.255.255.255 
     inet6    2001:db8:8087:300::1 56 
     ! route add default -link -iface wg0 
     ! route add -inet6 default -link -iface wg0 

 The last two lines set up the default route for rdomain 0 via the `wg0` interface. 

 Once `/etc/hostname.wg0` is created, the `/etc/wg0.key` file created previously can be removed. 
 It was only used to keep the private key while obtaining the remaining information needed to create `hostname.wg0` 

 ### Setting up the DNS 

 There are different options to tell the VPN client which DNS resolvers to use. 
 The issue is that `/et/resolv.conf` still contains the adresses of the DNS servers on the LAN, provided by dhclient(8). 
 Generally when using a VPN you don't want to use those, because they will leak the domains that the users of the VPN are connecting to. 

 #### Simple forwarding 

 The simplest solution is to use the _supersede_ option of [`dhclient.conf(5)`](https://man.openbsd.org/dhclient.conf.5) to replace the DHCP provided servers by the ones provided by the VPN provider. This will be the contents of `/etc/dhclient.conf`: 

     supersede domain-name-servers 198.51.100.10, 192.51.100.11; 

 #### Using unwind(8) 

 Another option is to set up [unwind(8)](https://man.openbsd.org/unwind.8), with an [`unwind.conf(5)`](https://man.openbsd.org/unwind.conf.5) configuration file specifying the VPN name servers as forwarders. 

 Add the DNS servers provided by the VPN provider in `/etc/unwind.conf` (see [`unwind.conf(5)`](https://man.openbsd.org/unwind.conf.5) for details): 

     forwarder { 198.51.100.10 192.51.200.11 } 
    
 Activate unwind with 

     rcctl enable unwind 
    
 And edit `/etc/dhclient.conf` to contain: 

     prepend domain-name-servers 127.0.0.1 ; 
    
 This solution also allows processes in routing domain 1 to use the DNS servers provided by the DHCP server.  

 ### SSH access from the LAN 

 If you want to be able to continue accessing the machine from the lan it is connected to, `/etc/ssh/sshd_config` needs to be told to also listen to routing domain 1. 

     ListenAddress 0.0.0.0 rdomain 0 
     ListenAddress :: rdomain 0 

     ListenAddress 0.0.0.0 rdomain 1 

 Otherwise, after reboot, the machine will only be accessible from the console and with SSH though the VPN. 

 ### Rebooting 

 And that's it. The machine can now be rebooted. 
 All processes in the default routing domain (0) will only see the `lo0` and `wg0` interfaces, while the dhclient process needed to bring up `re0` will be in routing domain 1. 
 The `wgrtable` keyword in the wg0 interface configuration tells it ue use the routing table of routing domain 1 to reach the remote VPN endpoint. 

 ## Checking that it works 

 After rebooting, let's review the setup by cheching the `wg0` interface: 

     # ifconfig wg0 
     wg0: flags=80c3<UP,BROADCAST,RUNNING,NOARP,MULTICAST> mtu 1420 
         index 6 priority 0 llprio 3 
         wgport 47326 
         wgrtable 1 
         wgpubkey <public key> 
         wgpeer Qay+wLckmRMr08t/9psjhrltJ0T4xb0m8++gQj0FpEA= 
                 wgendpoint 198.51.100.116 51820 
                 tx: 45564, rx: 71200 
                 last handshake: 107 seconds ago 
                 wgaip ::/0 
                 wgaip 0.0.0.0/0 
         groups: wg egress 
         inet    203.0.113.3 netmask 0xffffffff 
         inet6 2001:db8:8087:300::1 prefixlen 56 

 And the default routes: 

     # route -n show    | grep default 
     default              link#6               ULS          5        229       -       8 wg0   
     default                              link#6                           ULS          0          4       -       8 wg0 

 You can test that all traffic will go through the VPN using [traceroute(8)](https://man.openbsd.org/traceroute.8). 
 The machine is reachable from the internet using both its public IPv4 and IPv6 addresses. 

 Finally, the `ps` command with option `-o rtable` will show routing table information in the last column:  

     # ps xau -o rtable 
     USER         PID %CPU %MEM     VSZ     RSS TT    STAT     STARTED         TIME COMMAND            RTABLE 
     root           1    0.0    0.0     468     408 ??    I         4:43PM      0:01.02 /sbin/init              0 
     root       95458    0.0    0.0     788     620 ??    Ip        4:43PM      0:00.24 /sbin/slaacd            0 
     _slaacd    30350    0.0    0.0     792     676 ??    Ip        4:43PM      0:00.08 slaacd: engine (        0 
     _slaacd    69167    0.0    0.0     800     720 ??    Ip        4:43PM      0:00.08 slaacd: frontend        0 
     root       59774    0.0    0.0     704     528 ??    IU        4:43PM      0:00.02 dhclient: re0 [p        1 
     _dhcp      30649    0.0    0.0     828     656 ??    Ip        4:43PM      0:02.77 dhclient: re0 (d        1 
     root       35197    0.0    0.1     548    2252 ??    IpU       4:44PM      0:00.02 syslogd: [priv]         0 
     _syslogd    1991    0.0    0.1    1120    1384 ??    Ip        4:44PM      0:00.14 /usr/sbin/syslog        0 
     root       76166    0.0    0.0     836     584 ??    IU        4:44PM      0:00.01 pflogd: [priv] (        0 
     _pflogd     9499    0.0    0.0     884     564 ??    Sp        4:44PM      0:01.26 pflogd: [running        0 
     _ntp       45580    0.0    0.1    1044    2872 ??    I<p       4:44PM      0:00.72 ntpd: ntp engine        0 
     _ntp       59996    0.0    0.1     888    2560 ??    Ip        4:44PM      0:00.09 ntpd: dns engine        0 
     root       30954    0.0    0.1     848    1616 ??    I<pU      4:44PM      0:00.06 /usr/sbin/ntpd          0 
     root       75315    0.0    0.1    1328    1496 ??    I         4:44PM      0:00.16 sshd: /usr/sbin/        0 
     root       60900    0.0    0.1    1716    2028 ??    Ip        4:44PM      0:00.07 /usr/sbin/smtpd         0 
     _smtpd     65700    0.0    0.2    1448    3832 ??    Ip        4:44PM      0:00.08 smtpd: klondike         0 
     _smtpd     90699    0.0    0.2    1656    4044 ??    Ip        4:44PM      0:00.07 smtpd: control (        0 
     _smtpd     31369    0.0    0.2    1536    3936 ??    Ip        4:44PM      0:00.07 smtpd: lookup (s        0 
     _smtpd     45982    0.0    0.2    1596    4064 ??    Ip        4:44PM      0:00.06 smtpd: pony expr        0 
     _smtpq     17106    0.0    0.2    1664    4048 ??    Ip        4:44PM      0:00.08 smtpd: queue (sm        0 
     _smtpd     94920    0.0    0.2    1444    3872 ??    Ip        4:44PM      0:00.05 smtpd: scheduler        0 
     _sndiop    35803    0.0    0.0     524     936 ??    IpU       4:44PM      0:00.00 sndiod: helper (        0 
     _sndio     61376    0.0    0.0     536     808 ??    I<p       4:44PM      0:00.00 /usr/bin/sndiod         0 
     root       97224    0.0    0.0     204     836 ??    I         4:44PM      0:00.01 /usr/sbin/apmd -        0 
     root       98386    0.0    0.1     668    1312 ??    Sp        4:44PM      0:00.08 /usr/sbin/cron          0 
     root       27323    0.0    0.0     940     932 p0    Ip        5:13PM      0:00.36 -ksh (ksh)              0 
     root       49147    0.0    0.0     484     432 p0    R+pU/3    6:30PM      0:00.00 ps -xau -o rtabl        0 
     root       42404    0.0    0.1     316    1312 C1    I+pU      4:44PM      0:00.03 /usr/libexec/get        0 
     root       52228    0.0    0.1     320    1308 C2    I+pU      4:44PM      0:00.02 /usr/libexec/get        0 
     root       71695    0.0    0.1     316    1308 C3    I+pU      4:44PM      0:00.03 /usr/libexec/get        0 
     root       90445    0.0    0.1     320    1320 C5    I+pU      4:44PM      0:00.03 /usr/libexec/get        0 

 Only the dhclient(8) processes are in the non-default routing domain 1. 

 ## What's next ? 

 As already said above, the machine is now reachable from the internet. 
 So perhaps [pf(4)](https://man.openbsd.org/pf.4) needs to be configured to be more restrictive.  
 [sshd(8)](https://man.openbsd.org/sshd.8) can be configured to refuse password based authentication, in order to avoid brute force attacks. 

 You can then point a domain (leased from a registrar) to the IP addresses of the machine and [httpd(8)](https://man.openbsd.org/httpd.8) can be set-up to provide web based services on this domain. 

 Or another interface can be added to that host to convert it into a router to connect to another network. 
 This can be either another physical interface or a vlan interface over the existing re0 interface.