StrongSwan IKEv2 VPN on Raspberry pi

By Atomstar on Monday 24 December 2018 01:08 - Comments (4)
Categories: Linux, RaspberryPi, Views: 2.466

Guide to set up road warrior VPN server (i.e. road warrior = mobile clients connecting to static server, vs e.g. site-to-site connection) using IKEv2 using strongswan on a raspberry pi. This guide is largely based on this digitalocean guide combined with ready-made strongswan configurations.

Rationale for IKEv2/Strongswan

I've decided to go for IKEv2 for two main reasons:
  1. it's natively supported by iOS and macOS and
  2. it only requires strongswan to operate.
Two other options are 1) OpenVPN: requires non-native app/program to connect. 2) IPSEC/L2TP: requires xl2tpd on top of *swan.

After deciding on IKEv2, there are four main contenders for implementation. I chose strongswan because
  1. it's available in the default Raspbian/debian apt repository and
  2. it appears newer than openswan.
Libreswan dropped out because it's not available from the default apt repo, so it required compiling from source, which would've taken a long time on a raspberry pi. Softether also looks very promising (thanks Sterk1!) as it supports a wide range of VPN protocols. Unfortunately like Libreswan this is also not available from the default apt repo.

Alternative guides

I found some alternative guides/setups that could also work very well:
Automated installer scripts
There are a few scripts that automate VPN setup. One requirement is that you trust the script to run as root, which I prefer not to. The advantage is that these scripts might have thought of more than I did, and are better maintained than static guides.
Manual guides
Other guides have instructions to install VPN manually:

Target setup

The target setup is as follows:
  • My network is on 172.16.0.0/16,
  • the router/DNS server is available on 172.16.0.1,
  • the raspberry pi is at ${SERVER_FQDN}.
  • I want the VPN clients to be on 172.16.1.0/16 and use the same DNS server.
To this end, set the following variables:
SERVER_FQDN="my.router.com"
DNS_SERVER="172.16.0.1"
VPN_SUBNET="172.16.1.0/16"
SERVER_COUNTRY="NL"
YOUR_USERNAME="vpnuser"
YOUR_PASSWORD="vpnpassword"


Install required software

Plugins are required to support EAP-MSCHAPv2
sudo apt get install strongswan strongswan-pki strongswan-ikev2 \
  libcharon-extra-plugins libstrongswan-extra-plugins


Generate certificates and keys

More or less directly copied from the guide mentioned above. Ideally run this as a trusted user in a directory that nobody else can access:
# ensure no other use can read this
mkdir ~/vpn-certs/
cd ~/vpn-certs/
chmod 600 .

ipsec pki --gen --type rsa --size 4096 --outform pem > server-root-key.pem
chmod 600 server-root-key.pem

ipsec pki --self --ca --lifetime 3650 \
    --in server-root-key.pem \
    --type rsa --dn "C=${SERVER_COUNTRY}, O=VPN Server, CN=VPN Server Root CA" \
    --outform pem > server-root-ca.pem

ipsec pki --gen --type rsa --size 4096 --outform pem > vpn-server-key.pem

ipsec pki --pub --in vpn-server-key.pem \
    --type rsa | ipsec pki --issue --lifetime 1825 \
    --cacert server-root-ca.pem \
    --cakey server-root-key.pem \
    --dn "C=${SERVER_COUNTRY}, O=VPN Server, CN=${SERVER_FQDN}" \
    --san ${SERVER_FQDN} \
    --flag serverAuth --flag ikeIntermediate \
    --outform pem > vpn-server-cert.pem

sudo cp ./vpn-server-cert.pem /etc/ipsec.d/certs/vpn-server-cert.pem
sudo cp ./vpn-server-key.pem /etc/ipsec.d/private/vpn-server-key.pem

sudo chown root /etc/ipsec.d/private/vpn-server-key.pem
sudo chgrp root /etc/ipsec.d/private/vpn-server-key.pem
sudo chmod 600 /etc/ipsec.d/private/vpn-server-key.pem


/etc/ipsec.conf

# based on 
# https://www.digitalocean.com/community/tutorials/how-to-set-up-an-ikev2-vpn-server-with-strongswan-on-ubuntu-16-04
# combined with improved cipher selection from 
# https://wiki.strongswan.org/projects/strongswan/wiki/UsableExamples 
# with improved cipher selection

config setup
    charondebug="ike 1, knl 1, cfg 0"
    uniqueids=no

conn ikev2-vpn
    auto=add
    compress=no
    type=tunnel
    keyexchange=ikev2
    fragmentation=yes
    forceencaps=yes
    #ike=aes256-sha1-modp1024,3des-sha1-modp1024!
    ike=aes192gcm16-aes128gcm16-prfsha256-ecp256-ecp521,aes192-sha256-modp3072,default
    #esp=aes256-sha1,3des-sha1!
    esp=aes192gcm16-aes128gcm16-ecp256-modp3072,aes192-sha256-ecp256-modp3072

    dpdaction=clear
    dpddelay=300s
    rekey=no
    left=%any
    leftid=@${SERVER_FQDN}
    leftcert=/etc/ipsec.d/certs/vpn-server-cert.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0
    right=%any
    rightid=%any
    rightauth=eap-mschapv2
    rightdns=${DNS_SERVER}
    rightsourceip=${VPN_SUBNET}
    rightsendcert=never
    eap_identity=%identity


