Linux Notes
2019.11.26
A managed AdBock powered by AdGuard Home with DoH & DoT enabled
AdGuard Home supports all modern DNS encryption protocols, which enable us to setup a secure DNS server with custom AdBlock filters.
strongSwan, the Road-Warrior configuration
IKEv2, or Internet Key Exchange v2, is a protocol that allows for direct IPSec tunnelling between networks. It is developed by Microsoft and Cisco (primarily) for mobile users, and introduced as an updated version of IKEv1 in 2005. The IKEv2 MOBIKE (Mobility and Multihoming) protocol allows the client to main secure connection despite network switches, such as when leaving a WiFi area for a mobile data area. IKEv2 works on most platforms, and natively supported on some platforms (OS X 10.11+, iOS 9.1+, and Windows 10) with no additional applications necessary.
This post is adapted from How to Set Up an IKEv2 VPN Server with StrongSwan on Ubuntu 22.04 with little customisations for strongSwan Road-Warrior configuration.
First, we’ll install the strongSwan daemon itself.
And, we’ll also need to install the public key infrastructure (PKI) component so that we can create a Certificate Authority (CA) to provide credentials for our infrastructure.
Go ahead to update the local package cache and install the following packages:
sudo apt update
sudo apt install strongswan strongswan-pki libcharon-extra-plugins libcharon-extauth-plugins libstrongswan-extra-plugins
The
libcharon-extauth-plugins
package is used to ensure that various clients (especially Windows 10) can authenticate to the strongSwan server using an username and passphrase. Thelibstrongswan-extra-plugins
package is included so that strongSwan supports elliptic curve cipher suites that use theCurve25519
cryptography suite.
Now that everything’s installed, let’s move on to creating our certificates.
An IKEv2 server requires a certificate to identify itself to clients. To help create the required certificates, the strongswan-pki
package comes with a utility (i.e., pki
) to generate the certificate authority and server certificates.
To begin, 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
, where we will eventually move all of the generated files.
mkdir -p ~/pki/{cacerts,certs,private}
# potects the file against any access from other users, while the issuing user still has full access
chmod 700 ~/pki
Now that we have a directory structure to store everything.
Execute the following command to generate a RSA key with a cryptographic strength of 4096 bits:
pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/ca-key.pem
Alternative key type are ecdsa, ed25519 and ed448.
Never store the private key of the Certificate Authority (
ca-key.pem
) on a host with constant direct access to the Internet since a theft of this master signing key will completely compromise your PKI.1
Following that we can move on to creating our root certificate authority, using the key that we just generated to sign the root certificate:
pki --self --ca --lifetime 3652 --in ~/pki/private/ca-key.pem \
--dn "C=CN, O=Frank inDev., CN=strongSwan Root CA" \
--type rsa \
--outform pem > ~/pki/cacerts/ca-cert.pem
The --lifetime 3652
flag is used to ensure that the certificate authority’s root certificate will be valid for 10 years. This root certificate does not change typically, since it would have to be redistributed to every server and client that rely on it, so 10 years is a safe default expiry value.
You can change the Distinguished Name (DN)2 value to something else if you would like. The Common Name (CN field) here is just the indicator, so it doesn’t have to match anything in your infrastructure, just name it of your choice.
You can list the information with the pki --print
command.
pki --print --in ~/pki/cacerts/ca-cert.pem
If you prefer the CA cert key to be in binary DER
format then just omit the --outform pem
option.
Other pki
commands can be found at https://docs.strongswan.org/docs/5.9/pki/pki.html.
Now that we’ve got our root certificate authority up and running, we can create a certificate that the StrongSwan server will use.
We’ll now create a certificate that allow the client(s) to verify the server’s authenticity using the CA certificate that we just generated.
First, create a private key for the strongSwan server with the following command:
pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/server-key.pem
Now, create and sign the strongSwan server certificate with the certificate authority’s key (ca-cert.pem
and ca-key.pem
) we just created in the previous step. Execute the following command, but change the Common Name (CN) and the Subject Alternate Name (SAN) field to your server’s DNS name or IP address:
pki --pub --in ~/pki/private/server-key.pem --type rsa \
| pki --issue --lifetime 1825 \
--cacert ~/pki/cacerts/ca-cert.pem \
--cakey ~/pki/private/ca-key.pem \
--dn "CN=server_domain_or_IP" --san "server_domain_or_IP" \
--flag serverAuth --flag ikeIntermediate \
--outform pem > ~/pki/certs/server-cert.pem
Through the use of the (multiple) --san
parameter any number of desired subjectAlternativeNames can be added. These can be of the form:
--san sun.strongswan.org # fully qualified host name
--san carol@strongswan.org # RFC822 user email address
--san 192.168.0.1 # IPv4 address
--san fec0::1 # IPv6 address
Although strongSwan doesn’t support wildcard certs, you can assign multiple domains through --san
:
--dn "CN=example.com" --san "sun.example.com" --san "moon.example.com" --san "star.example.com"
Note: If you are using an IP address instead of a DNS name, you will need to specify multiple
--san
entries. The line in the previous command block where you specify the distinguished name (--dn ...
) will need to be modified with the extra entry like the following excerpted line:
--dn "CN=IP_address --san @IP_address --san IP_address \"
The reason for this extra
--san @IP_address
entry is that some clients will check whether the TLS certificate has both an DNS entry and an IP address entry for a server when they verify its identity.
The --flag serverAuth
option is used to indicate that the certificate will be used explicitly for server authentication, before the encryption tunnel is established. The --flag ikeIntermediate
option is used to support old macOS clients.
Now that we’ve generated all of the TLS/SSL files strongSwan needs, we can move the files into place in the /etc/ipsec.d
directory by typing:
sudo cp -r ~/pki/* /etc/ipsec.d/
After this, you can safely delete the ~/pki/
folder.
strongSwan has a default configuration file with some examples, but we will have to do most of the configuration ourselves. Let’s back up that file for reference before starting from scratch:
sudo mv /etc/ipsec.conf{,.original}
Create and open a new blank configuration file by typing:
sudo nano /etc/ipsec.conf
The complete configurations look like this for ipsec.conf
:
config setup
charondebug="ike 1, knl 1, cfg 0"
uniqueids=no
conn ikev2-strongswan
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
dpdaction=clear
dpddelay=300s
rekey=no
left=%any
leftid=@server_domain_or_IP
leftcert=server-cert.pem
leftsendcert=always
leftsubnet=0.0.0.0/0
right=%any
rightid=%any
rightauth=eap-mschapv2
rightsourceip=10.10.10.0/24
rightdns=8.8.8.8,8.8.4.4
rightsendcert=never
eap_identity=%identity
ike=chacha20poly1305-sha512-curve25519-prfsha512,aes256gcm16-sha384-prfsha384-ecp384,aes256-sha1-modp1024,aes128-sha1-modp1024,3des-sha1-modp1024!
esp=chacha20poly1305-sha512,aes256gcm16-ecp384,aes256-sha256,aes256-sha1,3des-sha1!
Let’s break it down with some explanations.
First, we’ll tell strongSwan to log daemon statuses for debugging and allow duplicate connections.
config setup
charondebug="ike 1, knl 1, cfg 0"
uniqueids=no
By default, the IKE charon
daemon logs via syslog(3)
using the facilities LOG_AUTHPRIV
(only messages on log level 0
) and LOG_DAEMON
(all log levels). The default log level for all subsystems is 1
. You can further config the logging refer to https://docs.strongswan.org/docs/5.9/config/logging.html.
Then, we’ll create a configuration section for our server. And tell strongSwan to create IKEv2 tunnels and to automatically load this configuration section when it starts up.
. . .
conn ikev2-strongswan
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
We’ll also configure dead-peer detection to clear any “dangling” connections in case the client unexpectedly disconnects.
. . .
conn ikev2-strongswan
. . .
dpdaction=clear
dpddelay=300s
rekey=no
Then, we’ll configure the server (left) side IPSec parameters.
. . .
conn ikev2-strongswan
. . .
left=%any
leftid=@server_domain_or_IP
leftcert=server-cert.pem
leftsendcert=always
leftsubnet=0.0.0.0/0
Each of the parameters ensures that the server is configured to accept connections from clients and to identify itself correctly.
left=@any
: The %any
value ensures that the server will use the network interface where it receives incoming connections for subsequent communication with clients. For example, if you are connecting a client over a private network, the server will use the private IP address where it receives traffic for the rest of the connection.
leftid=@server_domain_or_IP
: This option controls the name that the server presents to clients. When combined the the next option leftcert
, the leftid
option ensures that the server’s configured name and the distinguished name that is contained in the public certificate match. If you’d like to support multiple domains, you can use leftid=@*.example.com
and your server-cert.pem
should signed with desired domain name.
leftcert=server-cert.pem
: This option is the path to the public certificate for the server that you configured in previous step. Without it, the server will not be able to authenticate itself with clients, or finish negotiating the IKEv2 set up.
leftsendcert=always
: The always
value ensures that any client that connects to the server will always receive a copy of the server’s public certificate as part of the initial connection set up.
leftsubnet=0.0.0.0/0
: This tells clients about the subnets that are reachable behind the server. In this case, 0.0.0.0/0
is used to represent the entire set of IPv4 addresses, meaning that the server will tell clients to send all their traffic over the IKEv2 tunnel by default.
Note: When configuring the server ID (leftid
), only include the @
character if your strongSwan server will be identified by a domain name:
leftid=@domain.example.com
If the server will be identified by its IP address, just put the IP address without the @
character, for example:
leftid=1.2.3.4
Next, we can configure the client (right) side IPSec parameters, like the private IP address ranges and DNS servers to use:
conn ikev2-strongswan
. . .
right=%any
rightid=%any
rightauth=eap-mschapv2
rightsourceip=10.10.10.0/24,fec1::/16
rightdns=9.9.9.9,1.1.1.1
rightsendcert=never
right=%any
: The %any
option for the right
side of the connection instructs the server to accept incoming connections from any remote client.
rightid=%any
: This option ensures that the server will not reject connections from clients that provide an identity before the encrypted tunnel is established.
rightauth=eap-mschapv2
: This option configures the authentication method that clients will use to authenticate to the server. eap-mschapv2
is used here for broad compatibility to support clients like Windows, macOS, and Android devices.
rightsourceip=10.10.10.0/24,fec1::/16
: This option instructs the server to assign private IP addresses to clients from the specified pool of IPs.
rightdns=9.9.9.9,1.1.1.1
: These IP addresses are public DNS resolvers. Here is a list of known DNS providers to choose from.
rightsendcert=never
: This option instructs the server that clients do not need to send a certificate to authenticate themselves.
Now we’ll tell strongSwan to ask the client for user credentials when they connect:
conn ikev2-strongswan
. . .
eap_identity=%identity
Finally, the following lines support Linux, Windows, macOS, iOS, and Android clients. These lines specify the various key exchange, hashing, authentication, and encryption algorithms (commonly referred to as Cipher Suites) that strongSwan will allow different clients to use:
conn ikev2-strongswan
. . .
ike=chacha20poly1305-sha512-curve25519-prfsha512,aes256gcm16-sha384-prfsha384-ecp384,aes256-sha1-modp1024,aes128-sha1-modp1024,3des-sha1-modp1024!
esp=chacha20poly1305-sha512,aes256gcm16-ecp384,aes256-sha256,aes256-sha1,3des-sha1!
Each supported cipher suite is delineated from the others by a comma. For example, chacha20poly1305-sha512-curve25519-prfsha512
is one suite, and aes256gcm16-sha384-prfsha384-ecp384
is another. The cipher suites that are listed above are selected to ensure the widest range of compatibility across multiple platforms.
Save and close the file once you’ve verified that you’ve configured each line correctly.
Our IKEv2 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 called ipsec.secrets
:
Let’s open the secrets file for editing:
sudo nano /etc/ipsec.secrets
First, we’ll tell strongSwan where to find our private key:
: RSA "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"
another_username : EAP "another_password"
Save and close the file. Now that we’ve finished working with the server parameters, we’ll restart the strongSwan service so that our updated configuration is applied:
sudo systemctl restart strongswan-starter
Older versions of strongSwan should refer to the system service name of
strongswan
, to restart the strongSwan usesudo systemctl restart strongswan
.
Now that the strongSwan server has been fully configured with both server options and user credentials, it’s time to move on to configuring the most important part: the firewall.
With the strongSwan configuration complete, we need to configure the firewall to forward and allow network traffic through.
First, allow UDP traffic to the standard IPSec ports, 500
& 4500
. I configured this in the server provider’s firewall web interface. And you should config it via iptables
or UFW, choose one that fits your needs.
Using iptables:
We will edit the iptables
with a few low-level policies for routing and forwarding IPSec packets. Before we do, we need to find which network interface on our server is used for internet access.
ip route | grep default
Your public interface should follow the word “dev”, ens3
for example.
When you have your public network interface, add the following configuration block:
sudo iptables -t nat -A POSTROUTING -o ens3 -m policy --pol ipsec --dir out -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
sudo iptables -t mangle -A FORWARD --match policy --pol ipsec --dir in -o ens3 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
Change each instance of ens3
in the above configuration to match the interface name you found with ip route
. The -t nat
lines create rules so that the firewall can correctly route and manipulate traffic between the clients and the internet. The -t mangle
line adjusts the maximum packet segment size to prevent potential issues with certain clients.
To enable IPv6 traffic, also config iptables with
ip6tables
commands, such assudo ip6tables -t nat -A POSTROUTING -o ens3 -m policy --pol ipsec --dir out -j ACCEPT
, et al.
Next, we’ll change some network kernel parameters to allow routing from one interface to another. Open kernel parameters configuration file:
sudo nano /etc/sysctl.conf
We’ll need to configure a few things here:
First, we’ll enable IPv4 packet forwarding so that traffic can move between the strongSwan server and public facing network interfaces.
We’ll disable Path MTU discovery to prevent packet fragmentation problems.
We also won’t accept ICMP redirects nor send ICMP redirects to prevent man-in-the-middle attacks.
Add or uncomment these lines in sysctl.conf
file:
. . .
# Enable forwarding
# Uncomment the following line
net.ipv4.ip_forward = 1
. . .
# Do not accept ICMP redirects (prevent MITM attacks)
# Ensure the following line is set
net.ipv4.conf.all.accept_redirects = 0
# Do not send ICMP redirects (we are not a router)
# Add the following lines
net.ipv4.conf.all.send_redirects = 0
net.ipv4.ip_no_pmtu_disc = 1
If you need IPv6 support, also uncomment:
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.accept_redirects = 0
Save the file and persist the settings with:
sudo sysctl -p
Using UFW:
First add a rule to allow UDP traffic to port 500
& 4500
:
sudo ufw allow 500,4500/udp
Next, we will open up one of UFW’s configuration files to add a few low-level policies for routing and forwarding IPSec packets.
When you have your public network interface (i.e. ens3
), open the /etc/ufw/before.rules
file in your text editor. The rules in this file are added to the firewall before the rest of the usual input and output rules. They are used to configure NAT so that the server can correctly route connections to and from clients and the Internet.
sudo nano /etc/ufw/before.rules
Near the top of the file (before the *filter
line), add the following configuration block. Change each instance of ens3
in the above configuration to match the interface name you found with ip route
.
*nat
-A POSTROUTING -s 10.10.10.0/24 -o ens3 -m policy --pol ipsec --dir out -j ACCEPT
-A POSTROUTING -s 10.10.10.0/24 -o ens3 -j MASQUERADE
COMMIT
*mangle
-A FORWARD --match policy --pol ipsec --dir in -s 10.10.10.0/24 -o ens3 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
COMMIT
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]
. . .
Next, after the *filter
and chain definition lines, add one more block of configuration:
. . .
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]
-A ufw-before-forward --match policy --pol ipsec --dir in --proto esp -s 10.10.10.0/24 -j ACCEPT
-A ufw-before-forward --match policy --pol ipsec --dir out --proto esp -d 10.10.10.0/24 -j ACCEPT
When you’re finished, save and close the file once you’ve verified that you’ve added each line correctly.
Before restarting the firewall, we’ll change some network kernel parameters to allow routing from one interface to another. The file that controls these settings is called /etc/ufw/sysctl.conf
. We’ll need to configure a few things in the file including.
sudo nano /etc/ufw/sysctl.conf
. . .
net/ipv4/ip_forward=1
. . .
net/ipv4/conf/all/accept_redirects=0
net/ipv4/conf/all/send_redirects=0
. . .
net/ipv4/ip_no_pmtu_disc=1
Save and close the file when you’re finished. Now we can enable all of our changes by disabling and re-enabling the firewall, since UFW applies these settings any time that it restrats:
sudo ufw disable
sudo ufw enable
Now that we have everything set up on the server side, it’s time to try it out.
First, copy the CA certificate we created and install it on client device(s) that will connect to the strongSwan server. The easiest way to do this is to copy the contents of the certificate file:
cat /etc/ipsec.d/cacerts/ca-cert.pem
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.pem
. Ensure the file you create has the .pem
extension.
Alternatively, use scp
or rsync
to transfer this file.
Follow these steps to import the certificate:
Double-click the certificate file to import this certificate to Keychain Access (system
or login
are both okay).
Double-click the newly imported certificate (display name as configured CN
name, i.e., strongSwan root CA
as in previous example). This brings up a small properties window where you can specify the trust levels. Set IP Security (IPSec)
to Always Trust
and you’ll be prompted for your password if you close this window. This setting saves automatically after entering the password.
Now that the certificate is important and trusted, configure the network connection with these steps:
Go to System Preferences and choose Network.
Click on the small + button at the lower-left of the list of networks.
In the popup that appears, Set Interface to VPN
, set the VPN Type to IKEv2
, and give the connection a name.
In the Server Address and Remote ID field, enter the server’s domain name or IP address. Leave the Local ID blank.
Click on Authentication Settings, select Username, and enter your username and password you configured. Then click OK.
Finally, click on Connect to connect to the IKEv2 tunnel. You should now be connected to the strongSwan server.
To configure the strongSwan connection on an iOS device, follow these steps:
Send yourself the ca-cert.pem
through email or through iCloud.
Tap on the certificate file, then tap Install and enter your passcode. Once it installs, tap Done.
Go to Settings, General, VPN and tap Add VPN Configuration. This will bring up the VPN connection configuration screen.
Tap on Type and select IKEv2.
In the Description field, enter a short name for the VPN connection. This could be anything you like.
In the Server and Remote ID field, enter the server’s domain name or IP address. The Local ID field can be left blank.
Enter your username and password in the Authentication section, then tap Done.
Select the VPN connection that you just created, tap the switch on the top of the page, and you’ll be connected.
Follow these steps to import the certificate:
Save the CA certificate (ca-cert.pem
file) to your downloads folder.
Download the strongSwan VPN client from the Play Store, or download it from strongSwan’s official website: https://download.strongswan.org/Android/.
Open the strongSwan app. Tap the “more” icon (…) in the upper-right corner and select CA certificates.
Tap the “more” icon (…) in the upper-right corner again. Select Import certificate.
Browse to the CA certificate file in your downloads folder and select it to import it into the app.
Now that the certificate is imported into the strongSwan app, you can configure the VPN connection with these steps:
In the app, tap ADD VPN PROFILE at the top.
Fill out the Server with your strongSwan server’s domain name or public IP address.
Make sure IKEv2 EAP (Username/Password) is selected as the VPN Type.
Fill out the Username and Password with the credentials you defined on the server.
Deselect Select automatically in the CA certificate section and click Select CA certificate.
Tap the IMPORTED tab at the top of the screen and choose the CA you imported.
If you’d like, fill out Profile name (optional) with a more descriptive name.
Configuring Windows using PowerShell
To import the root CA certificate using PowerShell, first open a PowerShell prompt with administrator privileges. To do so, right click the Start menu icon and select Windows PowerShell (Admin)
. You can also open a command prompt as administrator and type powershell
.
Next we’ll import the certificate using the Import-Certificate
PowerShell cmdlet. In the following command, the first -CertStoreLocation
argument will ensure that the certificate is imported into the computer’s Trusted Root Certificate Authorities store so that all programs and users will be able to verify the strongSwan server’s certificate. The -FilePath
argument should point to the location where you copied the certificate. In the following example the path is C:\Users\franklin\Downloads\ca-cert.pem
. Ensure that you edit the command to math the location that you used.
Import-Certificate -CertStoreLocation cert:\LocalMachine\Root\ -FilePath C:\Users\franklin\Downloads\ca-cert.pem
The command will output something like the following:
Output
PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\Root
Thumbprint Subject
---------- -------
DB00813B4087E9367861E8463A60CEA0ADC5F002 CN=strongSwan root CA
Then go to Settings on your PC, select the Network & Internet option on the left pane. After that select the VPN option and then click the Add VPN button.
Choose Windows (built-in) as the provider.
Enter a Connection name of any name of your choice.
Enter the domain name or the IP address in the Server name or address field.
Type set to IKEv2.
Input the User name and Password.
Save and connect…
Special notes for IPv6 routes on Windows 10
Windows always requires something special - you have to set IPv6 routes manually:
First, connect to the server, it’s connected but IPv6 is not working yet. Then search for cmd or powershell - and run it as an administrator. List all network devices and set the default route for that interface:
netsh interface ipv6 show interfaces netsh interface ipv6 add route ::/0 interface="<name of the strongswan connection>"
In this post, you’ve built a strongSwan server that uses the IKEv2 protocol. Now you can be assured that your online activities will remain secure wherever you go!
This is a much easier implementation than OpenConnect(ocserv) that a single click brought me to a secure network environment.
Frank Lin
Linux Notes
2019.11.26
AdGuard Home supports all modern DNS encryption protocols, which enable us to setup a secure DNS server with custom AdBlock filters.
Web Notes
2022.03.01
Notes of Nextcloud installation on Ubuntu server with Nginx web server and PlanetScale cloud database.
Tools
2020.10.20
IBM Cloud CLI allows complete management of the Cloud Functions system. You can use the Cloud Functions CLI plugin-in to manage your code snippets in actions, create triggers, and rules to enable your actions to respond to events, and bundle actions into packages.