In my backup solution for my NAS I use a Raspberry Pi configured to use vpnc to securely connect back to my home through an IPSec tunnel to a Cisco ASA firewall. (read more – https://bourskov.dk/2015/03/raspberry-pi-as-a-nas-backup-appliance/). This works quite well, but since it is a remote access VPN client the Pi will be “offline” as seen from my home network, since the script will bring up the tunnel when the backup is running and take it down afterwards. I have used this for ~8 months now and it does the job, but I would really love to have access to my off-site backup device without having to either drive to the location or have to use TeamViewer etc. to a local computer at the site. So I decided to setup the Backup Pi for Site-to-Site VPN instead of Remote Access VPN.
Site-to-Site IPsec VPNs are fairly easy to setup, but since the Backup Pi should be a “zero-touch” setup, it should be able to run of a DHCP provided address without any change to the configuration in either end of the tunnel. Since the public IP address for the backup location is subject to changes, normal static tunnel configurations cannot be used. The use of pre shared keys as authentication on dynamic VPN tunnels is very insecure and should not be used at all. Therefore authentication will use X.509 digital certificates in both ends.
There are different possibilities for bulding IPSec tunnels in Linux, and I chose strongSwan (https://www.strongswan.org/) for two reasons – It is available as a package in Raspbian and because I have some experience with strongSwan from pfSense which uses it behind the scenes.
What is used?
- Cisco ASA 5505 running software version 9.2(1)
- Raspberry Pi model B running Raspbian Jessie Lite, Release date 2015-11-21, Kernel version 4.1
- Ubuntu Server with OpenSSL Certification Authority
sudo apt-get update
sudo apt-get install -t jessie strongswan
sudo apt-get install -t jessie libcharon-extra-plugins
Configuration added to /etc/ipsec.conf
# Default settings for all profiles where not specifically set conn %default ikelifetime=1440m keylife=480m rekeymargin=3m keyingtries=%forever keyexchange=ikev1 authby=secret conn BKG-FW left=%any leftsubnet=192.168.201.1/32 leftid=fqdn:bckpi01.urskov.eu right=vpn.mysite.eu rightsubnet=172.18.0.0/16 rightid=&amp;amp;quot;C=DK, ST=Syddanmark, L=Kolding, O=Urskov, CN=BKG-FW01&amp;amp;quot; auto=start leftauth=pubkey rightauth=pubkey leftcert=/etc/ipsec.d/certs/bckpi01.urskov.eu.cert.pem ike=aes256-sha-modp1024! esp=aes256-sha1! keyexchange=ikev1
I will not go through all parameters in details, since full official documentation for ipsec.conf can be found here: https://wiki.strongswan.org/projects/strongswan/wiki/IpsecConf
Left is the “local” endpoint of the tunnel, which means the endpoint where the ipsec.conf is located. Right is the far end of the tunnel, the remote party.
left – strongSwan outside address – is set to %any since this end will receive a dynamic IP address from DHCP.
leftsubnet – protected network behind strongSwan – set to a virtual host/loopback address – 192.168.201.1/32
leftid – IKEID sent by this endpoint
right – Remote endpoint outside address – could be IP or FQDN
rightsubnet – protected network behind remote endpoint
rightid – IKEID from remote endpoint – This is the remote endpoints certificate – “C=DK, ST=Syddanmark, L=Kolding, O=Urskov, CN=BKG-FW01”
auto=start – open tunnel when ipsec is started – i.e. at boot time
left|rightauth – how endpoints will authenticate – pubkey = certificates
leftcert – path to certificate to use for this connection
ike – Phase 1 (IKE) parameters – AES256 – SHA – D-H group2 (a ! means only use these parameters)
esp – Phase 2 (IPsec) parameters – AES256 – SHA – (a ! means only use these parameters)
keyexchange – key exchange protocol – IKEv1 or IKEv2
left|rightsubnet defines the traffic, that will be encrypted and sent through the tunnel. Since the Pi only has a single NIC, and I only need to access the Pi itself, a virtual IP address is added, and used as the leftsubnet (Pi side).
In /etc/network/interfaces a virtual interface can be added
auto eth0:1 iface eth0:1 inet static address 192.168.201.1 netmask 255.255.255.255
By default, IPv4 forwarding is not enabled, so this has to be changed in order for strongSwan to work. This is done in the file /etc/sysctl.conf – this will make the change permanent, but requires a reboot.
Add or uncomment following line
# Uncomment the next line to enable packet forwarding for IPv4 net.ipv4.ip_forward=1
To make the kernel forward packets immediately, run this command
sysctl -w net.ipv4.ip_forward=1
For authentication a certificate is needed. This can be bought or a personal certification authority can be used to issue the certificates. I have used a private CA running on Ubuntu Server (see https://jamielinux.com/docs/openssl-certificate-authority/ for inspiration if you want to setup your own CA.)
In order to use a certificate to authenticate IPSec tunnels, at least on an ASA, an IPSECTUNNEL OID have to be in the extended key usage of the certificate. The OID is: 18.104.22.168.22.214.171.124.6
In OpenSSL just add the OID to the extendedKeyUsage field of the profile used to sign the certificate.
Ideally, you should generate private keys and the certificate request on the device needing the certificate. This is more secure, since the private key never leaves the device. I have created my keys and request on the CA server because it easy – yes, I’m lazy… 😉
Generate private key with 2048 bits
openssl genrsa -aes256 -out intermediate/private/bckpi01.urskov.eu 2048
Generate Certificate request using the previously created private key
openssl req -config intermediate/openssl.cnf -key intermediate/private/bckpi01.urskov.eu -new -sha256 -out intermediate/csr/bckpi01.urskov.eu
Sign certificate, and set validity, usage etc.
openssl ca -config intermediate/openssl.cnf -extensions ipsec_cert -days 740 -notext -md sha256 -in intermediate/csr/bckpi01.urskov.eu -out intermediate/certs/bckpi01.urskov.eu.cert.pem
Now the certificate is ready to use, and the private key and signed certificate should be copied to /etc/ipsec.d/private and /etc/ipsec.d/certs respectively.
To make strongSwan able to use the certificate for authentication, the /etc/ipsec.secrets file needs to be updated with a reference to where the private key is stored. If you used a password to protect the private key, which I would recommend, you also needs to specify this password in order for strongSwan to decrypt the key.
# This file holds shared secrets or RSA private keys for authentication. # RSA private key for this host, authenticating it to any other host # which knows the public part. # this file is managed with debconf and will contain the automatically created private key include /var/lib/strongswan/ipsec.secrets.inc : RSA bckpi01.urskov.eu.key.pem &amp;amp;quot;verySecretPassWord&amp;amp;quot;
In etc/ipsec.conf a reference to the signed certificate is needed so strongSwan knows which certificate to use. The keyword leftcert is where the certificate path should be placed.
The Cisco ASA will also need a certificate to use for authentication, and can be issued the same way. My ASA already had a certificate from my CA, so this will not be covered here.
But installing a device certificate is not all that needs to be done, since everybody can create their own CAs and sign their own certificates, a trusted root and/or intermediate CA certificate is needed as well. These certificates, is a part of the certificate chain and provides a way for endpoints to verify if the certificate is actually trustworthy or not.
The root and intermediate CA certificates we trust, should be copied to /etc/ipsec.d/cacerts. Likewise on the Cisco ASA we need to install the certificates, a so called trustpoint in the ASA (not covered here).
The ASA needs to be configured to accept connection from the Pi.
First a certificate for the ASA needs to be imported as well as any root and intemediate certificates
Create a trustpoint for the root and intermediate (if any).
crypto ca trustpoint MY-CA enrollment terminal crl optional exit ! ! crypto ca authenticate MY-CA Enter the base 64 encoded CA certificate. End with the word "quit" on a line by itself: -----BEGIN CERTIFICATE----- MIIGQDCCBCigAwIBAgIJAPo/pjQes4oLMA0GCSqGSIb3DQEBCwUAMIGsMQswCQYD VQQGEwJESzETMBEGA1UE ....... -----END CERTIFICATE----- quit
Next create a trustpoint for the device certificate for use with VPN. For ease I’ve used a PKCS12 file containing both the private key and the signed ceritificate
crypto ca import DEV-CERT pkcs12 &quot;passphrase&quot; Enter the base 64 encoded pkcs12. End with the word "quit" on a line by itself: -----BEGIN PKCS12----- MIIMxwIBAzCCDIEGCSqGSIb3DQEHAaCCDHIEggxuMIIMajCCDGYGCSqGSIb3DQEH BqCCDFcwggxTAgEAMII .... -----END PKCS12----- quit
Now, setup IKEv1 parameters to match the parameters configured in StrongSWAN. Note that multiple policies can be configured on the ASA. The policy number is used as preference for first match.
crypto ikev1 policy 20 authentication rsa-sig encryption aes-256 hash sha group 2 lifetime 86400
Configure IPsec transform set
crypto ipsec ikev1 transform-set ESP-AES-256-SHA esp-aes-256 esp-sha-hmac
Create an access-list for interesting traffic for the tunnel.
access-list VPN-BACKUP-PI remark SITE-TO-SITE VPN BACKUP PI access-list VPN-BACKUP-PI extended permit ip 172.18.0.0 255.255.0.0 192.168.201.1 255.255.255.255
Create a group policy for the tunnel
group-policy GRP-BCKPI-VPN internal group-policy GRP-BCKPI-VPN attributes vpn-tunnel-protocol ikev1
Next, configure a tunnel-group for the VPN tunnel and map it with a certificate map for a specific CN.
tunnel-group DYN-BCKPI-VPN type ipsec-l2l tunnel-group DYN-BCKPI-VPN general-attributes default-group-policy GRP-BCKPI-VPN tunnel-group DYN-BCKPI-VPN ipsec-attributes peer-id-validate nocheck ikev1 trust-point VPN-CERT ! crypto ca certificate map DefaultCertificateMap 10 subject-name attr cn eq bckpi01 tunnel-group-map DefaultCertificateMap 10 DYN-BCKPI-VPN
Wrap it all up in a crypto map and enable the map on an interface
crypto dynamic-map DYN-BCKPI-MAP 5 match address VPN-BACKUP-PI crypto dynamic-map DYN-BCKPI-MAP 5 set ikev1 transform-set ESP-AES-256-SHA crypto map outside_map 65533 ipsec-isakmp dynamic DYN-BCKPI-MAP crypto map outside_map interface outside
That about it…
Verify status of strongSwan by typing: ipsec statusall
The Pi can now be accessed on the virtual address of 192.168.201.1 from inside mt home LAN
Job done… 🙂
UPDATE: I have experienced some problems with the tunnel going down for various reasons, so I created a small script to check the status of the tunnel and reconnect if it should be down.
#!/bin/bash # Check if IPSEC service is running ipsec status if [ $? != 0 ] ; then echo &quot;IPSEC service NOT running! Starting...&quot;; logger -t IPSEC-CHECK Service NOT running! Starting... ipsec start # Wait to allow tunnel to go up... sleep 2 else echo &quot;IPSEC service is running...&quot;; logger -t IPSEC-CHECK Service is running... fi TUNNELSTATUS=&quot;$(ipsec status BKG-FW | grep 'ESTABLISHED')&quot; if [ -z &quot;;$TUNNELSTATUS&quot;; ] ; then echo &quot;;Tunnel NOT up! Bringing up...&quot;; logger -t IPSEC-CHECK Tunnel NOT up! Bringing up... ipsec up BKG-FW else echo &quot;Tunnel is established, no more to do...&quot;; logger -t IPSEC-CHECK Tunnel is established... fi
The script is scheduled to run every hour using crontab
# m h dom mon dow user command 10 * * * * root /home/pi/ipsec-check.sh #