2017-04-30 : **UPDATED VERSION** AT THIS LINK WITH OPENBSD 6.1
INTRODUCTION :
___________________________________________________
___________________________________________________
In my previous articles we have seen how to build a home router being a VPN gateway based off FreeBSD
or OpenBSD. In these cases, we used an external VPN provider to connect to, and
route all of our encrypted traffic through it. However, while I received positive feeback, I also had legitimate questions about the trust given to the VPN provider. What if the VPN
provider is not honest and is in fact logging despite stating the opposite? What if he is malicious and watch his clients traffic? The VPN provider could also be perfectly honest,
but could be breached (OS vulnerability, OpenSSL/Heartbleed, Shellshock, etc...) by attackers then logging clients traffics. Or simply, may be we perfectly trust it, but we just
want to be in control of the VPN server itself.
Managing and controlling your own VPN server gives you the following advantages: no concurrent clients connections limit, dedicated server not used simultaneously by strangers, the choice of the OS and security parameters, and complete trust on your provider (yourself). On the other hand, depending on the server hosting provider and its prices, you may have a monthly bandwitdh limit, and in all cases, a server to maintain continuously (security patches, monitoring, backups, etc...). Also, the price will probably be a little higher when hosting your own server online. Using AirVPN I have a yearly price of 54€. Using a dedicated Virtual Private Server (VPS) for 5€ per month for instance, it makes 60€ per year. Using a VPS is cheaper than using a hardware dedicated server, while still being a dedicated (virtual) server. VPS can also be saved with whole OS snapshots, which is handy before attemping an upgrade.
Then, which VPS provider to choose? I have looked at a lot of them, looking for a rare one natively providing FreeBSD and OpenBSD. Better yet, allowing the use of custom ISO and booting onto it, and having a console access for the install or for rebooting into single user mode. I was looking at being able to do snapshots too, and have a choice of different datacenters in various countries. I have found such provider: Vultr. You can of course follow this article if you use or plan of using any other web hoster, dedicated server or VPS. It just happened that Vultr had all of the features I needed, and even more such as a Two-Factor Authentication (2FA) with Yubikey (Google Authenticator possible too). As a bonus they accept Bitcoin payments.
In the following, I assume you have chosen your server provider, and have a running OpenBSD 5.6 freshly installed. If you want installation instructions, you can check my OpenBSD VPN gateway article, keeping in mind it's best to let your interface in DHCP while installing it for the first time on your VPS. I also assume you have one root and one user account, the user account being in the wheel group, and allowed to use sudo, as described in my aforementioned article.
Managing and controlling your own VPN server gives you the following advantages: no concurrent clients connections limit, dedicated server not used simultaneously by strangers, the choice of the OS and security parameters, and complete trust on your provider (yourself). On the other hand, depending on the server hosting provider and its prices, you may have a monthly bandwitdh limit, and in all cases, a server to maintain continuously (security patches, monitoring, backups, etc...). Also, the price will probably be a little higher when hosting your own server online. Using AirVPN I have a yearly price of 54€. Using a dedicated Virtual Private Server (VPS) for 5€ per month for instance, it makes 60€ per year. Using a VPS is cheaper than using a hardware dedicated server, while still being a dedicated (virtual) server. VPS can also be saved with whole OS snapshots, which is handy before attemping an upgrade.
Then, which VPS provider to choose? I have looked at a lot of them, looking for a rare one natively providing FreeBSD and OpenBSD. Better yet, allowing the use of custom ISO and booting onto it, and having a console access for the install or for rebooting into single user mode. I was looking at being able to do snapshots too, and have a choice of different datacenters in various countries. I have found such provider: Vultr. You can of course follow this article if you use or plan of using any other web hoster, dedicated server or VPS. It just happened that Vultr had all of the features I needed, and even more such as a Two-Factor Authentication (2FA) with Yubikey (Google Authenticator possible too). As a bonus they accept Bitcoin payments.
In the following, I assume you have chosen your server provider, and have a running OpenBSD 5.6 freshly installed. If you want installation instructions, you can check my OpenBSD VPN gateway article, keeping in mind it's best to let your interface in DHCP while installing it for the first time on your VPS. I also assume you have one root and one user account, the user account being in the wheel group, and allowed to use sudo, as described in my aforementioned article.
SUMMARY :
___________________________________________________
___________________________________________________
-
INTRODUCTION
- PROTECTING YOUR NAKED SERVER
- SYSTEM & NETWORK
- DNS
- FIREWALL
- VPN SERVER
- SECURITY & ANONYMITY
CONCLUSION
LINKS
1. PROTECTING YOUR NAKED SERVER
___________________________________________________
___________________________________________________
OpenBSD default settings are very secure, and no services are listening on the outside except SSH. However SSH is listening on the default 22 port, accepting password authentication.
Before configuring our server, it is best to block any inbound access except from our computer public IP, and then take our time to lock down SSH. Let's start by a basic pf ruleset:
Replace "x.x.x.x" by your computer public IP address you are connecting from. You can check on http://whoer.net/ if you don't know it. Of course this ruleset is temporary. Now apply it:
We now have few things to do: create an SSH key, disable root login and password base authentication, and make SSH listening on another port as a bonus (to avoid automated scans adding "noise" to our logs). For Linux/BSD clients you can create a key with -t ed25519 as below, but for Windows your SSH client may only be compatible with keys created using -t rsa.
Then copy your public key to ~/.ssh/authorized_keys :
Copy the content of your private key "~/.ssh/id_ed25519" on the remote computer you will use to connect to your router, and set a permission of "600" on it. If on Linux or BSD, you will be able to connect later with "ssh -i your_private_key your_server_ip".
Now modify your SSH server with this temporary configuration, the TCP port 21598 being an example, choose the port you want. You can choose a higher port to avoid scans, or choose a port such as 443 to be able to connect to your server from everywhere, when outbound TCP port 22 could be blocked:
Restart sshd :
Connect from your remote computer with the private key, for instance with "ssh -i your_private_key your_server_ip", and check that connecting with your regular user and with the SSH key fully works. Once it's working, modify the following line in /etc/ssh/sshd_config :
Restart sshd :
On the client side, you can enable SSH key fingerprint visual display in /etc/ssh/ssh_config which displays your SSH key in hex format and an ACSCII graphic everytime you connect. Once you get used to the ASCII graphic of your server, you should notice if all of a sudden it is completely different (probably a man-in-the-middle):
You now have a SSH listening on a non default port, root denied from connecting in, password authentication disabled, and authencation based on SSH keys and passphrase. For further SSH hardening, read the following excellent article describing which protocols and ciphers to use for optimum security. I may in the future update the SSH settings given in this article to follow some of the advises from this page.
Finally, to update the system and packages easily, I really like to use "openup" from M:Tier:
M:Tier is a third party not related to OpenBSD project however, so you have to decide if you wish to trust their repository or not.
$ sudo vi /etc/pf.conf
block in quick from ! x.x.x.x # your public IP address
pass out quick
pass out quick
Replace "x.x.x.x" by your computer public IP address you are connecting from. You can check on http://whoer.net/ if you don't know it. Of course this ruleset is temporary. Now apply it:
$ sudo pfctl -f /etc/pf.conf
We now have few things to do: create an SSH key, disable root login and password base authentication, and make SSH listening on another port as a bonus (to avoid automated scans adding "noise" to our logs). For Linux/BSD clients you can create a key with -t ed25519 as below, but for Windows your SSH client may only be compatible with keys created using -t rsa.
$ ssh-keygen -t ed25519
Then copy your public key to ~/.ssh/authorized_keys :
$ cp ~/.ssh/id_ed25519.pub ~/.ssh/authorized_keys
Copy the content of your private key "~/.ssh/id_ed25519" on the remote computer you will use to connect to your router, and set a permission of "600" on it. If on Linux or BSD, you will be able to connect later with "ssh -i your_private_key your_server_ip".
Now modify your SSH server with this temporary configuration, the TCP port 21598 being an example, choose the port you want. You can choose a higher port to avoid scans, or choose a port such as 443 to be able to connect to your server from everywhere, when outbound TCP port 22 could be blocked:
$ sudo vi /etc/ssh/sshd_config
# Modify default listening port
Port 21598
# Authentication
PasswordAuthentication yes # temporary
PermitRootLogin no
AllowUsers YOUR_USER
AuthorizedKeysFile .ssh/authorized_keys
AllowTcpForwarding no
UsePrivilegeSeparation sandbox # Default for new installations.
Subsystem sftp /usr/libexec/sftp-server
Port 21598
# Authentication
PasswordAuthentication yes # temporary
PermitRootLogin no
AllowUsers YOUR_USER
AuthorizedKeysFile .ssh/authorized_keys
AllowTcpForwarding no
UsePrivilegeSeparation sandbox # Default for new installations.
Subsystem sftp /usr/libexec/sftp-server
Restart sshd :
$ sudo /etc/rc.d/sshd restart
Connect from your remote computer with the private key, for instance with "ssh -i your_private_key your_server_ip", and check that connecting with your regular user and with the SSH key fully works. Once it's working, modify the following line in /etc/ssh/sshd_config :
PasswordAuthentication no
Restart sshd :
$ sudo /etc/rc.d/sshd restart
On the client side, you can enable SSH key fingerprint visual display in /etc/ssh/ssh_config which displays your SSH key in hex format and an ACSCII graphic everytime you connect. Once you get used to the ASCII graphic of your server, you should notice if all of a sudden it is completely different (probably a man-in-the-middle):
$ sudo vi /etc/ssh/ssh_config
# Display fingerprint in hex and ASCII graphic when connecting
VisualHostKey yes
VisualHostKey yes
You now have a SSH listening on a non default port, root denied from connecting in, password authentication disabled, and authencation based on SSH keys and passphrase. For further SSH hardening, read the following excellent article describing which protocols and ciphers to use for optimum security. I may in the future update the SSH settings given in this article to follow some of the advises from this page.
Finally, to update the system and packages easily, I really like to use "openup" from M:Tier:
$ ftp https://stable.mtier.org/openup
$ chmod +x openup
$ sudo openup
===> Checking for openup update
===> Installing/updating binpatch(es)
===> Updating package(s)
$ chmod +x openup
$ sudo openup
===> Checking for openup update
===> Installing/updating binpatch(es)
===> Updating package(s)
M:Tier is a third party not related to OpenBSD project however, so you have to decide if you wish to trust their repository or not.
2. SYSTEM & NETWORK
___________________________________________________
___________________________________________________
A few tweaks we can make before configuring further our server. As Vultr VPS are hosted on SSD, it is a good idea to add in the fstab file the mount options "softdep" and "noatime".
The first one increase disk performances, while the second will prevent the "last access time" file properties to be written:
Your server has booted with DHCP and has acquired its network configuration from your VPS provider. As the server IP address is fixed, I prefer setting manually the network configuration to avoid relying on another server (VPS provider's DHCP and DNS) I do not control. Modify the following files according to your server public ip address, mask, and gateway:
Add the gateway :
Our server will forward traffic between its VPN interface and its default network interface. We have to enable forwarding:
At this point your still rely on your provider DNS server in /etc/resolv.conf, we will take care of that in the next step.
$ sudo vi /etc/fstab
YourDiskDUID.b none swap sw
YourDiskDUID.a / ffs rw,noatime,softdep 1 1
YourDiskDUID.k /home ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.d /tmp ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.f /usr ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.g /usr/X11R6 ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.h /usr/local ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.j /usr/obj ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.i /usr/src ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.e /var ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.a / ffs rw,noatime,softdep 1 1
YourDiskDUID.k /home ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.d /tmp ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.f /usr ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.g /usr/X11R6 ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.h /usr/local ffs rw,nodev,noatime,softdep 1 2
YourDiskDUID.j /usr/obj ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.i /usr/src ffs rw,nodev,nosuid,noatime,softdep 1 2
YourDiskDUID.e /var ffs rw,nodev,nosuid,noatime,softdep 1 2
Your server has booted with DHCP and has acquired its network configuration from your VPS provider. As the server IP address is fixed, I prefer setting manually the network configuration to avoid relying on another server (VPS provider's DHCP and DNS) I do not control. Modify the following files according to your server public ip address, mask, and gateway:
$ sudo vi /etc/hostname.vio0
inet server_public_ip server_netmask
Add the gateway :
$ sudo vi /etc/mygate
server_gateway_ip
Our server will forward traffic between its VPN interface and its default network interface. We have to enable forwarding:
$ sudo sysctl net.inet.ip.forwarding=1
$ sudo vi /etc/sysctl.conf
$ sudo vi /etc/sysctl.conf
net.inet.ip.forwarding=1
At this point your still rely on your provider DNS server in /etc/resolv.conf, we will take care of that in the next step.
3. DNS
___________________________________________________
___________________________________________________
We will use DNSCrypt to make our DNS requests encrypted, and Unbound to have a local DNS cache. This will allow us to avoid using our VPS provider DNS servers, and will also
be useful to your future VPN clients which will be able to use your VPN server as their DNS server too, if they wish too (e.g mobile phones). Both dnscrypt and unbound will
listen on the localhost only, not to the outside. They will be reachable nonetheless later to your VPN clients trough the VPN tunnel, using a firewall redirection.
You can choose your dnscrypt enabled DNS server at the following list (choose a logless DNSSEC enabled one).
We now configure and enable unbound, already included in the base system. Unbound will drop privileges and will be chrooted in /var/unbound:
Do not forget to modify your /etc/resolv.conf:
Run Unbound, and enable it to launch at startup :
Test that your DNS chain is working:
Unbound is listening on locahost port 53, and when contacted is forwarding to dnscrypt listening on locahost port 40, itself contacting an external dnscrypt enabled DNS server.
$ export PKG_PATH=http://ftp.fr.openbsd.org/pub/OpenBSD/5.6/packages/amd64/
$ sudo pkg_add dnscrypt-proxy
$ sudo vi /etc/rc.local
$ sudo pkg_add dnscrypt-proxy
$ sudo vi /etc/rc.local
# DNSCrypt
/usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -l /dev/null -R dnscrypt.eu-dk
/usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -l /dev/null -R dnscrypt.eu-dk
You can choose your dnscrypt enabled DNS server at the following list (choose a logless DNSSEC enabled one).
$ sudo /usr/local/sbin/dnscrypt-proxy -a 127.0.0.1:40 -u _dnscrypt-proxy -d -l /dev/null -R dnscrypt.eu-dk
We now configure and enable unbound, already included in the base system. Unbound will drop privileges and will be chrooted in /var/unbound:
$ sudo vi /var/unbound/etc/unbound.conf
server:
username: _unbound
directory: /var/unbound
chroot: /var/unbound
do-not-query-localhost: no
interface: 127.0.0.1
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.8.0.0/24 allow
hide-identity: yes
hide-version: yes
auto-trust-anchor-file: "/var/unbound/db/root.key"
forward-zone:
name: "." # use for ALL queries
forward-addr: 127.0.0.1@40 # dnscrypt-proxy
username: _unbound
directory: /var/unbound
chroot: /var/unbound
do-not-query-localhost: no
interface: 127.0.0.1
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.8.0.0/24 allow
hide-identity: yes
hide-version: yes
auto-trust-anchor-file: "/var/unbound/db/root.key"
forward-zone:
name: "." # use for ALL queries
forward-addr: 127.0.0.1@40 # dnscrypt-proxy
Do not forget to modify your /etc/resolv.conf:
$ sudo vi /etc/resolv.conf
nameserver 127.0.0.1 # unbound is listening there at port 53
Run Unbound, and enable it to launch at startup :
$ sudo /etc/rc.d/unbound start
$ sudo vi /etc/rc.conf.local
$ sudo vi /etc/rc.conf.local
# Unbound
unbound_flags="-c /var/unbound/etc/unbound.conf"
unbound_flags="-c /var/unbound/etc/unbound.conf"
Test that your DNS chain is working:
$ host openbsd.org
openbsd.org has address 129.128.5.194
openbsd.org mail is handled by 6 shear.ucar.edu.
openbsd.org mail is handled by 10 cvs.openbsd.org.
openbsd.org has address 129.128.5.194
openbsd.org mail is handled by 6 shear.ucar.edu.
openbsd.org mail is handled by 10 cvs.openbsd.org.
Unbound is listening on locahost port 53, and when contacted is forwarding to dnscrypt listening on locahost port 40, itself contacting an external dnscrypt enabled DNS server.
4. FIREWALL
___________________________________________________
___________________________________________________
The pf ruleset below does many things:
- denies all inbound, except SSH and OpenVPN on non default ports
- protects SSH from SYN flood, and bruteforce
- detects scans on common ports and blacklist the miscreants for 24H
- allows VPN clients to make DNS requests to unbound on localhost (which uses dnscrypt)
- does not log blocked network traffic from the provider's DHCP
You should modify this ruleset according to your chosen SSH and VPN listening ports (we will setup OpenVPN later, but you can choose a random port now). The scan detection and blacklisting concept can theoretically backfire, if someone sends spoofed packets with trusted IPs. However, as it is implemented, only incoming traffic will match the blacklist table. Therefore, if a spoofed packet is sent with a website IP you trust, it will not prevent you to access that website at all as your traffic will be outbound. Also, as we will write a script to parse pf logs and add IPs into the blacklist, we will add an exception for our own trusted client computer public IP address to avoid being locked out. As a last resort the remote console access from the VPS provider could allow us to login, if we were totally locked out for any reason. This adaptative behavior is not mandatory fo your VPN server to be operational, but it is useful to block automatic scans on the Internet to query your SSH and VPN ports once they hit previously ports in your watchlist. Additionally, while I show below an example with selected ports in the watchlist, you could test putting the whole ports range, excluding your two open ports (more aggressive).
Check the ruleset syntax, with the first command, and then apply it if no error returned:
Now we have to make our script which will look for IPs blocked because they matched our ports watchlist rule, labeled "new_guy". Script will be in /home/user/scripts:
Edit the crontab to schedule execution of this script, as well as check every hour to expire table entries older than 24 hours. Replace "/home/your_user" below with your username:
You can check with another script the state of your blacklist/badguys table, ports blocked to them once blacklisted (including ports not in the watchlist), and number of blocked IP in your bruteforce table. Here is the script example, you can freely modify:
Make the two scripts executable. Below is also an example of a possible output from the second script:
- "first" is the number of blocks matching the ports watchlist from IP not being blacklisted (since last ruleset reload)
- "retry" is the number of blocks matching the ports watchlist from IP already blacklisted (since last ruleset reload)
- "ports blocked" is the port list accessed by the blacklisted IPs.
- "bruteforce" is the total number of IP which made too many connections to our open SSH port.
You now have a nice adaptative firewall, however as warned above, be careful as it can backfire if trusted IPs are not excluded and become blacklisted. It is a working configuration I had no trouble with, in my context, but in your situation it may have to be modified to fit your case.
- denies all inbound, except SSH and OpenVPN on non default ports
- protects SSH from SYN flood, and bruteforce
- detects scans on common ports and blacklist the miscreants for 24H
- allows VPN clients to make DNS requests to unbound on localhost (which uses dnscrypt)
- does not log blocked network traffic from the provider's DHCP
You should modify this ruleset according to your chosen SSH and VPN listening ports (we will setup OpenVPN later, but you can choose a random port now). The scan detection and blacklisting concept can theoretically backfire, if someone sends spoofed packets with trusted IPs. However, as it is implemented, only incoming traffic will match the blacklist table. Therefore, if a spoofed packet is sent with a website IP you trust, it will not prevent you to access that website at all as your traffic will be outbound. Also, as we will write a script to parse pf logs and add IPs into the blacklist, we will add an exception for our own trusted client computer public IP address to avoid being locked out. As a last resort the remote console access from the VPS provider could allow us to login, if we were totally locked out for any reason. This adaptative behavior is not mandatory fo your VPN server to be operational, but it is useful to block automatic scans on the Internet to query your SSH and VPN ports once they hit previously ports in your watchlist. Additionally, while I show below an example with selected ports in the watchlist, you could test putting the whole ports range, excluding your two open ports (more aggressive).
$ sudo vi /etc/pf.conf
# "Being your own VPN provider with OpenBSD"
# Guillaume Kaddouch: http://networkfilter.blogspot.com/
# ruleset last modified: 2015 January 11
# VARIABLES, MACRO, AND TABLES
# ---------------------------------------------------------------------------------------
egress="vio0" # your server network interface, modify accordingly
vpn="tun0"
vpn_ip="10.8.0.1"
all_networks="0.0.0.0/0"
private_networks="10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16"
ssh_port="21598" # just a random example, modify to match your chosen SSH port
vpn_port="21600" # just a random example, modify to match your chosen OpenVPN port
# ports watchlist example, modify as you wish.
# Match against this will be put in "badguys" table below, by an external scheduled script
bad_ports="{ ftp-data, ftp, ssh, telnet, smtp, domain, http, pop3, ntp, netbios-ns, \
netbios-dgm, netbios-ssn, https, microsoft-ds, ms-sql-s, ms-sql-m, \
mysql, postgresql }"
table <internet> const { $all_networks, !self, !$private_networks }
table <myself> const { self }
table <bruteforce> persist
table <badguys> persist
# GLOBAL POLICY
# ---------------------------------------------------------------------------------------
block log all
set block-policy drop
set loginterface egress
set skip on lo
match in all scrub (no-df max-mss 1440 random-id)
block in log quick from <bruteforce> label "bruteforce"
block in log quick from <badguys> label "old_guys"
# DEFAULT TRAFFIC TAGGING
# --------------------------------------------------------------------------------
# POLICY ENFORCEMENT
# ---------------------------------------------------------------------------------------
match in tagged VPN_EGRESS_IN set tos lowdelay set prio 6
match out tagged VPN_FORWARD nat-to (egress) set prio 6
# Blocking spoofed or malformed packets, IPv6, and some bad traffic
antispoof log quick for egress label "antispoof"
block quick log tagged BAD_PACKET label "noroute_urpf"
block quick log tagged IPV6 label "ipv6"
block quick log tagged BAD_GUYS label "new_guy"
# Standard rules
# protect SSH from SYN flood and bruteforce
pass in quick tagged SSH_IN synproxy state \
(max-src-conn 10, max-src-conn-rate 5/5, overload <bruteforce> flush global)
# Redirect VPN clients DNS requests to unbound
pass in quick inet tagged VPN_DNS_IN rdr-to 127.0.0.1 port domain
pass in quick tagged VPN_EGRESS_IN
pass in quick tagged VPN_TUN_IN
pass out quick tagged HTTP_OUT
pass out quick tagged DNS_OUT
pass out quick tagged VPN_FORWARD modulate state
pass out quick tagged NTP_OUT
# no log for
block in quick proto udp from 0.0.0.0 port bootpc to port bootps
block in quick proto udp from any port bootps to 255.255.255.255 port bootpc
# Guillaume Kaddouch: http://networkfilter.blogspot.com/
# ruleset last modified: 2015 January 11
# VARIABLES, MACRO, AND TABLES
# ---------------------------------------------------------------------------------------
egress="vio0" # your server network interface, modify accordingly
vpn="tun0"
vpn_ip="10.8.0.1"
all_networks="0.0.0.0/0"
private_networks="10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16"
ssh_port="21598" # just a random example, modify to match your chosen SSH port
vpn_port="21600" # just a random example, modify to match your chosen OpenVPN port
# ports watchlist example, modify as you wish.
# Match against this will be put in "badguys" table below, by an external scheduled script
bad_ports="{ ftp-data, ftp, ssh, telnet, smtp, domain, http, pop3, ntp, netbios-ns, \
netbios-dgm, netbios-ssn, https, microsoft-ds, ms-sql-s, ms-sql-m, \
mysql, postgresql }"
table <internet> const { $all_networks, !self, !$private_networks }
table <myself> const { self }
table <bruteforce> persist
table <badguys> persist
# GLOBAL POLICY
# ---------------------------------------------------------------------------------------
block log all
set block-policy drop
set loginterface egress
set skip on lo
match in all scrub (no-df max-mss 1440 random-id)
block in log quick from <bruteforce> label "bruteforce"
block in log quick from <badguys> label "old_guys"
# DEFAULT TRAFFIC TAGGING
# --------------------------------------------------------------------------------
match in on egress proto tcp from <internet> to port $ssh_port match in on egress proto { udp tcp } from <internet> to port $bad_ports match in on egress proto udp to port $vpn_port match in on $vpn proto { icmp udp tcp } match in on $vpn proto { udp tcp } to $vpn_ip port domain match out on egress tagged VPN_TUN_IN match out on egress proto tcp from <myself> to port { http https } match out on egress proto { udp tcp } from <myself> to port domain match out on egress proto udp from <myself> to port https match out on egress proto udp from <myself> to port ntp match in on egress from { no-route urpf-failed } to any match out on egress from any to no-route match inet6 all |
   tag SSH_IN    tag BAD_GUYS    tag VPN_EGRESS_IN    tag VPN_TUN_IN    tag VPN_DNS_IN    tag VPN_FORWARD    tag HTTP_OUT    tag DNS_OUT    tag DNS_OUT    tag NTP_OUT    tag BAD_PACKET    tag BAD_PACKET    tag IPV6 |
# POLICY ENFORCEMENT
# ---------------------------------------------------------------------------------------
match in tagged VPN_EGRESS_IN set tos lowdelay set prio 6
match out tagged VPN_FORWARD nat-to (egress) set prio 6
# Blocking spoofed or malformed packets, IPv6, and some bad traffic
antispoof log quick for egress label "antispoof"
block quick log tagged BAD_PACKET label "noroute_urpf"
block quick log tagged IPV6 label "ipv6"
block quick log tagged BAD_GUYS label "new_guy"
# Standard rules
# protect SSH from SYN flood and bruteforce
pass in quick tagged SSH_IN synproxy state \
(max-src-conn 10, max-src-conn-rate 5/5, overload <bruteforce> flush global)
# Redirect VPN clients DNS requests to unbound
pass in quick inet tagged VPN_DNS_IN rdr-to 127.0.0.1 port domain
pass in quick tagged VPN_EGRESS_IN
pass in quick tagged VPN_TUN_IN
pass out quick tagged HTTP_OUT
pass out quick tagged DNS_OUT
pass out quick tagged VPN_FORWARD modulate state
pass out quick tagged NTP_OUT
# no log for
block in quick proto udp from 0.0.0.0 port bootpc to port bootps
block in quick proto udp from any port bootps to 255.255.255.255 port bootpc
Check the ruleset syntax, with the first command, and then apply it if no error returned:
$ sudo pfctl -nf /etc/pf.conf
$ sudo pfctl -f /etc/pf.conf
$ sudo pfctl -f /etc/pf.conf
Now we have to make our script which will look for IPs blocked because they matched our ports watchlist rule, labeled "new_guy". Script will be in /home/user/scripts:
$ cd ~
$ mkdir scripts
$ cd scripts
$ sudo ./pf_badguys.sh
$ mkdir scripts
$ cd scripts
$ sudo ./pf_badguys.sh
#!/bin/sh
# Modify to match your server IP address and network interface
trusted="YOUR COMPUTER/CLIENT PUBLIC IP HERE"
ext_if="vio0"
label="new_guy"
file_temp="/home/your_user/badguys.txt"
file_clean="/home/your_user/badguys_clean.txt"
# Find rule number to look the logs for, we added a label in pf ruleset to locate it easily
# pf starts its numbering at rule 0 (tcpdump logs), while grep starts at rule 1
grep_number=`pfctl -sr | grep -n $label | cut -d":" -f1`
rule_number=$(($grep_number - 1))
echo "" > $file_temp
echo "" > $file_clean
# Look in all blocked traffic the IP blocked because of matching our ports watchlist (rule_number above)
tcpdump -enr /var/log/pflog | grep "rule $rule_number/(match) block in on $ext_if" | cut -d':' -f4 | cut -d' ' -f2 | \
awk '{split($0,ip,"."); print ip[1]"."ip[2]"."ip[3]"."ip[4]}' | sort | uniq >> $file_temp
# Remove our own trusted client IP we connect from!
sed -e "s/$trusted//g" $file_temp > $file_clean
cat $file_clean
# Add the new IP addresses in the badguys table
# pfctl handles by itself duplicate IPs and does not add an already existing one
pfctl -t badguys -T add -f $file_clean
# Modify to match your server IP address and network interface
trusted="YOUR COMPUTER/CLIENT PUBLIC IP HERE"
ext_if="vio0"
label="new_guy"
file_temp="/home/your_user/badguys.txt"
file_clean="/home/your_user/badguys_clean.txt"
# Find rule number to look the logs for, we added a label in pf ruleset to locate it easily
# pf starts its numbering at rule 0 (tcpdump logs), while grep starts at rule 1
grep_number=`pfctl -sr | grep -n $label | cut -d":" -f1`
rule_number=$(($grep_number - 1))
echo "" > $file_temp
echo "" > $file_clean
# Look in all blocked traffic the IP blocked because of matching our ports watchlist (rule_number above)
tcpdump -enr /var/log/pflog | grep "rule $rule_number/(match) block in on $ext_if" | cut -d':' -f4 | cut -d' ' -f2 | \
awk '{split($0,ip,"."); print ip[1]"."ip[2]"."ip[3]"."ip[4]}' | sort | uniq >> $file_temp
# Remove our own trusted client IP we connect from!
sed -e "s/$trusted//g" $file_temp > $file_clean
cat $file_clean
# Add the new IP addresses in the badguys table
# pfctl handles by itself duplicate IPs and does not add an already existing one
pfctl -t badguys -T add -f $file_clean
Edit the crontab to schedule execution of this script, as well as check every hour to expire table entries older than 24 hours. Replace "/home/your_user" below with your username:
$ sudo crontab -e
# add badguys to the pf table to be blocked
*/5 * * * * /home/your_user/scripts/pf_badguys.sh
# Clear pf tables
0 * * * * pfctl -t bruteforce -T expire 86400
0 * * * * pfctl -t badguys -T expire 86400
*/5 * * * * /home/your_user/scripts/pf_badguys.sh
# Clear pf tables
0 * * * * pfctl -t bruteforce -T expire 86400
0 * * * * pfctl -t badguys -T expire 86400
You can check with another script the state of your blacklist/badguys table, ports blocked to them once blacklisted (including ports not in the watchlist), and number of blocked IP in your bruteforce table. Here is the script example, you can freely modify:
$ sudo vi ./pf_show_tables.sh
#!/bin/sh
ext_if="vio0"
label_new="new_guy"
label_old="old_guy"
BAD_TOTAL=`pfctl -t badguys -T show | wc -l | sed -e 's/^ *//' -e 's/ *$//'`
BRUTE_TOTAL=`pfctl -t bruteforce -T show | wc -l | sed -e 's/^ *//' -e 's/ *$//'`
BAD_NEW=`pfctl -sl | grep $label_new | cut -d' ' -f3`
BAD_OLD=`pfctl -sl | grep $label_old | cut -d' ' -f3`
grep_number=`pfctl -sr | grep -n $label_new | cut -d":" -f1`
rule_number=$(($grep_number - 1))
PORTS_SCAN=`tcpdump -enr /var/log/pflog | grep "rule $rule_number/(match) block in on $ext_if" | \
cut -d':' -f4 | cut -d' ' -f4 | awk '{split($0,ip,"."); print ip[5]}'| sort | uniq`
echo ""
echo -e "Table <badguys> total/first/retry : $BAD_TOTAL/$BAD_NEW/$BAD_OLD"
echo "ports blocked :"
echo "$PORTS_SCAN"
echo ""
echo -e "Table <bruteforce> : $BRUTE_TOTAL"
ext_if="vio0"
label_new="new_guy"
label_old="old_guy"
BAD_TOTAL=`pfctl -t badguys -T show | wc -l | sed -e 's/^ *//' -e 's/ *$//'`
BRUTE_TOTAL=`pfctl -t bruteforce -T show | wc -l | sed -e 's/^ *//' -e 's/ *$//'`
BAD_NEW=`pfctl -sl | grep $label_new | cut -d' ' -f3`
BAD_OLD=`pfctl -sl | grep $label_old | cut -d' ' -f3`
grep_number=`pfctl -sr | grep -n $label_new | cut -d":" -f1`
rule_number=$(($grep_number - 1))
PORTS_SCAN=`tcpdump -enr /var/log/pflog | grep "rule $rule_number/(match) block in on $ext_if" | \
cut -d':' -f4 | cut -d' ' -f4 | awk '{split($0,ip,"."); print ip[5]}'| sort | uniq`
echo ""
echo -e "Table <badguys> total/first/retry : $BAD_TOTAL/$BAD_NEW/$BAD_OLD"
echo "ports blocked :"
echo "$PORTS_SCAN"
echo ""
echo -e "Table <bruteforce> : $BRUTE_TOTAL"
Make the two scripts executable. Below is also an example of a possible output from the second script:
$ chmod +x ./*.sh
$ sudo pf_show_tables.sh
Table <badguys> total/first/retry : 486/71/82
ports blocked :
123
137
1433
21
22
23
25
3306
445
80
Table <bruteforce> : 0
- "total" is the number of IP addresses blacklisted. $ sudo pf_show_tables.sh
Table <badguys> total/first/retry : 486/71/82
ports blocked :
123
137
1433
21
22
23
25
3306
445
80
Table <bruteforce> : 0
- "first" is the number of blocks matching the ports watchlist from IP not being blacklisted (since last ruleset reload)
- "retry" is the number of blocks matching the ports watchlist from IP already blacklisted (since last ruleset reload)
- "ports blocked" is the port list accessed by the blacklisted IPs.
- "bruteforce" is the total number of IP which made too many connections to our open SSH port.
You now have a nice adaptative firewall, however as warned above, be careful as it can backfire if trusted IPs are not excluded and become blacklisted. It is a working configuration I had no trouble with, in my context, but in your situation it may have to be modified to fit your case.
5. VPN SERVER
___________________________________________________
___________________________________________________
5.1 - SERVER
We are going to setup our OpenVPN server, with the help of the easy-rsa package to make it easier to build our Certificate Authority (CA) and other keys and certificates. The requirements for our server is to use secure keys and protocols only:
- CA, server and clients keys, in 4096 bits RSA
- Key exchange with 4096 bits Diffie-Hellman
- HMAC SHA1 packet authentication, with a TLS 2048 bits static key
- AES 256 bits tunnel encryption
- Perfect Forward Secrecy (PFS)
Let's download our packages and create needed directories:
$ sudo pkg_add openvpn easy-rsa
$ sudo mkdir -p /usr/local/etc/openvpn/{public,secret,clients/{public,secret},easy-rsa/keys}
$ sudo mkdir /usr/local/share/easy-rsa/keys
$ sudo mkdir -p /var/openvpn/tmp
$ cd /usr/local/share/easy-rsa/
$ chmod +x ./*
$ sudo mkdir -p /usr/local/etc/openvpn/{public,secret,clients/{public,secret},easy-rsa/keys}
$ sudo mkdir /usr/local/share/easy-rsa/keys
$ sudo mkdir -p /var/openvpn/tmp
$ cd /usr/local/share/easy-rsa/
$ chmod +x ./*
You have to manually edit /usr/local/share/easy-rsa/vars file to modify KEY_SIZE=1024 into KEY_SIZE=2048, and edit /usr/local/share/easy-rsa/build-dh to modify 2048 into 4096. Now let's create our CA and keys. Log in as root temporarily to execute these commands (notice the double dot for the ". ./vars" command):
$ su -
# cd /usr/local/share/easy-rsa/
# cp openssl-1.0.0.cnf ./openssl.cnf
# . ./vars
# ./clean-all
# ./build-ca --keysize 4096
# ./build-key-server --keysize 4096 server
# ./build-key --keysize 4096 myhome
# ./build-key --keysize 4096 myphone
# ./build-dh
# openvpn --genkey --secret ta.key
# cd /usr/local/share/easy-rsa/
# cp openssl-1.0.0.cnf ./openssl.cnf
# . ./vars
# ./clean-all
# ./build-ca --keysize 4096
# ./build-key-server --keysize 4096 server
# ./build-key --keysize 4096 myhome
# ./build-key --keysize 4096 myphone
# ./build-dh
# openvpn --genkey --secret ta.key
We have built certificates and keys for our CA, server, two clients, Diffie-Hellman parameters, and finally the 2048 bits TLS static key that will be used for HMAC packet authentication. We can now move the files in /usr/local/etc/openvpn, in different folders according to the public or private status of the files generated:
# cp ./* /usr/local/etc/openvpn/easy-rsa
# ./clean-all
# cd /usr/local/etc/openvpn/easy-rsa/keys
# cp ca.crt /usr/local/etc/openvpn/public
# mv ca.crt /usr/local/etc/openvpn/clients/public
# mv ca.key /usr/local/etc/openvpn/secret
# mv dh4096.pem /usr/local/etc/openvpn/public
# mv server.key /usr/local/etc/openvpn/secret
# mv server.crt /usr/local/etc/openvpn/public
# mv myhome.key /usr/local/etc/openvpn/clients/secret
# mv myhome.c* /usr/local/etc/openvpn/clients/public
# mv myphone.key /usr/local/etc/openvpn/clients/secret
# mv myphone.c* /usr/local/etc/openvpn/clients/public
# cp ta.key /usr/local/etc/openvpn/secret
# mv ta.key /usr/local/etc/openvpn/clients/secret
# ./clean-all
# cd /usr/local/etc/openvpn/easy-rsa/keys
# cp ca.crt /usr/local/etc/openvpn/public
# mv ca.crt /usr/local/etc/openvpn/clients/public
# mv ca.key /usr/local/etc/openvpn/secret
# mv dh4096.pem /usr/local/etc/openvpn/public
# mv server.key /usr/local/etc/openvpn/secret
# mv server.crt /usr/local/etc/openvpn/public
# mv myhome.key /usr/local/etc/openvpn/clients/secret
# mv myhome.c* /usr/local/etc/openvpn/clients/public
# mv myphone.key /usr/local/etc/openvpn/clients/secret
# mv myphone.c* /usr/local/etc/openvpn/clients/public
# cp ta.key /usr/local/etc/openvpn/secret
# mv ta.key /usr/local/etc/openvpn/clients/secret
Files are sorted like this:
- servers public files are in /openvpn/public (ca.crt, dh4096.pem, server.crt)
- servers secret files are in /openvpn/secret (ca.key, server.key, ta.key)
- clients public files are in /openvpn/clients/public (myhome.csr, myhome.crt, myphone.csr, myphone.crt, ca.crt)
- clients secret files are in /openvpn/clients/secret (myhome.key, myphone.key, ta.key)
Let's not forget the main OpenVPN server configuration file in the process. We can logout from root account:
# logout
$ sudo vi /usr/local/etc/openvpn/server.conf
$ sudo vi /usr/local/etc/openvpn/server.conf
# Server configuration
# SSL/TLS certificate and keys, PFS enabled by default
ca "/usr/local/etc/openvpn/public/ca.crt"
cert "/usr/local/etc/openvpn/public/server.crt"
dh "/usr/local/etc/openvpn/public/dh4096.pem" # Diffie Helman 4096 bits
key "/usr/local/etc/openvpn/secret/server.key" # RSA 4096 bits
tls-auth "/usr/local/etc/openvpn/secret/ta.key" 0 # TLS 2048 bits for HMAC
cipher AES-256-CBC # AES 256 bits
# Network parameters
port 21600 # as an example, pick your own port
proto udp
dev tun
tls-server
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
# push our DNS server to clients accepting it (will not override a home router DNS configuration
# with fixed DNS settings). Usefull for mobile phones for instance, where installing
# dnscrypt requires a rooted phone
push "dhcp-option DNS 10.8.0.1"
keepalive 10 120
comp-lzo no
# Limits
max-clients 5 # change this value if you plan on connecting from more clients
# Privileges, chroot
chroot /var/openvpn
user _openvpn
group _openvpn
persist-key
persist-tun
# LOG
verb 4
mute 20
# SSL/TLS certificate and keys, PFS enabled by default
ca "/usr/local/etc/openvpn/public/ca.crt"
cert "/usr/local/etc/openvpn/public/server.crt"
dh "/usr/local/etc/openvpn/public/dh4096.pem" # Diffie Helman 4096 bits
key "/usr/local/etc/openvpn/secret/server.key" # RSA 4096 bits
tls-auth "/usr/local/etc/openvpn/secret/ta.key" 0 # TLS 2048 bits for HMAC
cipher AES-256-CBC # AES 256 bits
# Network parameters
port 21600 # as an example, pick your own port
proto udp
dev tun
tls-server
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
# push our DNS server to clients accepting it (will not override a home router DNS configuration
# with fixed DNS settings). Usefull for mobile phones for instance, where installing
# dnscrypt requires a rooted phone
push "dhcp-option DNS 10.8.0.1"
keepalive 10 120
comp-lzo no
# Limits
max-clients 5 # change this value if you plan on connecting from more clients
# Privileges, chroot
chroot /var/openvpn
user _openvpn
group _openvpn
persist-key
persist-tun
# LOG
verb 4
mute 20
It is time to start our server and to make it start at boot time:
$ sudo chmod -Rf 640 /usr/local/etc/openvpn
$ sudo /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
$ sudo vi /etc/rc.local
$ sudo /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
$ sudo vi /etc/rc.local
# OpenVPN
/usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
/usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
You shoud check with tail -f /var/log/messages that OpenVPN started successfully. If something went wrong, check your files and folders ownership and rights.
5.2 - CLIENT
In my OpenBSD router article there is a chapter about an OpenVPN client installation and configuration. Below I will just provide the OpenVPN configuration file to use on the client side:
$ sudo vi /usr/local/etc/openvpn/client.conf
# Client configuration (router, computer)
# SSL/TLS certificate and keys
ca "/usr/local/etc/openvpn/ca.crt" # public
cert "/usr/local/etc/openvpn/myhome.crt" # public
key "/usr/local/etc/openvpn/myhome.key" # secret
tls-auth "/usr/local/etc/openvpn/ta.key" 1 # secret
cipher AES-256-CBC
remote-cert-tls server
client
dev tun
proto udp
resolv-retry infinite
nobind
comp-lzo no
# VPS OpenBSD
remote YOUR_SERVER_IP 21600
# Privileges, chroot
user _openvpn
group _openvpn
chroot /var/empty
persist-key
persist-tun
# LOG
verb 3
explicit-exit-notify 5
# SSL/TLS certificate and keys
ca "/usr/local/etc/openvpn/ca.crt" # public
cert "/usr/local/etc/openvpn/myhome.crt" # public
key "/usr/local/etc/openvpn/myhome.key" # secret
tls-auth "/usr/local/etc/openvpn/ta.key" 1 # secret
cipher AES-256-CBC
remote-cert-tls server
client
dev tun
proto udp
resolv-retry infinite
nobind
comp-lzo no
# VPS OpenBSD
remote YOUR_SERVER_IP 21600
# Privileges, chroot
user _openvpn
group _openvpn
chroot /var/empty
persist-key
persist-tun
# LOG
verb 3
explicit-exit-notify 5
Client keys must be copied from the server to the client over a secure channel, for instance by using SCP to transfer them trough SSH. As an example, if you copied the client files on the server in /home/user/vpn, from a Linux/BSD client you can run a command such as:
$ scp -P your_ssh_port -i id_ed25519 your_remote_user@your_server_ip:/home/user/vpn/*.* ./
5.3 - MOBILE CLIENT
A smartphone such as Android can download and install "OpenVPN for Android", which is also working with CyanogenMod by the way. Then you will have to transfer on the phone an OpenVPN configuration file, which will require to have the whole configuration in it, including certificates and keys. The configuration file has the certificates and keys inside it. Basically you just copy/paste the content of the required files and insert them between tags like below. Be aware to not miss the "key-direction 1" line before the "tls-auth" block at the end:
remote-cert-tls server
cipher AES-256-CBC
client
dev tun
proto udp
resolv-retry infinite
nobind
remote YOUR_SERVER_IP 21600
comp-lzo no
verb 3
explicit-exit-notify 5
persist-key
persist-tun
# ca.crt below, just a random example. Full extract is above 35 lines
<ca>
-----BEGIN CERTIFICATE-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSLDJLQSJDQSd45454QMDMSQMDMklajzEd4
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdSDL
-----END CERTIFICATE-----
</ca>
# myphone.crt below, just a random example. Full extract is above 35 lines
<cert>
-----BEGIN CERTIFICATE-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSLDJLQSJDQSd45454QMDMSQMDMklajzEd4
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdSDL
-----END CERTIFICATE-----
</cert>
# myphone.key below, just a random example. Full extract is above 35 lines
<key>
-----BEGIN CERTIFICATE-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSLDJLQSJDQSd45454QMDMSQMDMklajzEd4
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdSDL
-----END CERTIFICATE-----
</key>
key-direction 1
# ta.key below, just a random example. Full extract is above 20 lines
<tls-auth>
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSL
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdS
-----END OpenVPN Static key V1-----
</tls-auth>
cipher AES-256-CBC
client
dev tun
proto udp
resolv-retry infinite
nobind
remote YOUR_SERVER_IP 21600
comp-lzo no
verb 3
explicit-exit-notify 5
persist-key
persist-tun
# ca.crt below, just a random example. Full extract is above 35 lines
<ca>
-----BEGIN CERTIFICATE-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSLDJLQSJDQSd45454QMDMSQMDMklajzEd4
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdSDL
-----END CERTIFICATE-----
</ca>
# myphone.crt below, just a random example. Full extract is above 35 lines
<cert>
-----BEGIN CERTIFICATE-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSLDJLQSJDQSd45454QMDMSQMDMklajzEd4
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdSDL
-----END CERTIFICATE-----
</cert>
# myphone.key below, just a random example. Full extract is above 35 lines
<key>
-----BEGIN CERTIFICATE-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSLDJLQSJDQSd45454QMDMSQMDMklajzEd4
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdSDL
-----END CERTIFICATE-----
</key>
key-direction 1
# ta.key below, just a random example. Full extract is above 20 lines
<tls-auth>
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
ffidLLDKSJskfjf56s/smdjdhQSDOQSL
.
.
.
.
sqd54dLLDKSJskfjf56ssmdjdsqdqsdS
-----END OpenVPN Static key V1-----
</tls-auth>
This configuration file, you can name "myserver.ovpn" for instance, must be transfered into the phone via a secure channel. As I'm using SpiderOak I used the Hive folder (which is a synchronized folder among many clients/devices) to retrieve the file. However, once you copied with SCP the phone keys and certificate on your computer, I guess a classical USB transfer will do the job as well :-)
5.4 - SYSTRACE
I already talked about systrace on my previous OpenBSD router article, in the following chapter, as well as on another article comparing the security of OpenBSD and FreeBSD, where systrace is mentioned in the system hardening part. While OpenVPN is ran chrooted and with no privileges, we can additionally enforce a systrace policy on it which will allow only system calls we defined. As a quick reminder, you can run a systrace learning mode with $ sudo systrace -A /bin/foo which will store the application profile in /home/your_user/.systrace/bin_foo file. Once you edited the profile and moved it to /etc/systrace, you can run the program in enforce mode with $ sudo systrace -a -U /bin/foo (-U argument will use the file located in /etc/systrace). Below is a working systrace policy on my VPN server, but you should review it and test it in learning mode first on yours (modify the 21600 port for instance at the line "sockaddr match "inet-*:21600""):
$ sudo vi /etc/systrace/usr_local_sbin_openvpn
Policy: /usr/local/sbin/openvpn, Emulation: native
# Global
native-issetugid: permit
native-getentropy: permit
native-fstat: permit
native-close: permit
native-read: permit
native-sigprocmask: permit
native-__sysctl: permit
native-gettimeofday: permit
native-minherit: permit
native-mquery: permit
native-sigaction: permit
native-clock_gettime: permit
native-getpid: permit
native-sendsyslog: permit
native-write: permit
native-ioctl: permit
native-fork: permit
native-wait4: permit
native-pread: permit
native-exit: permit
native-setsid: permit
native-dup2: permit
native-sigreturn: permit
native-writev: permit
native-poll: permit
native-readv: permit
native-lseek: permit
native-ftruncate: permit
# Memory
native-munmap: permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mmap: prot eq "PROT_READ" then permit
native-mmap: prot eq "PROT_NONE" then permit
native-mmap: prot eq "PROT_READ|PROT_EXEC" then permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-mprotect: prot eq "PROT_NONE" then permit
native-mprotect: prot eq "PROT_READ" then permit
# File read
native-fsread: filename eq "/usr/local/etc/openvpn/server.conf" then permit
native-fsread: filename eq "/etc/resolv.conf" then permit
native-fsread: filename match "/usr/local/etc/openvpn/public/*" then permit
native-fsread: filename match "/usr/local/etc/openvpn/secret/*" then permit
native-fsread: filename eq "/var/openvpn" then permit
native-fsread: filename eq "/tmp" then permit
native-fsread: filename match "/usr/share/zoneinfo/*" then permit
native-fsread: filename match "/usr/lib/libcrypto.so.*" then permit
native-fsread: filename match "/usr/lib/libc.so.*" then permit
native-fsread: filename match "/usr/lib/libssl.so.*" then permit
native-fsread: filename eq "/var/run/ld.so.hints" then permit
native-fsread: filename match "/usr/local/lib/liblzo2.so.*" then permit
native-fsread: filename eq "/etc/malloc.conf" then permit
native-fsread: filename eq "/usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/etc/group" then permit
native-fsread: filename eq "/etc/spwd.db" then permit
native-fsread: filename eq "/<non-existent filename>: /etc/resolv.conf" then permit
native-fsread: filename match "/<non-existent filename>: /usr/share/zoneinfo/*" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C./libc.cat" then permit
native-fsread: filename eq "/var/openvpn/tmp" then permit
# File write
native-fswrite: filename eq "/dev/null" then permit
native-fswrite: filename eq "/dev/tun0" then permit
# Network
native-socket: sockdom eq "AF_INET" and socktype eq "SOCK_DGRAM" then permit
native-socket: sockdom eq "AF_UNKNOWN(17)" and socktype eq "SOCK_RAW" then permit
native-bind: sockaddr match "inet-*:21600" then permit
native-sendto: sockaddr match "inet-*:*" then permit
native-getsockopt: permit
native-setsockopt: permit
native-recvfrom: permit
# Chroot
native-chdir: filename eq "/" then permit
native-chroot: filename eq "/var/openvpn" then permit
native-setgid: gid eq "577" then permit
native-setgroups: permit
native-setuid: uid eq "577" and uname eq "_openvpn" then permit
# Exec
native-execve: filename eq "/sbin/ifconfig" and argv match "/sbin/ifconfig tun0 * mtu 1500 netmask 255.255.255.255 up -link0" then permit
native-execve: filename eq "/<non-existent filename>: /sbin/route" and argv match "/sbin/route delete -net * -netmask *" then permit
native-execve: filename eq "/var/openvpn/auth.sh" and argv eq "/var/openvpn/auth.sh " then permit
native-execve: filename eq "/sbin/route" and argv match "/sbin/route add -net * -netmask *" then permit
# Process
native-fcntl: cmd eq "F_SETFD" then permit
native-fcntl: cmd eq "F_SETFL" then permit
# Global
native-issetugid: permit
native-getentropy: permit
native-fstat: permit
native-close: permit
native-read: permit
native-sigprocmask: permit
native-__sysctl: permit
native-gettimeofday: permit
native-minherit: permit
native-mquery: permit
native-sigaction: permit
native-clock_gettime: permit
native-getpid: permit
native-sendsyslog: permit
native-write: permit
native-ioctl: permit
native-fork: permit
native-wait4: permit
native-pread: permit
native-exit: permit
native-setsid: permit
native-dup2: permit
native-sigreturn: permit
native-writev: permit
native-poll: permit
native-readv: permit
native-lseek: permit
native-ftruncate: permit
# Memory
native-munmap: permit
native-mmap: prot eq "PROT_READ|PROT_WRITE" then permit
native-mmap: prot eq "PROT_READ" then permit
native-mmap: prot eq "PROT_NONE" then permit
native-mmap: prot eq "PROT_READ|PROT_EXEC" then permit
native-mprotect: prot eq "PROT_READ|PROT_WRITE" then permit
native-mprotect: prot eq "PROT_NONE" then permit
native-mprotect: prot eq "PROT_READ" then permit
# File read
native-fsread: filename eq "/usr/local/etc/openvpn/server.conf" then permit
native-fsread: filename eq "/etc/resolv.conf" then permit
native-fsread: filename match "/usr/local/etc/openvpn/public/*" then permit
native-fsread: filename match "/usr/local/etc/openvpn/secret/*" then permit
native-fsread: filename eq "/var/openvpn" then permit
native-fsread: filename eq "/tmp" then permit
native-fsread: filename match "/usr/share/zoneinfo/*" then permit
native-fsread: filename match "/usr/lib/libcrypto.so.*" then permit
native-fsread: filename match "/usr/lib/libc.so.*" then permit
native-fsread: filename match "/usr/lib/libssl.so.*" then permit
native-fsread: filename eq "/var/run/ld.so.hints" then permit
native-fsread: filename match "/usr/local/lib/liblzo2.so.*" then permit
native-fsread: filename eq "/etc/malloc.conf" then permit
native-fsread: filename eq "/usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/etc/group" then permit
native-fsread: filename eq "/etc/spwd.db" then permit
native-fsread: filename eq "/<non-existent filename>: /etc/resolv.conf" then permit
native-fsread: filename match "/<non-existent filename>: /usr/share/zoneinfo/*" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C/libc.cat" then permit
native-fsread: filename eq "/<non-existent filename>: /usr/share/nls/C./libc.cat" then permit
native-fsread: filename eq "/var/openvpn/tmp" then permit
# File write
native-fswrite: filename eq "/dev/null" then permit
native-fswrite: filename eq "/dev/tun0" then permit
# Network
native-socket: sockdom eq "AF_INET" and socktype eq "SOCK_DGRAM" then permit
native-socket: sockdom eq "AF_UNKNOWN(17)" and socktype eq "SOCK_RAW" then permit
native-bind: sockaddr match "inet-*:21600" then permit
native-sendto: sockaddr match "inet-*:*" then permit
native-getsockopt: permit
native-setsockopt: permit
native-recvfrom: permit
# Chroot
native-chdir: filename eq "/" then permit
native-chroot: filename eq "/var/openvpn" then permit
native-setgid: gid eq "577" then permit
native-setgroups: permit
native-setuid: uid eq "577" and uname eq "_openvpn" then permit
# Exec
native-execve: filename eq "/sbin/ifconfig" and argv match "/sbin/ifconfig tun0 * mtu 1500 netmask 255.255.255.255 up -link0" then permit
native-execve: filename eq "/<non-existent filename>: /sbin/route" and argv match "/sbin/route delete -net * -netmask *" then permit
native-execve: filename eq "/var/openvpn/auth.sh" and argv eq "/var/openvpn/auth.sh " then permit
native-execve: filename eq "/sbin/route" and argv match "/sbin/route add -net * -netmask *" then permit
# Process
native-fcntl: cmd eq "F_SETFD" then permit
native-fcntl: cmd eq "F_SETFL" then permit
To test the profile in learning mode, kill the running process, and start it with the systrace policy (-A = learning):
$ sudo pkill openvpn
$ sudo systrace -A -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
$ tail -f /var/log/messages
$ sudo systrace -A -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
$ tail -f /var/log/messages
If everything is working as expected, check your policy file. If nothing new, you can kill openvpn and restart it in enforce mode:
$ sudo pkill openvpn
$ sudo systrace -a -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
$ tail -f /var/log/messages
$ sudo systrace -a -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
$ tail -f /var/log/messages
If you want to run it under a systrace policy from the startup, you have to modify the /etc/rc.local file like this:
$ sudo vi /etc/rc.local
# OpenVPN
systrace -a -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
systrace -a -U /usr/local/sbin/openvpn --config /usr/local/etc/openvpn/server.conf --daemon
Your VPN server is now finished!
6. SECURITY & ANONYMITY
___________________________________________________
___________________________________________________
VPN are usually seen as a holy grail for security, privacy, and anonymity. However, as I mentioned it in the OpenBSD VPN gateway article, in the
Beyond VPN part, VPN does not solve every problem.
With VPN, you will prevent your traffic from being intercepted and watched either in a public WIFI or by your ISP, or by any country practising global surveillance. It is thus possible to reach security and privacy. One caveat mentioned in the aformentioned article, is that traffic leaving your VPN server is not encrypted and requires end-to-end encryption to protect your privacy (HTTPS, SSH, SMTPS, DNSCrypt, etc...). Security is not automatic while using a VPN however, if we read this spiegel.de article. We learn that the NSA is able to break some VPN such as PPTP or even IPSEC, but that's the how which is interesting, instead of declaring VPN "broken" alltogether. First method is for NSA to participate in encryption standard elaboration to weaken these standards (IETF). If we bought products using less secure encryption, it will be easier for them to decrypt. Then for IPSEC connections for instance, which is more robust, they do not break the protocol itself and hence any IPSEC connection, but are rather using their TAO team to hack routers to steal the keys. NSA targeted for instance a VPN provider named SecurityKiss in Ireland. Security of both VPN protocol and both endpoints (client and server) is of first importance to have a secure connection. If we use the best in class "uncrackable" encryption, but that the server or clients are not secured enough, secret keys can be stolen and VPN decrypted.
Privacy, even if we use strong VPN encryption with very secure server and clients, is a fragile thing. Indeed, at the other end of the tunnel, on the websites and forums you visit, what you type there is of critical importance to your privacy. Obviously, posting your whole life on Facebook quite nullifies the privacy acquired by the use of VPN. Also, even if you use a secure and privacy minded mailbox such as ProtonMail, if you still communicate with Gmail clients your emails will still be read. Additionaly, if in the confort of your VPN you confess to Google Search engine all of your questions, fears, or interests, your privacy will have a very short life (I advise using Duckduckgo search engine instead).
What about anonymity? If we have a good security and privacy, are we automatically anonymous? Having privacy is not the same as being anonymous. If you know my real name because I choose to, but I do not disclose to you my favourite movie, or what books I like to read, I have privacy (I choose what I want to say to who I want). If however you don't even know who I am, I have anonymity. Anonymity is really tricky to achieve. Even if you use a VPN, your browser is likely to betray you with tracking cookies. If you go to a particular website with a VPN server located in a foreign country, the website will see your connection coming from this country, but if it uses tracking cookies it will recognize you anyway. Browser fingerprints are pretty unique too and can be used to identify you no matter which VPN you use and even if you disable all cookies. You can test you browser fingerprint uniqueness at https://panopticlick.eff.org/. My browser fingerprint is unique among nearly 5 millions tests done on this site! The fact I did the test with a VPN and am using Ghostery browser plugin does not change anything. By using the TOR browser with default settings, still trough my VPN, my fingerprint was matching 8655 other browsers fingerprints, I was no longer uniquely identifiable.
Achieving security, privacy, and anonymity, requires proper end-to-end encryption and security (server and client). It also requires the use of multiple tools and encrypted channels (VPN, Tor, HTTPS, 2FA with Yubikeys), and the avoidance of public services having questionable privacy policies (use alternatives such as ProtonMail, SpiderOak, Duckduckgo, RedPhone, TextSecure, etc...). Most of all, be aware that everything written in the clear, as in an email sent to friend on a webmail account, a "private" message on a forum, or a standard mobile phone SMS, can be potentially intercepted and is thus to be considered public.
With VPN, you will prevent your traffic from being intercepted and watched either in a public WIFI or by your ISP, or by any country practising global surveillance. It is thus possible to reach security and privacy. One caveat mentioned in the aformentioned article, is that traffic leaving your VPN server is not encrypted and requires end-to-end encryption to protect your privacy (HTTPS, SSH, SMTPS, DNSCrypt, etc...). Security is not automatic while using a VPN however, if we read this spiegel.de article. We learn that the NSA is able to break some VPN such as PPTP or even IPSEC, but that's the how which is interesting, instead of declaring VPN "broken" alltogether. First method is for NSA to participate in encryption standard elaboration to weaken these standards (IETF). If we bought products using less secure encryption, it will be easier for them to decrypt. Then for IPSEC connections for instance, which is more robust, they do not break the protocol itself and hence any IPSEC connection, but are rather using their TAO team to hack routers to steal the keys. NSA targeted for instance a VPN provider named SecurityKiss in Ireland. Security of both VPN protocol and both endpoints (client and server) is of first importance to have a secure connection. If we use the best in class "uncrackable" encryption, but that the server or clients are not secured enough, secret keys can be stolen and VPN decrypted.
Privacy, even if we use strong VPN encryption with very secure server and clients, is a fragile thing. Indeed, at the other end of the tunnel, on the websites and forums you visit, what you type there is of critical importance to your privacy. Obviously, posting your whole life on Facebook quite nullifies the privacy acquired by the use of VPN. Also, even if you use a secure and privacy minded mailbox such as ProtonMail, if you still communicate with Gmail clients your emails will still be read. Additionaly, if in the confort of your VPN you confess to Google Search engine all of your questions, fears, or interests, your privacy will have a very short life (I advise using Duckduckgo search engine instead).
What about anonymity? If we have a good security and privacy, are we automatically anonymous? Having privacy is not the same as being anonymous. If you know my real name because I choose to, but I do not disclose to you my favourite movie, or what books I like to read, I have privacy (I choose what I want to say to who I want). If however you don't even know who I am, I have anonymity. Anonymity is really tricky to achieve. Even if you use a VPN, your browser is likely to betray you with tracking cookies. If you go to a particular website with a VPN server located in a foreign country, the website will see your connection coming from this country, but if it uses tracking cookies it will recognize you anyway. Browser fingerprints are pretty unique too and can be used to identify you no matter which VPN you use and even if you disable all cookies. You can test you browser fingerprint uniqueness at https://panopticlick.eff.org/. My browser fingerprint is unique among nearly 5 millions tests done on this site! The fact I did the test with a VPN and am using Ghostery browser plugin does not change anything. By using the TOR browser with default settings, still trough my VPN, my fingerprint was matching 8655 other browsers fingerprints, I was no longer uniquely identifiable.
Achieving security, privacy, and anonymity, requires proper end-to-end encryption and security (server and client). It also requires the use of multiple tools and encrypted channels (VPN, Tor, HTTPS, 2FA with Yubikeys), and the avoidance of public services having questionable privacy policies (use alternatives such as ProtonMail, SpiderOak, Duckduckgo, RedPhone, TextSecure, etc...). Most of all, be aware that everything written in the clear, as in an email sent to friend on a webmail account, a "private" message on a forum, or a standard mobile phone SMS, can be potentially intercepted and is thus to be considered public.
CONCLUSION :
___________________________________________________
___________________________________________________
We have seen how to build an OpenVPN server based on OpenBSD, to benefit from OpenBSD's memory protection, randomness implementation, LibreSSL, and secure by default philosophy.
I find the VPS server to be a cost effective way to build our own VPN server, with many benefits such as snapshot before an upgrade, full access to boot the wanted ISO, remote console access,
datacenter country location choice, and Two-Factor authentication with Yubikey. It is a way to be in full control of your computer, your home router, and your VPN server at the other
end.
However, there is still benefits of using an external VPN provider such as AirVPN. You spend less money yearly, less time as you do not have to maintain a server or upgrade it, and you have other options such as tunneling VPN inside a SSH or SSL connection. You can switch of VPN server country more quickly, whereas on Vultr you would have to setup DHCP again on your server, do a snapshot, delete your server, and restore the snapshot by selecting a different datacenter. It is still nice to be able to do such manipulation though!
By using an external VPN provider you choose convenience, whereas by managing your own server you prioritize control and trust. Make your choice!
However, there is still benefits of using an external VPN provider such as AirVPN. You spend less money yearly, less time as you do not have to maintain a server or upgrade it, and you have other options such as tunneling VPN inside a SSH or SSL connection. You can switch of VPN server country more quickly, whereas on Vultr you would have to setup DHCP again on your server, do a snapshot, delete your server, and restore the snapshot by selecting a different datacenter. It is still nice to be able to do such manipulation though!
By using an external VPN provider you choose convenience, whereas by managing your own server you prioritize control and trust. Make your choice!
LINKS
___________________________________________________
___________________________________________________
http://www.openbsd.org
https://www.vultr.com
http://whoer.net/
https://stribika.github.io
http://www.cyanogenmod.org
https://en.wikipedia.org
http://www.spiegel.de
https://spideroak.com
https://protonmail.ch
https://duckduckgo.com
https://panopticlick.eff.org
https://www.ghostery.com
https://www.torproject.org
https://airvpn.org
https://www.vultr.com
http://whoer.net/
https://stribika.github.io
http://www.cyanogenmod.org
https://en.wikipedia.org
http://www.spiegel.de
https://spideroak.com
https://protonmail.ch
https://duckduckgo.com
https://panopticlick.eff.org
https://www.ghostery.com
https://www.torproject.org
https://airvpn.org
Follow me @gkweb76