The return of the Linux router... (from pfSense to Debian, part 8: IPSec VPN betwen Cisco and Debian)

The return of the Linux router... (from pfSense to Debian, part 8: IPSec VPN betwen Cisco and Debian)

Hi again... yet another IT article on the way.
Today I'm going to summarize on this article all my config snippets and notes that I gathered as I struggled to setup VPN tunnels from CISCO routers against a Debian virtual routers running StrongSwan.

To my taste, CISCO IPsec VPN, when compared with OpenVPN, is way too complex to setup, somehow troublesome or unstable, and definitely not as flexible... but Cisco is Cisco, and the ability to stablish VPN tunnels between Cisco devices and Debian virtual routers became a must.

The example, configuration and snippets I'll share here are the ones that allowed me to 'break through', to get 'something that just works', from where eventually evolve into more complex or specific setups where needed.
So, consider this when facing a real scenario, due to the extreme simplicity of this setup...

So, essentially, what I'm going to show here is how to create an IPSec tunnel, between a local/branch office/home office Cisco router (the labs were done with 1841 and 2801 routers running IOS 12.4) and a virtual Debian router, running at the datacenter, allowing me to interconnect the local LAN with the remote virtual/physical resources, in the most simple way (that I'm aware of): through a pre-shared key.
Sure, there're way better, way more modern, secure (and waaaay expensive) ways to do all this with todays Cisco stuff ... but we do also can switch to Debian and use OpenVPN ;-)

Scenario

For the sake of better understanding the configuration files, let's first put in place some asserts about the situation:

  • We have a virtual network, a Broadcast domain or virtual LAN (not to be confused with a swhitch vLAN although both can be inter-connected), running on our Hypervisor cluster environment, with our virtual Debian router having a virtual interface connected to it, lets say its address is LAN: 10.1.1.0/24, and we got our virtual router having also a WAN interface, receiving traffic to/from public fixed address WAN: 1.2.3.4, rosolved by DNS name debian-router.example.com.
  • We do have two remote branch sites, having each one a Cisco ISR G2 Router.
    Those sites may have a public fixed IP address but, in this case, they don't, since, instead, they handle a DynDNS dynamic IP automatic DNS update (you may be interested on my article about setting up DynDNS on Cisco devices here).
  • One remote site has two separate LANs, let's say LAN1: 192.168.1.0/26 and LAN2: 192.168.1.64/26, and its public IP address is always resolvable through site-one.example.com.
  • The other side has just the typical single LAN, let's say LAN1: 192.168.2.0/24, with its DynDNS name site-two.example.com always resolving its public IP address.

Some points about Strongswan/IPSec setup

