Libreswan IPsec VPN

For a Site-to-site VPN tunnel from a cloud service (for example, Azure) to the local on-premise network, a Libreswan Virtual private network (VPN) router with Internet Protocol Security (IPsec) can be used.

Libreswan is a free software implementation of the most widely supported and standardized VPN protocol using IPsec and the Internet Key Exchange (IKE).

In Red Hat Enterprise Linux 8 (RHEL 8), a virtual private network (VPN) can be configured using the IPsec protocol, which is supported by the Libreswan application. Some information pages about VPN setups:

Libreswan installation on EL8

The RHEL 8 (as well as EL8_clones such as AlmaLinux and RockyLinux) offer an RPM package for Libreswan version 4.4.

Install the Libreswan package by:

dnf install libreswan

There are some Libreswan examples:

Network firewall setup

If your organization has a firewall device protecting your external (Internet faced) network perimeter, it is necessary to configure that firewall to allow 500 and 4500/UDP ports for the IKE (defined in RFC7296), ESP (defined in RFC4303), and AH (not used) protocols bidirectionally to and from the remote cloud service:

IP UDP Port 500
IP UDP Port 4500
ESP protocol 50

In addition, the Linux firewalld must be configured, see Firewalld setup below.

Libreswan tunnel connection

The following configuration examples have been shown to work (in May 2022) with the Azure cloud and a local VPN gateway running Red Hat RHEL 8.6 (or the EL8 clones of RHEL 8).

Configuration files are created in the /etc/ipsec.d/ directory and should be named for each VPN tunnel (here azure.conf and azure.secrets).

First create the file /etc/ipsec.d/azure.conf:

conn azure
  authby=secret
  auto=start
  dpdaction=restart
  dpddelay=30
  dpdtimeout=120
  ike=aes256-sha1;modp1024
  ikelifetime=3600s
  pfs=yes
  esp=aes128-sha1
  salifetime=3600s

Some parameters will then take their default values which you should not modify, see man ipsec.conf. Important defaults are:

  • ikev2=insist Please note a RHEL 8 modification of the upstream Libreswan where RHEL 8 uses ikev2=<insist|no> in stead of <yes|no>, see man ipsec.conf.

  • type=tunnel

  • encapsulation=auto (forceencaps is obsoleted)

Second, determine the public IP-address of your local VPN gateway as well as the public IP of the Azure VPN gateway. We use these example-only addresses:

  • Local VPN gateway public address: 123.45.67.89

  • Azure VPN gateway public address: 20.21.22.23

Add your specific IP-addresses and subnets after the conn parameter in the above file /etc/ipsec.d/azure.conf (the values here are just examples!):

conn azure
  left=123.45.67.89        # Local VPN gateway public address
  leftsubnet=10.2.0.0/16   # Local subnet
  leftsourceip=10.2.0.1    # Local VPN gateway on the local private subnet
  right=20.21.22.23        # Azure VPN gateway public address
  rightsubnet=10.0.0.0/16  # Azure subnet
  ....

The leftsourceip is relevant only locally, and the other end need not agree. This option is used to make the gateway itself use its internal IP, which is part of the leftsubnet, to communicate to the rightsubnet or right.

Third, generate a really random secret Pre-Shared Key (PSK) string, see the ipsec.secrets manual page.

You may use the output from one of these Linux commands (see Generate a strong pre-shared key):

openssl rand -base64 24
head -c 24 /dev/urandom | base64

The PSK value used must of course also be identically configured in the Azure VPN gateway Shared key value, see the VPN Gateway FAQ.

Now create the file /etc/ipsec.d/azure.secrets (the values here are just examples!):

123.45.67.89 20.21.22.23 : PSK "mEEVg4KXSl5nFJk3yDZbSj7wTNN5wxFt"

The PSK value should be enclosed in quotes () as shown.

The value %any signifies an IP-address to be filled in (by automatic keying) during negotiation, see the ipsec.secrets manual page:

%any %any : PSK "mEEVg4KXSl5nFJk3yDZbSj7wTNN5wxFt"

Make sure the file is only readable by root:

chmod 0600 /etc/ipsec.d/azure.secrets

Now you may enable, start and check the ipsec service:

systemctl enable ipsec --now
systemctl status ipsec

Verify and view the IPsec connections status by:

