How to install IKEv2 VPN server on EdgeRouter or VyOS

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
    [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]ork

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

Reference