OK, let's suppose that, like me, after using GUI based routers such as pfSense to handle IPSec connections, we do not know anything about Strongswan/IPSec setup mechanics... if so, the following advices may certainly help you, if not, you may entirelly omit this section of the article :-) ... here we go:

  • We will need to explicitly define and setup a connection in the configuration file for every pair of networks we want to tunnel traffic.
  • In this case, although there are two remote routers, since I want to inter-connect all the three remote LANs (one remote Cisco router has two LANs), with the local Debain router LAN, this makes three connections to configure.
  • I will setup yet another connection (a bypass connection) to tell the Strongswan IPSec process to don't bother about traffic going from/to the local LAN itself.
    Would the Debian router had two, three, four LANs... then two, three, four... baypass connections had to be put in place in the configuration file.
    So, three connections plus the LAN bypass connection, makes a total of four connections that will make up the main body of this example setup.
  • From the Debian router perspective, regarding Strongswan way of understanding the configuration file, It, the router itself, is the LEFT side of every defined connection.
  • The remote side af a connection, the Cisco router in this scenario, is therefore the RIGHT side on every defined connection.
  • The configuration file /etc/ipsec.conf is the place that contains the configuration of IPSec used here and, along with some general configuration options, is organized as a set of, you may guess, connections!
  • On every connection, the local, public IP, is defined by the right stanza, while the left stanza will define the remote public IP address or (in this example) the full host dns name.
  • On every connection, the inter-connected local networks (each side's LAN) will be defined by rightsubnet (the LAN connected to de Debian reouter) and leftsubnet (the LAN behind the remote Cisco router)
  • On every connection, both left (local) and right (remote) sides do get an identifier, a kind of email-like string format id, defined by the leftid and rightid stanzas, that would be used to check Pre-shared key.
  • Nothing prevents us to re-use ids, so, multiple connections, may have the same configured ids.
  • A file named /etc/ipsec.secrets will contain a set of lines, where every line defines a valid combination of left-side id, right-side id, and the pre-shared key both endpoints know/agree to use for mutual authentication.
  • By reusing ids on the connections, a single pre-shared key may be used for multiple connections.

OK... that's enough I think ... Neverthless, I would add some comments within this example configuration file, but, altoghether, I think that all toghether may make the whole picture clearer... let's see how it looks!

Setting up Debian Router side

First install Strongswan package with apt, so every needed dependency is automatically installed... you guessed it

apt-get install strongswan

 
And now let's go for te configuration.
As pointed earlier, the configuration takes place at /etc/ipsec.conf, most of it consist of connection definitions, that start with the conn word, along with some general settings... here we go:

# ipsec.conf - strongSwan IPsec configuration file

#### basic configuration ####

config setup
	charondebug="cfg 2, dmn 2, ike 2, net 2"	
	uniqueids = yes


#### Connections ####

# Bypass connections do match traffic going to/from local subnets
# We state them as passthrough to kinda ignore them.
# The naming of the connections is entirely up to you.

# Bypass for local LAN
conn bypassLAN
	leftsubnet = 10.1.1.0/24
	rightsubnet = 10.1.1.0/24
	authby = never
	type = passthrough
	auto = route


# Tunnel connections go next.
# Every connection matches traffic from/to remote LAN endpoints
# The first connection has relevant parts separated and commented    

# tunnel with site-one LAN1
conn siteoneLAN1
    fragmentation = yes
    keyexchange = ikev1
    reauth = yes
    forceencaps = no
    mobike = no
    rekey = yes
    installpolicy = yes
    type = tunnel
    dpdaction = restart
    dpddelay = 10s
    dpdtimeout = 60s
    auto = route

    # Local is left, and here's public IP address
    left = 1.2.3.4
    # Remote is right, and here's the dns name resolving public IP
    right = site-one.example.com
    # Tayloring a left id to be used in IPSec PSK in an email-like fashion  
    leftid = siteone@debian-router.example.com

    ikelifetime = 14400s
    lifetime = 3600s
    ike = 3des-sha1-modp1024!
    esp = 3des-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024!

    # Note both sides agree to use PSK for auth
    leftauth = psk
    rightauth = psk
    # Next is the right id as we expect to be sent by Cisco router.
    # Cisco router will assemble the id from hostname plus domain.
    # So, ensure this string matches what Cisco will send.
    rightid = r1.site-one.example.com

    aggressive = no
    # Finally declare traffic to be matched by this connection
    # This is done by declaring both endpoint LAN subnets.
    rightsubnet = 192.168.1.0/26
    leftsubnet = 10.1.1.0/24

# tunnel with site-one LAN2
conn siteoneLAN2
    fragmentation = yes
    keyexchange = ikev1
    reauth = yes
    forceencaps = no
    mobike = no
    rekey = yes
    installpolicy = yes
    type = tunnel
    dpdaction = restart
    dpddelay = 10s
    dpdtimeout = 60s
    auto = route
    left = 1.2.3.4
    right = site-one.example.com 
    leftid = siteone@debian-router.example.com
    ikelifetime = 14400s
    lifetime = 3600s
    ike = 3des-sha1-modp1024!
    esp = 3des-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024!
    leftauth = psk
    rightauth = psk
    rightid = r1.site-one.example.com
    aggressive = no
    rightsubnet = 192.168.1.64/26
    leftsubnet = 10.1.1.0/24

# tunnel with site-two LAN1
conn sitetwoLAN1
    fragmentation = yes
    keyexchange = ikev1
    reauth = yes
    forceencaps = no
    mobike = no
    rekey = yes
    installpolicy = yes
    type = tunnel
    dpdaction = restart
    dpddelay = 10s
    dpdtimeout = 60s
    auto = route
    left = 1.2.3.4
    right = site-two.example.com 
    leftid = sitetwo@debian-router.example.com
    ikelifetime = 14400s
    lifetime = 3600s
    ike = 3des-sha1-modp1024!
    esp = 3des-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024!
    leftauth = psk
    rightauth = psk
    rightid = r1.site-two.example.com
    aggressive = no
    rightsubnet = 192.168.2.0/24
    leftsubnet = 10.1.1.0/24


### End connections add includes

include /var/lib/strongswan/ipsec.conf.inc

 
Ok, that was enough for this very basic setup (but also gives an idea on how this technology can get really tricky to setup when a mix of more demanding specifications are needed in different connections).

Now let's take a look to the /etc/ipsec.secrets file.
It basically depicts a kind of map of id-to-id pre-shared key assignment:

# 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

# PSK id pairs go next
siteone@debian-router.example.com r1.site-one.example.com : PSK "SECRETONE"
sitetwo@debian-router.example.com r1.site-two.example.com : PSK "SECRETTWO"

 
That's it...
Essentially, connections against a single remote router do share the same PSK, by reusing the same leftid, that's why only two lines are enough for three conns.
Cisco router at site-one will have to be configured with 'SECRETONE' as PSK, whilst site-two Cisco router will have to be configured with 'SECRETTWO'.
So let's jump onto Cisco part of the game...

Setting up Cisco Router side

Ok, since, essentially, both configurations on Cisco routers are the same, I'll depict only one, the one for site-one, just because due to the fact that it tunnels two local subnets.

I'll split the configuration in sections, to explain them better, and note that here I will not deal with anything unrelated to the actual IPSec tunneling topic...

So, let's dive into configuration details.

First, just by appearance in Cisco start/run config, I'll mention that we need to have hostname and domain set up on the routers, since they'll be used as peer id during PSK handshake.
So, r1, at site-one, will include the following within its config:

hostname r1
ip domain name site-one.example.com

 
Next comes the bulk of IPSec related configuration.
First we are defining the usage of PSK as policy for isakmp, along with defining a pre-shared key to use when connecting against 1.2.3.4 (our debian-router IP) along with some isakmp settings.
A ciphering suite is defined after this.
And finally, we setup a crypto map, named 'debianRouterVPN', that will be afterwards assigned to the WAN router interface.
Note how we define 1.2.3.4 as peer, we select the created transform set, and we declare which ACL (ACL 111 in the example) will this map use to discriminate which traffic passing through the afected interface will be intercepted and undergo tunneling.

crypto isakmp policy 10
 encr 3des
 authentication pre-share
 group 2
crypto isakmp key SECRETONE address 1.2.3.4 no-xauth
crypto isakmp identity hostname
crypto isakmp aggressive-mode disable
!
!
crypto ipsec transform-set 3DES-SHA esp-3des esp-sha-hmac 
!
crypto map DebianRouterVPN 10 ipsec-isakmp 
 set peer 1.2.3.4 default
 set security-association idle-time 60 default
 set transform-set 3DES-SHA 
 set pfs group2
 match address 111

 
Next step is to assign the crypto map to the interesting interface.
Here I depict as a WAN interface a Dialer0 interface.

interface Dialer0
 crypto map DebianRouterVPN

 
Now, traffic passing through this interface is candidate for tunneling... but just candidate, we must specify which one... this is where an ACL (a numbered 111 ACL in this example) comes into play.
In this ACL 111 we will ensure that just the traffic going to/from local LANs 192.168.1.0/26 192.168.1.64/26 and remote LAN 10.1.1.0/24 will match.
By doing so, this traffic will be selected and undergo tunneling.

access-list 111 permit ip 192.168.1.0 0.0.0.63 10.1.1.0 0.0.0.255
access-list 111 permit ip 10.1.1.0 0.0.0.255 192.168.1.0 0.0.0.63
access-list 111 permit ip 192.168.1.64 0.0.0.63 10.1.1.0 0.0.0.255
access-list 111 permit ip 10.1.1.0 0.0.0.255 192.168.1.64 0.0.0.63

 
Now, at this point, although the configuration, from the IPSec perspective, is complete, in a typical scenario where the router is our gateway towards the internet for the local LANs, we would find this setup is still no working.... why? ... because of NAT.

Since this router is acting as the branch gateway, any traffic forwarded from the LANs to the Internet through the WAN interface has its source IP address changed by the router's WAN interface IP address, and this happens BEFORE ACL 111 is applied... so, it never matches!
To avoid this we have to tune the ACL that rules NAT/overload to never match (and thus trigger natting) the traffic we intend to tunnel.
So, if our r1 router at site-one has this very typical NAT rule:

ip nat inside source list 101 interface Dialer0 overload  

 
Then, in the NAT ACL (numbered ACL 101 in this example), we will explicty deny our target traffic:

access-list 101 deny ip 192.168.1.0 0.0.0.63 10.1.1.0 0.0.0.255
access-list 101 deny ip 192.168.1.64 0.0.0.63 10.1.1.0 0.0.0.255
access-list 101 permit ip any any

 
Note that, comparing NAT ACL 101 with crypto ACL 111, since NAT happens as traffic goes LAN to WAN (ip nat inside / ip nat outside), only the traffic from local LANs towards remote LANs has to be rejected, while on the crypto ACL 111, both to/from traffic had to be specified for tunneling in/out.

And that's it for the day... I found tricky to combine all this with Cisco DynDNS implementation and Zone Based Firewall... but once get it correctly set up, it works consistently and is a quite good starting point.
Hope someone finds this useful!