ipsec verify
ipsec status

If there are errors from the status command you should examine the /var/log/secure logfile. You can also try this command:

ipsec pluto --config /etc/ipsec.conf --nofork

If the encryption methods are mismatched, look for lines like this one:

no local proposal matches remote proposals
1:IKE:ENCR=AES_CBC_256;INTEG=HMAC_SHA1_96;PRF=HMAC_SHA1;DH=MODP1024
2:IKE:ENCR=AES_CBC_256;INTEG=HMAC_SHA2_256_128;PRF=HMAC_SHA2_256;DH=MODP1024
3:IKE:ENCR=AES_CBC_128;INTEG=HMAC_SHA1_96;PRF=HMAC_SHA1;DH=MODP1024
4:IKE:ENCR=AES_CBC_128;INTEG=HMAC_SHA2_256_128;PRF=HMAC_SHA2_256;DH=MODP1024
5:IKE:ENCR=3DES;INTEG=HMAC_SHA1_96;PRF=HMAC_SHA1;DH=MODP1024
6:IKE:ENCR=3DES;INTEG=HMAC_SHA2_256_128;PRF=HMAC_SHA2_256;DH=MODP1024

In this case replace the above ike= line by one of the options, for example:

ike=AES_CBC_256;MODP1024

and restart the ipsec service.

Firewalld setup

The IPsec VPN gateway server must have its internal firewall configured.

Configure firewalld to permit routing of VPN tunnel IPsec traffic:

firewall-cmd --add-service="ipsec"

Add the local IP subnet (10.2.0.0/16 in the present example) to firewalld_trusted_zone:

firewall-cmd --zone=trusted --add-source=10.2.0.0/16

Make these changes permanent:

firewall-cmd --runtime-to-permanent

List the contents of the firewalld_trusted_zone:

firewall-cmd --zone=trusted --list-all

Configure IPsec gateway to route VPN traffic

When the IPsec VPN router is working correctly, the next step is to configure IP packet forwarding. Append this line to /etc/sysctl.conf:

net.ipv4.ip_forward=1

Disable IPv6:

net.ipv6.conf.default.disable_ipv6=1

The Reverse Path Forwarding filtering subsystem related to IP spoofing protection must be turned off on both gateways for IPSEC to work properly, see:

  • https://access.redhat.com/solutions/53031:

    The most simple way to disable the strict check is to set the sysctl net.ipv4.conf.all.rp_filter=2 (loose) as this will override the interface-specific settings.
    Setting net.ipv4.conf.all.rp_filter=0 (disabled) does not override interface-specific settings so is not recommended.
    

    (See also this LibreSwan FAQ)

Add this in /etc/sysctl.conf:

net.ipv4.conf.all.rp_filter=2

Now reload sysctl:

sysctl -p

Route IP traffic via the VPN tunnel

For those hosts on the on-premise network that need to send IP traffic to the cloud nodes through the VPN tunnel gateway, you have to add a route command, for example:

ip route add 10.0.0.0/16 via 10.2.0.1

where 10.2.0.1 is the VPN gateway’s local IP address and 10.0.0.0/16 is the IP subnet in the cloud service. This configuration will disappear when the host is rebooted.

To make manual routes persistent across reboots on EL8 hosts, you could add the above command to the /etc/rc.local script. Remember to make it executable:

chmod +x /etc/rc.local

Another method is to determine the interface which the host uses to send traffic to the gateway (10.2.0.1 in the above example). Assume the interface name is eno49.

Configure the routing file for the /etc/sysconfig/network-scripts/route-eno49 interface:

ADDRESS0=10.0.0.0
NETMASK0=255.255.0.0
GATEWAY0=10.2.0.1

Then update the NetworkManager:

nmcli device reapply eno49

and check the routes with:

netstat -r

Perhaps it may be necessary to reboot the server.

See:

ipsec commands

Optional information about some IPsec commands:

Libreswan provides the ipsec_command, see:

ipsec --help

Libreswan uses a local database to keep track of authentication keys and identity certificates, so initialize the key database on each computer:

ipsec initnss

Check the current CKAID keys:

ipsec showhostkey --list

If no keys exist, generate a CKAID key for each machine (see man ipsec_showhostkey):

ipsec newhostkey
ipsec showhostkey --list