summaryrefslogtreecommitdiffstats
path: root/content/posts/openbsd-vpn-gateway/index.org
blob: e1aadd0f745017ac23b1f3cd3a2be463cfc05f79 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#+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. You may
  also want to consider checking out my [[{{< ref openbsd-introduction-talk >}}][Introduction to OpenBSD]] talk.

* 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.<if>=, where =<if>= 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<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> 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=, and your traffic should be going through
   the VPN. To easily check this you can make a request to a service
   like https://icanhazip.com or https://ifconfig.so using the =ftp=
   command.

   #+BEGIN_SRC shell
   ftp -o- https://canhazip.com 2>/dev/null
   #+END_SRC

   This should output your current external IP address, which should
   belong to your VPN provider.