Introduction
A virtual private network, or VPN, allows you to securely encrypt traffic as it travels through untrusted networks, such as those at the coffee shop, a conference, or an airport.
IKEv2, or Internet Key Exchange v2, is a protocol that allows for direct IPSec tunneling between the server and client. In IKEv2 VPN implementations, IPSec provides encryption for the network traffic. IKEv2 is natively supported on some platforms (OS X 10.11+, iOS 9.1+, and Windows 10) with no additional applications necessary, and it handles client hiccups quite smoothly.
In this tutorial, you’ll learn how to setup lKEv2 VPN server on an EdgeRouter or a VyOS virtual appliance.
Prerequisites
To complete this tutorial, you will need:
- An Edgerouter, USG or a VPS host running VyOS 1.2.5
- Set up DDNS service if your ISP only assigns a dynamic IP for you.
Creating a Certificate Authority
An IKEv2 server requires a certificate to identify itself to clients.
Let’s create a few directories to store all the assets we’ll be working on. The directory structure matches some of the directories in /etc/ipsec.d
.
mkdir -p ~/ipsec.d/{cacerts,certs,private,reqs}
Execute following commands to generate the CA key and certificate.
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \ -keyout ~/ipsec.d/private/ca-key.pem \ -out ~/ipsec.d/cacerts/ca-cert.cer \ -subj "/CN=Creekside Root CA"
You can change the common name (CN) values to something else to if you would like. The common name here is just the indicator, so it doesn’t have to match anything in your infrastructure.
Generating a Certificate for the VPN Server
Generating the private key
StrongSwan will only use one private key for per port. Since we may also need to add site-to-site VPN connections in the future, let’s use system built-in generate vpn rsa-key commands to generate the VPN server’s private key.
[email protected]:~$ generate vpn rsa-key | tee localhost.pub Generating 2048 bit rsa-key to /config/ipsec.d/rsa-keys/localhost.key .........+++++ ...........................+++++ Your new local RSA key has been generated The public portion of the key is: 0sAwEAAe7k2zE85tw4T7BGQGjkGEcIB3K7PnktckNx/JskpkhAjcU3TE7Q9xj6MtjWw794XKNFk2cnGmLCD9tkNPK30vITi3quJQxVNfuTJy3rFT6uJfPxyNsnCr+D483UNYdJThtsac8zenBoqQVMS5O50Db7/6UFdKF6QsoAMd9aRyROFZ+3RBiPe3uDMMwCaFEW28EFKN3Ye47LTCk1r1V/cXIUsMa9uVkgy9b5Axp+FnYwDl84m2mbViE+/sm7WPRGpuR15nFVwZHlk8Fj+USXMmjdteqOzq0Q19I4ma7v15LLdKlhhboxJiwjO/OqRzKsW4zt+5GcvbCagF6PzM942ok=
It is a good practice to always keep the public in configurations for future use. Replace the pub key section of following commands with the actual key generated from previous step.
configure set vpn rsa-keys local-key file /config/ipsec.d/rsa-keys/localhost.key set vpn rsa-keys rsa-key-name localhost.pub rsa-key 0sAwEAAe7k2zE85tw4T7BGQGjkGEcIB3K7PnktckNx/JskpkhAjcU3TE7Q9xj6MtjWw794XKNFk2cnGmLCD9tkNPK30vITi3quJQxVNfuTJy3rFT6uJfPxyNsnCr+D483UNYdJThtsac8zenBoqQVMS5O50Db7/6UFdKF6QsoAMd9aRyROFZ+3RBiPe3uDMMwCaFEW28EFKN3Ye47LTCk1r1V/cXIUsMa9uVkgy9b5Axp+FnYwDl84m2mbViE+/sm7WPRGpuR15nFVwZHlk8Fj+USXMmjdteqOzq0Q19I4ma7v15LLdKlhhboxJiwjO/OqRzKsW4zt+5GcvbCagF6PzM942ok= commit;save;exit
Let’s copy the localhost.key to our working directory, and make it readable.
sudo cp /config/ipsec.d/rsa-keys/localhost.key ~/ipsec.d/private/server-key.pem mv ./localhost.pub ~/ipsec.d/certs/ sudo chmod +r ~/ipsec.d/private/server-key.pem
Creating and signing the VPN server certificate
Before we sign the VPN server certificate, we need to generate a certificate request file (csr). Replace the value in subject option with the full domain name of your VPN server.
openssl req -new -nodes \ -key ~/ipsec.d/private/server-key.pem \ -out ~/ipsec.d/reqs/server-req.csr \ -subj /CN="vpn.creekside.network"
Since a VPN server certificate requires SAN name, we need to create a extension file to add additional options. Change the alt_names to the full domain name of your VPN server and execute following commands.
echo "authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth,clientAuth subjectAltName = @alt_names [alt_names] DNS.1 = vpn.creekside.network" > ~/ipsec.d/reqs/server-req.ext
You may also use more than one domain name or/and IP address to identify your server as following:
.... [alt_names] DNS.1 = vpn.creekside.network DNS.2 = vpn2.creekside.network IP.1 = 123.45.67.89 ...
Finally we sign the server certificate.
openssl x509 -req -days 3650 -CAcreateserial \ -in ~/ipsec.d/reqs/server-req.csr \ -CA ~/ipsec.d/cacerts/ca-cert.cer \ -CAkey ~/ipsec.d/private/ca-key.pem \ -out ~/ipsec.d/certs/server-cert.pem \ -extfile ~/ipsec.d/reqs/server-req.ext
Preserve the certificates
In order to preserve the certificates and keys against a firmware upgrade, we need to copy the assets we just generated to /
config folder.
sudo cp -r ~/ipsec.d /config/
Configuring StrongSwan
Following command will generate a standard configuration file ipsec.conf
under /config/ipsec.d
.
You may want to update the leftid
in last line of the configure file to your VPN DNS name.
echo " # customized roadwarrior configuration by Creekside Networks LLC config setup uniqueids=never ca rootca cacert=/config/ipsec.d/cacerts/ca-cert.cer auto=add conn winlx ike=aes256-sha1-modp1024,aes128-sha1-modp1024,3des-sha1-modp1024! esp=aes256-sha1,aes128-sha1,3des-sha1! keyexchange=ikev2 compress=no type=tunnel fragmentation=yes forceencaps=yes ikelifetime=4h lifetime=2h auto=add dpddelay=300s dpdtimeout=30s dpdaction=clear rekey=no left=%any leftcert=/config/ipsec.d/certs/server-cert.pem leftsendcert=always leftsubnet=0.0.0.0/0 right=%any rightid=%any rightsourceip=10.255.255.1/24 rightdns=8.8.8.8,8.8.4.4 rightsendcert=never rightauth=eap-mschapv2 eap_identity=%identity conn apple also=winlx lefti[email protected] " | sudo tee /config/ipsec.d/ipsec.conf
Let’s explain the configuration details here.
First we tell StrongSwan to allow duplicate connections, and instruct it to load CA certificate from /config/ipsec.d/cacerts/ca-cert.cer with these lines.
config setup uniqueids=never ca rootca cacert=/config/ipsec.d/cacerts/ca-cert.cer
Then, we’ll create a configuration section for our VPN. Due to limited hardware offload engines on EdgeRouter platforms, we only specify three crypto algorithms in the configuration file. Don’t worry it will be sufficient for most clients, including Windows 7 and up, macOS, iOS, Android and Ubuntu.
conn winlx ike=aes256-sha1-modp1024,aes128-sha1-modp1024,3des-sha1-modp1024! esp=aes256-sha1,aes128-sha1,3des-sha1!
We’ll also tell StrongSwan to create IKEv2 VPN Tunnels and to automatically load this configuration section when it starts up. Append the following lines to the file:
keyexchange=ikev2 compress=no type=tunnel fragmentation=yes forceencaps=yes ikelifetime=4h lifetime=2h auto=add
We’ll also configure dead-peer detection to clear any “dangling” connections in case the client unexpectedly disconnects. Add these lines:
dpddelay=300s dpdtimeout=30s dpdaction=clear
Then, we’ll configure the server (left) side IPSec parameters. Add this to the file:
left=%any leftcert=/config/ipsec.d/certs/server-cert.pem leftsendcert=always leftsubnet=0.0.0.0/0
Next, we can configure the client (right) side IPSec parameters, like the private IP address ranges and DNS servers to use:
right=%any rightid=%any rightsourceip=10.255.255.1/24 rightdns=8.8.8.8,8.8.4.4 rightsendcert=never
Finally, we’ll tell StrongSwan to ask the client for user credentials when they connect:
rightauth=eap-mschapv2 eap_identity=%identity
We will create a dedicated connection for Apple device. First we use directive “also=” to copy everything from connection “winlx”.
conn apple also=winlx
which requires remote ID correspond to the server ID (leftid) in StrongSwan. Only include the @
character if your VPN server will be identified by a domain name:
[email protected]
If the server will be identified by its IP address, just put the IP address in:
leftid=123.45.67.89
Configuring VPN Authentication
Our VPN server is now configured to accept client connections, but we don’t have any credentials configured yet. We’ll need to configure a couple things in a special configuration file in /config/ipsec.d/ipsec.secrets:
- We need to tell StrongSwan where to find the private key for our server certificate, so the server will be able to authenticate to clients.
- We also need to set up a list of users that will be allowed to connect to the VPN.
Let’s generate the secrets file using following command.
echo " # roadwarrior user accounts : RSA /config/ipsec.d/private/server-key.pem bob : EAP bobpasswd alice : EAP alicepasswd " | sudo tee /config/ipsec.d/ipsec.secrets
In above command, we’ll tell StrongSwan where to find our private key first:
: RSA /config/ipsec.d/private/server-key.pem
Then, we’ll define the user credentials. You can make up any username or password combination that you like:
your_username : EAP "your_password"
Configuring the Router
Activate IPSec configuration
With the StrongSwan configuration complete, we need to add them to router’s configuration. Also assign eth0 as the IPSec interface.
configure set vpn ipsec include-ipsec-conf /config/ipsec.d/ipsec.conf set vpn ipsec include-ipsec-secrets /config/ipsec.d/ipsec.secrets set vpn ipsec ipsec-interface interface eth0
WAN policies
If you already followed prerequisite tutorial, you should already enable WAN firewall policy. We need to add extra rules to allow ike and esp packets passthrough.
set firewall name WAN_LOCAL rule 200 action 'accept' set firewall name WAN_LOCAL rule 200 description 'ipsec ike' set firewall name WAN_LOCAL rule 200 destination port '500,4500' set firewall name WAN_LOCAL rule 200 log 'disable' set firewall name WAN_LOCAL rule 200 protocol 'udp' set firewall name WAN_LOCAL rule 201 action 'accept' set firewall name WAN_LOCAL rule 201 description 'ipsec esp' set firewall name WAN_LOCAL rule 201 log 'disable' set firewall name WAN_LOCAL rule 201 protocol 'esp' set firewall name WAN_IN rule 210 action 'accept' set firewall name WAN_IN rule 210 description 'ipsec traffic' set firewall name WAN_IN rule 210 log 'disable' set firewall name WAN_IN rule 210 protocol 'all' set firewall name WAN_IN rule 210 ipsec match-ipsec
To allow VPN client access internet and local resource, we need extra rules to enable decrypted traffic pass-through.
set firewall name WAN_LOCAL rule 210 action 'accept' set firewall name WAN_LOCAL rule 210 description 'ipsec traffic' set firewall name WAN_LOCAL rule 210 log 'disable' set firewall name WAN_LOCAL rule 210 protocol 'all' set firewall name WAN_LOCAL rule 210 ipsec match-ipsec
TCP MSS
We need to tell firewall to adjust the maximum packet segment size (TCP MSS) to prevent potential issues with certain VPN clients.
VyOS
set firewall options interface eth0 adjust-mss 1360
EdgeOS
set firewall options mss-clamp interface-type all set firewall options mss-clamp mss 1360
NAT Exclude
For the traffic send to VPN client, we need exclude them from NAT. Please be advised this rule should be placed prior to WAN interface masquerade rule.
VyOS
set nat source rule 10 escription "exclude roadwarrior ipsec" set nat source rule 10 destination address 10.255.255.0/24 set nat source rule 10 exclude set nat source rule 10 log disable set nat source rule 10 outbound-interface eth0 set nat source rule 10 protocol all set nat source rule 10 translation address masquerade
EdgeOS
set service nat rule 5001 description "exclude roadwarrior ipsec" set service nat rule 5001 destination address 10.255.255.0/24 set service nat rule 5001 exclude set service nat rule 5001 log disable set service nat rule 5001 outbound-interface eth0 set service nat rule 5001 protocol all set service nat rule 5001 type masquerade
Additional consideration for USG
By default, USG does not has the source NAT for outgoing road warrior VPN traffic. Following commands will add a source NAT rule after the IPSec NAT exclude rule we just added.
set service nat rule 5002 description "masquerade road-warrior" set service nat rule 5002 source address 10.255.255.0/24 set service nat rule 5002 log disable set service nat rule 5002 outbound-interface eth0 set service nat rule 5002 protocol all set service nat rule 5002 type masquerade
Finally, commit and save your configuration.
commit;save;exit
Testing the VPN connection
Setup and test from your clients
Now that you have everything set up, it’s time to try it out. First, you’ll need to copy the CA certificate you created and install it on your client device(s) that will connect to the VPN. The easiest way to do this is to log into your server and output the contents of the certificate file:
cat /config/ipsec.d/cacerts/ca-cert.cer
You’ll see output similar to this:
-----BEGIN CERTIFICATE----- MIIFQjCCAyqgAwIBAgIIFkQGvkH4ej0wDQYJKoZIhvcNAQEMBQAwPzELMAkGA1UE . . . EwbVLOXcNduWK2TPbk/+82GRMtjftran6hKbpKGghBVDPVFGFT6Z0OfubpkQ9RsQ BayqOb/Q -----END CERTIFICATE-----
Copy this output to your computer, including the -----BEGIN CERTIFICATE-----
and -----END CERTIFICATE-----
lines, and save it to a file with a recognizable name, such as ca-cert.cer
. Ensure the file you create has the .cer
extension.
Alternatively, use SFTP to transfer the file to your computer.
Once you have the ca-cert.pem
file downloaded to your computer, you can set up the connection to the VPN.
Please follow our other tutorial How to setup IPSec VPN Client to set up your VPN client.
Debug commands
Following are some debug commands can be used on EdgeOS and VyOS.
openssl x509 -text -in <path to your certificate file> sudo ipsec statusall sudo ipsec listcerts sudo ipsec restart sudo swanctl --log
Scripts
To make above set up process easier, we prepared a script that can help you to automatically generate the certificates, and configure the VPN section for you. You may still need to configure the firewall rules and NAT rule on your own as they are subject to actual deploy environment.
Use following command to download to your router, you need to input your VPN server’s fully qualified domain name (FQDN), such as vpn.creekside.network
.
You may want to set up DNS record or DDNS before executing the script, since it will verify your input by trying to resolve the FQDN of your VPN server.
curl https://raw.githubusercontent.com/creeksidenetworks/edgerouter-roadwarrior-ikev2/master/ubnt-ikev2-cfg.sh -o ubnt-ikev2-cfg.sh chmod +x ubnt-ikev2-cfg.sh ./ubnt-ikev2-cfg.sh