Background
IPsec is a handy tool for encryption connections on networks, but it can be a bit complicated to configure, especially when you’re dealing with multiple vendors. On Linux, the protocol that encrypts connections is built-in to the kernel, it’s called Encapsulating Security Payload. However there are many security parameters that need to be configured, so a tool is usually needed to handle the task of figuring that out. That’s where the IKE protocol comes in to handle negotiation of cryptographic keys and parameters between the two IPsec tunnel endpoints.
There are several projects that implement the IKE protocol on Linux, my personal favorite is Strongswan, due to its active development on Github and comprehensive implementation of IPsec’s features. You can check out the Strongswan website and their Github page for more information and open source code.
A “standard” IPsec tunnel usually has the two LAN subnets that the tunnel will be connecting configured into the tunnel “policy”, and is negotiated when bringing up the tunnel. Changing those subnets requires bringing down the tunnel and manually re-configuring it by hand. A solution to this is a “route-based” tunnel. instead of a policy, a logical or “virtual” interface (a network interface with no physical counterpart) exists with an IP address on it. Once the tunnel interface is up and encryption is working, you can treat it like any other interface and apply policies, shaping, routing protocols, etc. It’s like an Ethernet cable made out of math. There are two kinds (that I know of) of route-based tunneling, GRE and VTI. Today I’m going to configure GRE.
Ubuntu 18.04 Server
Ubuntu Linux 18.04 makes installation of Strongswan nice and easy with its package manager:
apt-get install strongswan
This can be out of date, though. If you want a really new version of Strongswan, you can try compiling from source using Github. Ubuntu 18.04 repositories have Strongswan 5.6.2, which is pretty feature-complete.
Topology
We’re trying to get Host1 (Ubuntu 18.04 Server) to be able to reach Host2 (Ubuntu 18.04 Server). You can think of the top of the topology as an Internet-like network, where the private networks that Host1 and Host2 are attached to cannot directly reach other, and wouldn’t want to even if they could since the Internet is not such a friendly place. Encryption and authentication are needed, which the IPsec tunnel provides.
Inside the tunnel there is a another set of IP-headers encapsulating packets, which is the essence of a tunnel in networking. There are virtual interfaces on either side, in this case I’ve randomly chosen 100.0.0.1/30 for the Ubuntu side and 100.0.0.2/30 for the Cisco side. The Ubuntu box has a tunnel interface name “james_gre”, while the Cisco box has an interface name of “tunnel0”.
Router1 (Ubuntu18.04)
The first order of business is to create a GRE virtual interface. It’s pretty straightforward on Ubuntu 18.04:
#Add the interface ip tunnel add james_gre local 10.10.10.1 remote 30.30.30.2 mode gre #Activate it ip link set james_gre up #Add an IP address ip addr add 100.0.0.1/30 dev james_gre #Set the MTU, to account for GRE/ESP protocol overhead ip link set dev james_gre mtu 1440
Second, we configure Strongswan. First edit the text file /etc/ipsec.conf in you favorite text editor, I use Vim. It should look something like this:
config setup strictctlpolicy=yes uniqueids=no conn james_tunnel left=10.10.10.1 #Outside interface of this router leftprotoport=47 #IP protocol 47 for GRE right=30.30.30.2 #Outside interface of the cisco router rightprotoport=47 #IP protocol 47 for GRE ike=aes256-sha2_256-modp1024! #Corresponds to cisco ikev2 proposal esp=aes-sha2_256! #Corresponds to cisco transform set keyingtries=0 ikelifetime=1h lifetime=8h authby=secret auto=start keyexchange=ikev2 type=transport #Corresponds to cisco transform set "mode"
I use transport mode for less overhead, although you can use tunnel mode if you want. Just make sure all parameters on both sides match. Notice there is no policy to specify subnets to traverse the tunnel, the routing table determines that. Hence, route-based tunnel.
Then edit the /etc/ipsec.secrets text file, it should look like this:
10.10.10.1 30.30.30.2 : PSK '12345'
Finally, restart strongswan to load your configuration.
ipsec restart
Router4 (Cisco IOSv, 15.4)
The Cisco IOS configuration is much like a policy-based tunnel except in place of a crypto-map there is an “ipsec profile”. This profile is attached to the GRE tunnel interface. Make sure to specify “mode transport” in your transform set. Your configuration will look like this, I’ve edited for brevity:
crypto ikev2 proposal james-proposal encryption aes-cbc-256 integrity sha256 group 2 ! crypto ikev2 policy james-policy proposal james-proposal ! crypto ikev2 keyring james-ring peer remote-router-james address 10.10.10.1 pre-shared-key 12345 ! ! crypto ikev2 profile james-profile match identity remote address 10.10.10.1 255.255.255.255 authentication remote pre-share authentication local pre-share keyring local james-ring ! crypto ipsec transform-set james-trans esp-aes esp-sha256-hmac mode transport ! crypto ipsec profile james-protect-gre set transform-set james-trans set ikev2-profile james-profile ! interface Tunnel0 ip address 100.0.0.2 255.255.255.252 ip mtu 1440 tunnel source 30.30.30.2 tunnel destination 10.10.10.1 tunnel protection ipsec profile james-protect-gre ! interface Ethernet0/0 ip address 30.30.30.2 255.255.255.252 ! interface Ethernet0/1 ip address 172.16.0.1 255.255.255.0
Verification
Router1 (Ubuntu18.04)
You can check to see the status of a particular tunnel with:
root@uvm1804:ipsec status james_tunnel #Produces the following output: Security Associations (1 up, 0 connecting): james_tunnel[9]: ESTABLISHED 42 minutes ago, 10.10.10.1[10.10.10.1]...30.30.30.2[30.30.30.2] james_tunnel{9}: INSTALLED, TRANSPORT, reqid 6, ESP SPIs: c4f61431_i b854a518_o james_tunnel{9}: 10.10.10.1/32[gre] === 30.30.30.2/32[gre]
The above output shows an established tunnel. Also try pinging across the tunnel, that’s always a surefire way to tell if things are working well.
Router4 (Cisco IOSv, 15.4)
On a Cisco IOS device, you can always use this command to show tunnel status:
Router4#show crypto session Crypto session current status Interface: Tunnel0 Profile: james-profile Session status: UP-ACTIVE Peer: 10.10.10.1 port 4500 Session ID: 13 IKEv2 SA: local 30.30.30.2/4500 remote 10.10.10.1/4500 Active IPSEC FLOW: permit 47 host 30.30.30.2 host 10.10.10.1 Active SAs: 2, origin: crypto map Router4#
Don’t forget you’ll also need to install routes, either statically or with a protocol, to get traffic other than pings across. Did I mention this is a route-based VPN?
Troubleshooting
Router1 (Ubuntu18.04)
My favorite command to troubleshoot Strongswan is this one:
cat /var/log/syslog | grep charon
Which produces the logs of Charon, the Strongswan IKE daemon. If there’s something wrong, you’ll probably notice it in here. The system log file is different on different Linux distributions, check yours to be sure which one.
Router4 (Cisco IOSv, 15.4)
In addition to “show crypto session”, you can run debugs for IPsec and ISAKMP on a Cisco IOS device:
Router4#debug crypto ipsec Crypto IPSEC debugging is on Router4#debug crypto isakmp Crypto ISAKMP debugging is on Router4# *Feb 1 06:51:20.425: IPSEC(key_engine): got a queue event with 1 KMI message(s) *Feb 1 06:51:20.425: IDB is NULL : in crypto_ipsec_key_engine_delete_sas (), 5101 *Feb 1 06:51:20.425: IPSEC(key_engine_delete_sas): rec'd delete notify from ISAKMP *Feb 1 06:51:20.425: IPSEC:(SESSION ID = 13) still in use sa: 0xF5222CE4 *Feb 1 06:51:20.425: IPSEC:(SESSION ID = 13) (key_engine_delete_sas) delete SA with spi 0xD0337743 proto 50 for 30.30.30.2 *Feb 1 06:51:20.425: IPSEC:(SESSION ID = 13) (delete_sa) deleting SA, (sa) sa_dest= 30.30.30.2, sa_proto= 50, sa_spi= 0xD0337743(3493033795), sa_trans= esp-aes esp-sha256-hmac , sa_conn_id= 14 sa_lifetime(k/sec)= (4608000/3600), (identity) local= 30.30.30.2:0, remote= 10.10.10.1:0, local_proxy= 30.30.30.2/255.255.255.255/47/0, remote_proxy= 10.10.10.1/255.255.255.255/47/0 *Feb 1 06:51:20.425: IPSEC:(SESSION ID = 13) (delete_sa) deleting SA,
Be ready for some pretty funky output, and a lot of it. Generally you should be able to find some clues in the debug, though.
You’ll also want to do a packet capture, if possible. You’ll be looking for ISAKMP (a subset of IKE) messages attempting to establish the tunnel first:
Then when the tunnel is established, you’ll only see ESP packets where data should be. If you’re seeing unencrypted, something is definitely wrong:
Hit me up if you have a question or a tunnel you’re troubleshooting. I’m happy to help.