/etc/ipsec.secrets

${SERVER_FQDN} : RSA "/etc/ipsec.d/private/vpn-server-key.pem"
${YOUR_USERNAME} %any% : EAP "${YOUR_PASSWORD}"


iptables

# ensure we don't lock our ssh session out
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# always accept loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# accept ports 500 and 4500, required for IKEv2
sudo iptables -A INPUT -p udp --dport  500 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT

# forward ESP
sudo iptables -A FORWARD --match policy --pol ipsec --dir in  --proto esp \
  -s ${VPN_SUBNET} -j ACCEPT
sudo iptables -A FORWARD --match policy --pol ipsec --dir out --proto esp \
  -d ${VPN_SUBNET} -j ACCEPT

# more forwarding
sudo iptables -t nat -A POSTROUTING -s ${VPN_SUBNET} -o eth0 -m policy \
  --pol ipsec --dir out -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s ${VPN_SUBNET} -o eth0 -j MASQUERADE

# fix fragmentation
sudo iptables -t mangle -A FORWARD --match policy --pol ipsec --dir in \
  -s ${VPN_SUBNET} -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss \
  --mss 1361:1536 -j TCPMSS --set-mss 1360

# Drop everything we don't accept - for added security. 
# NB only add if you know what you're doing,
# I accidentally locked out my grafana/influxdb setup here :p
# Also, for a router behind NAT I think this is superfluous.
#sudo iptables -A INPUT -j DROP
#sudo iptables -A FORWARD -j DROP

# make persistent
sudo netfilter-persistent save
sudo netfilter-persistent reload

To review your iptables rules, this StackExchange post explains how to view all iptables tables, by default only the filter table is shown:

iptables -vL -t filter
iptables -vL -t nat
iptables -vL -t mangle
iptables -vL -t raw
iptables -vL -t security


/etc/sysctl.conf

Run sysctl -p after updating. If that doesn't work, reboot.
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

# Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
# Do not send ICMP redirects (we are not a router)
net.ipv4.conf.all.send_redirects = 0

# Not sure if this is required, I added it to be sure
net.ipv4.ip_no_pmtu_disc = 1

Optionally, ensure port-forwarding on your home router is enabled such that udp 4500 and 500 on the server are reachable from the internet.

Connecting clients

Ensure you install server-root-ca.pem on any clients. On macOS, after adding to keychain, make sure to trust it explicitly.

For iOS/macOS, Server and Remote ID are the same FQDN of your server.

After setting everything up, you're done!

Troubleshooting

  • loading EAP_MSCHAPV2 method failed -- ensure you have charon and strongswan plugins installed (libcharon-extra-plugins libstrongswan-extra-plugins)
  • "Authentication failure" or immediate disconnect from iOS/macOS -- this happens when you don't explicitly install or trust the server certificate.
  • loading EAP_DYNAMIC method failed -- this happens when you have multiple EAP authentication methods in IPSec.conf but no associated strongswan.conf solution. Note this is also listed explicitly in the example configuration file (if you read this 8)):
    IF you need to support several EAP methods at the same time, you need to use eap-dynamic and not use any other conn with eap settings. Add the settings for the eap-dynamic plugin to your strongswan.conf file.
  • unknown attribute type (25) -- this is not really an error
  • received ESP_TFC_PADDING_NOT_SUPPORTED, not using ESPv3 TFC padding -- this is not an error either

Volgende: Measuring CO2 using MH-Z19B and D1 mini pro 20-12 Measuring CO2 using MH-Z19B and D1 mini pro

Comments


By Tweakers user Sterk1, Monday 24 December 2018 11:02

softether wel eens overwogen ?
werkt geweldig als server op de raspberry pi
en native op, windows, mac en ios

mooie grafiscne interface en zeer flexibel

By Tweakers user Qwerty-273, Monday 24 December 2018 11:02

Any specific reason to choose the United States of America as the location? Or just as it was in the guide, or is the environment / ownership based in the US?
https://www.digicert.com/ssl-certificate-country-codes.htm

By Tweakers user Atomstar, Monday 24 December 2018 12:46

Looks promising! I've added it to the list of alternatives, thanks!
Qwerty-273 wrote on Monday 24 December 2018 @ 11:02:
Any specific reason to choose the United States of America as the location?
That was the default, I've added a variable to capture this. Thanks!

By Tweakers user GekkePrutser, Tuesday 25 December 2018 16:57

Another important point: IKEv2 is also natively supported on all Samsung smartphones.

Android as such only supports IKEv1 but Samsung has added IKEv2 support to the base OS on their phones.

Another reason to have IKEv2 is that it is rarely blocked due to its use being very common in the corporate world. Unlike things like WireGuard.

Personally I also use IKEv2 with StrongSwan but I used algo to set it up, which makes the process quite easy. Unfortunately they moved to WireGuard for Android devices but IKEv2 still works as they still support it for iOS, so you can simply use it on Android as well by manually configuring it.

[Comment edited on Tuesday 25 December 2018 16:58]


Comment form
(required)
(required, but will not be displayed)
(optional)