StrongSwan IKEv2 VPN on Raspberry pi
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.
Update 20181224: added algo VPN configurator
Update 20190223: added cipher analysis / recommendation, clarified eth0 interface use on server, ESP/AH forwarding, added password generation one-liner.
Update 20200801: minor fixes in commands.
After deciding on IKEv2, there are four main contenders for implementation. I chose strongswan because
Encryption: aes128, aes192, aes256, aes128gcm16, aes192gcm16, aes256gcm16
Integrity: sha256, sha384, sha512
Sign: modp2048, modp3072, modp4096, ecp256, ecp384, ecp521
When authenticating by password, use long passwords with at least the entropy content as the cipher strength (e.g. 128 bit for AES128).
The default ciphers on StrongSwan are reasonably OK, although unfortunately the broken MD5, SHA1, and 3DES are also included (perhaps for compatibility). Unfortunately, I haven't found a way to remove support for specific ciphers, and removing the plugins from /etc/strongswan.d/charon does not work.
There are two ways to fix this:
ESP syntax is encryption-integrity[-dhgroup][-esnmode], for IKE this is encryption-integrity[-prf]-dhgroup. By using encryption-integrity-dhgroup, these are compatible
with each other. Unfortunately you have to list all permutations of the encryption, integrity, and signing ciphers. Don't forget to add an exclamation mark to enforce these ciphers!
If you want to specifically enable ciphers on the server, you could use this python script (not tested!).
dsa4096 and ecdsap512 gave a segfault on openssl, not sure why.
If you want to select your own ciphers, read here on how to configure, here on what key length is recommended, and here for general security recommendations.
N.B. Make sure your password is strong enough! To generate a strong password, use the following (source):
This gives a 32-character length string of 6 bit printable characters (base64 is 6-bit) such that the password strength is 32*6 = 192bit.
To review your iptables rules, this StackExchange post explains how to view all iptables tables, by default only the filter table is shown:
Run sysctl -p after updating. If that doesn't work, reboot.
For iOS/macOS, Server and Remote ID are the same FQDN of your server.
After setting everything up, you're done!
Update 20181224: added algo VPN configurator
Update 20190223: added cipher analysis / recommendation, clarified eth0 interface use on server, ESP/AH forwarding, added password generation one-liner.
Update 20200801: minor fixes in commands.
Rationale for IKEv2/Strongswan
I've decided to go for IKEv2 for two main reasons:- it's natively supported by iOS and macOS and
- it only requires strongswan to operate.
After deciding on IKEv2, there are four main contenders for implementation. I chose strongswan because
- it's available in the default Raspbian/debian apt repository and
- it appears newer than openswan.
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.- algo - automated script supporting IKEv2 among others, and explicitly not supporting weak keys (thanks GekkePrutser!)
- Automatic install of IPsec-L2TP/Libreswan setup -- runs on libreswan compiled from source
Manual guides
Other guides have instructions to install VPN manually:- StrongSwan IKEv2 VPN on a Raspberry Pi -- similar guide
- Automatic install of IPsec-L2TP/Libreswan setup -- this requires compiling from source and trusting someone else's script (which I don't)
- Openswan IPsec-L2TP
- https://vpnki.com/settings/linux/debian-l2tp-ipsec
- https://www.raspberrypi.org/forums/viewtopic.php?p=704519
- https://openwrt.org/docs/...ec/strongswan/roadwarrior
Target setup
The target setup is as follows:- My network is on 172.16.0.0/24,
- 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/24 and use the same DNS server. Alternatively instead of using virtual IPs, you can assign DHCP'ed IPs to VPN clients by setting VPN_SUBNET to %dhcp
SERVER_FQDN="my.router.com" DNS_SERVER="172.16.0.1" VPN_SUBNET="172.16.1.0/24" VPN_IFACE="eth0" SERVER_COUNTRY="NL" YOUR_USERNAME="vpnuser" YOUR_PASSWORD="vpnpassword"
Ciphers and security recommendations
These guides have a nice overview of cipher security, from which I distilled this selection:Encryption: aes128, aes192, aes256, aes128gcm16, aes192gcm16, aes256gcm16
Integrity: sha256, sha384, sha512
Sign: modp2048, modp3072, modp4096, ecp256, ecp384, ecp521
When authenticating by password, use long passwords with at least the entropy content as the cipher strength (e.g. 128 bit for AES128).
The default ciphers on StrongSwan are reasonably OK, although unfortunately the broken MD5, SHA1, and 3DES are also included (perhaps for compatibility). Unfortunately, I haven't found a way to remove support for specific ciphers, and removing the plugins from /etc/strongswan.d/charon does not work.
There are two ways to fix this:
- Set secure ciphers server-side manually and explicitly
- Choose secure ciphers client-side
Server-side ciphers
The relevant ipsec.conf settings are esp and ike.ESP syntax is encryption-integrity[-dhgroup][-esnmode], for IKE this is encryption-integrity[-prf]-dhgroup. By using encryption-integrity-dhgroup, these are compatible
with each other. Unfortunately you have to list all permutations of the encryption, integrity, and signing ciphers. Don't forget to add an exclamation mark to enforce these ciphers!
If you want to specifically enable ciphers on the server, you could use this python script (not tested!).
code:
1
2
3
4
5
6
| encrypt =['aes128', 'aes192','aes256','aes128gcm16','aes192gcm16','aes256gcm16'] integrity=['sha256','sha384','sha512'] sign = ['modp2048','modp3072','modp4096','ecp256','ecp384','ecp521'] ciphersuites = [e+'-'+i+'-'+s for e in encrypt for i in integrity for s in sign] ",".join(ciphersuites)+"!" |
Client-side ciphers
See my other post on creating iOS profiles.Speed
Since this is running on a raspberry, speed is also relevant. I found these results on my RPi3B+ using openssl speed -evp <cipher> and openssl speed <sign>. Although the speeds are to some extent in arbitrary units, the relative values should be comparable. Based on this I chose to use SHA256 with AES-128-CBC and ECP256 for my own setup.The 'numbers' are in 1000s of bytes per second processed. type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes 16384 bytes md5 24634.10k 74728.55k 154655.66k 211365.59k 224220.50k 232265.05k sha1 6816.60k 22071.29k 53680.45k 82852.25k 99040.45k 92405.76k sha256 6001.71k 18437.16k 46062.42k 68029.68k 74043.08k 76436.82k sha384 3025.30k 12140.95k 19447.72k 29114.71k 34839.29k 32287.40k aes-128-cbc 30789.43k 43457.24k 47193.47k 47911.17k 48994.78k 48894.46k aes-192-cbc 38234.35k 38777.04k 43397.33k 43725.83k 42692.50k 42976.49k aes-256-cbc 33992.59k 36185.00k 35603.11k 38232.87k 37623.13k 35748.90k aes-128-gcm 21008.15k 25713.49k 27408.30k 27992.41k 28466.52k 26858.84k aes-192-gcm 19203.80k 23740.33k 25268.31k 24521.16k 21925.65k 22093.74k aes-256-gcm 18081.80k 22149.27k 22574.48k 22588.82k 20678.59k 22074.42k sign verify sign/s verify/s 256 bit ecdsa (nistp256) 0.0005s 0.0012s 1944.2 838.7 384 bit ecdsa (nistp384) 0.0204s 0.0109s 49.1 91.9 dsa 2048 bits 0.008810s 0.008716s 113.5 114.7
dsa4096 and ecdsap512 gave a segfault on openssl, not sure why.
Install required software
Plugins are required to support EAP-MSCHAPv2 (strongswan-ikev2 might not be needed anymore as of Ubuntu 20.04). netfilter-persistent is used to make iptables rules persistent.sudo apt install strongswan strongswan-pki strongswan-ikev2 \ libcharon-extra-plugins libstrongswan-extra-plugins netfilter-persistent
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 700 . 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 # Manually specify the ciphers here if you want. #ike=aes192gcm16-aes128gcm16-prfsha256-ecp256-ecp521,aes192-sha256-modp3072 #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} # alternatively, set rightsourceip=%dhcp to get DHCP'ed IPs from wherever the server is getting IPs from. rightsendcert=never eap_identity=%identity
If you want to select your own ciphers, read here on how to configure, here on what key length is recommended, and here for general security recommendations.
/etc/ipsec.secrets
${SERVER_FQDN} : RSA "/etc/ipsec.d/private/vpn-server-key.pem" ${YOUR_USERNAME} %any% : EAP "${YOUR_PASSWORD}"
N.B. Make sure your password is strong enough! To generate a strong password, use the following (source):
dd if=/dev/urandom count=1 bs=32 2>/dev/null | base64
This gives a 32-character length string of 6 bit printable characters (base64 is 6-bit) such that the password strength is 32*6 = 192bit.
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 ${VPN_IFACE} -m policy \ --pol ipsec --dir out -j ACCEPT sudo iptables -t nat -A POSTROUTING -s ${VPN_SUBNET} -o ${VPN_IFACE} -j MASQUERADE # fix fragmentation sudo iptables -t mangle -A FORWARD --match policy --pol ipsec --dir in \ -s ${VPN_SUBNET} -o ${VPN_IFACE} -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
# 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
Run sysctl -p after updating. If that doesn't work, reboot.
Port forwarding
Optionally (almost always), ensure port-forwarding on your home router is enabled such that UDP 4500 and 500 on the server are reachable from the internet. If using forceencaps as I did above, these are the only ports you need. If not, make sure you also forward protocols ESP and AH, but be aware that NAT'ing ESP and AH is apparently not always supported.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
):
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
01-'19 Setting up an A+-grade nginx SSL server
12-'18 Measuring CO2 using MH-Z19B and D1 mini pro
Comments
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
werkt geweldig als server op de raspberry pi
en native op, windows, mac en ios
mooie grafiscne interface en zeer flexibel
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
https://www.digicert.com/ssl-certificate-country-codes.htm
Looks promising! I've added it to the list of alternatives, thanks!Sterk1 wrote on Monday 24 December 2018 @ 11:02:
softether wel eens overwogen ?
That was the default, I've added a variable to capture this. Thanks!Qwerty-273 wrote on Monday 24 December 2018 @ 11:02:
Any specific reason to choose the United States of America as the location?
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.
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]
Hi,
great instructions. I only have a problem with the forwarding.
If I use %dhcp in the ipsec.conf to get a IP from my normal dhcp I can ping the machine where the VPN Server is running on. I also can ssh to this machine.
But all other machines in the same network cannot be reached (no ping nothing). I checked the sysctl.conf (ip4 forwarding is on) and also the rules for the iptables.
Where can I search what happens or find out what is wrong?
Many thanks and Kind Regards,
Marco
great instructions. I only have a problem with the forwarding.
If I use %dhcp in the ipsec.conf to get a IP from my normal dhcp I can ping the machine where the VPN Server is running on. I also can ssh to this machine.
But all other machines in the same network cannot be reached (no ping nothing). I checked the sysctl.conf (ip4 forwarding is on) and also the rules for the iptables.
Where can I search what happens or find out what is wrong?
Many thanks and Kind Regards,
Marco
Hi,
Is it also possible to add the config that IPv6 will work?
I was able to solve it- I had at first a typo in the ipsec.conf and then found out that the laptop uses ipv6 over LTE and therefore was not able to do anything. After I switched IPv6 off on that device it worked.Marco wrote on Tuesday 12 March 2019 @ 14:29:
Hi,
great instructions. I only have a problem with the forwarding.
Is it also possible to add the config that IPv6 will work?
This is a useful guide indeed, IKEv2 has a few advantages over OpenVPN that are really compelling, like out-of-the-box compatibility with Windows, iOS and macOS and higher efficiency/lower resources.
A few questions:
- why are you using iptables and not nftables? iptables is legacy and is already disappearing from more and more distros (eg Debian)
- can the clients communicate to each other within the VPN?
- can VPN clients open a port in the VPN gateway (with NAT-PMP/PCP) to make themselves accessible?
No IPv6 also makes this guide a bit less futureproof but I guess this still works for most users at this point in time as most 'roadwarriors' on European mobile networks are likely to be IPv4-only.
A few questions:
- why are you using iptables and not nftables? iptables is legacy and is already disappearing from more and more distros (eg Debian)
- can the clients communicate to each other within the VPN?
- can VPN clients open a port in the VPN gateway (with NAT-PMP/PCP) to make themselves accessible?
No IPv6 also makes this guide a bit less futureproof but I guess this still works for most users at this point in time as most 'roadwarriors' on European mobile networks are likely to be IPv4-only.
[Comment edited on Tuesday 9 July 2019 09:45]
Comments are closed