How to Build an IPSec VPN With Cisco ASAs & Overlapping Address Space

There are times your company will partner with another to provide a resource to them. Often, this interaction is secured with a LAN-to-LAN (L2L) VPN tunnel. Most Cisco documentation about L2L VPNs are written for VPNs within the same organization, as opposed to different companies trying to peer with each other. L2L VPN tunnels within the same organization are relatively simple, for the following reasons:

  • That company controls their own IP addressing and can avoid overlapping address space.
  • Most L2L VPNs are usually wide open, allowing all IP communication through.

With an L2L VPN tunnel between different organizations, these issues become a greater concern because of overlapping IP space and the need for greater network security.

We will demonstrate how both can be dealt with, but first let us setup the IPSec configuration that is common to L2L tunnels. This lab has been built in GNS3 using ASAs with 8.4 code and MicroCore  Linux hosts.

rsz_blog1

Configs

Note: Some of the VPN config is not all in here yet; we will work on it in the next section.

Local ASA config -

!
interface GigabitEthernet0
 nameif outside
 security-level 0
 ip address 1.1.1.2 255.255.255.0
!
interface GigabitEthernet1
 nameif inside
 security-level 100
 ip address 10.0.0.1 255.255.255.0
!
object network inside
 subnet 10.0.0.0 255.255.255.0
! 
!--- PAT for all other inside hosts
nat (inside,outside) 10 source dynamic inside interface
route outside 0.0.0.0 0.0.0.0 1.1.1.1 1
!
crypto ipsec ikev1 transform-set aesset esp-aes esp-sha-hmac
crypto ipsec security-association lifetime seconds 86400
!
crypto map outside-map 1 set pfs group5
crypto map outside-map 1 set peer 2.2.2.2
crypto map outside-map 1 set ikev1 transform-set aesset
crypto map outside-map 1 set security-association lifetime seconds
 86400
!
crypto map outside-map interface outside
! 
crypto ikev1 policy 1
 authentication pre-share
 encryption aes
 hash sha
 group 5
 lifetime 86400
!
group-policy vpn-grp-policy internal
group-policy vpn-grp-policy attributes
 vpn-tunnel-protocol ikev1
!
tunnel-group 2.2.2.2 type ipsec-L2L
tunnel-group 2.2.2.2 general-attributes
 default-group-policy vpn-grp-policy
tunnel-group 2.2.2.2 ipsec-attributes
 ikev1 pre-shared-key cisco123
 peer-id-validate nocheck

 

 Remote ASA config-

!
interface GigabitEthernet0
 nameif outside
 security-level 0
 ip address 2.2.2.2 255.255.255.0
!
interface GigabitEthernet1
 nameif inside
 security-level 100
 ip address 192.168.0.1 255.255.255.0
!
route outside 0.0.0.0 0.0.0.0 2.2.2.1 1 
!
crypto ipsec ikev1 transform-set aesset esp-aes esp-sha-hmac
crypto ipsec security-association lifetime seconds 86400
!
crypto map outside-map 1 set pfs group5
crypto map outside-map 1 set peer 1.1.1.2
crypto map outside-map 1 set ikev1 transform-set aesset
crypto map outside-map 1 set security-association lifetime seconds
 86400
!
crypto map outside-map interface outside
! 
crypto ikev1 policy 1
 authentication pre-share
 encryption aes
 hash sha
 group 5
 lifetime 86400
!
group-policy vpn-grp-policy internal
group-policy vpn-grp-policy attributes
 vpn-tunnel-protocol ikev1
!
tunnel-group 1.1.1.2 type ipsec-L2L
tunnel-group 1.1.1.2 general-attributes
 default-group-policy vpn-grp-policy
tunnel-group 1.1.1.2 ipsec-attributes
 ikev1 pre-shared-key cisco123
 peer-id-validate nocheck

 

Router config -

!
interface FastEthernet0/0
 ip address 1.1.1.1 255.255.255.0
 speed 100
 full-duplex
!
interface FastEthernet0/1
 ip address 2.2.2.1 255.255.255.0
 speed 100
 full-duplex

Local host config-

hostname local_host
ifconfig eth0 10.0.0.10 netmask 255.255.255.0
route add default gw 10.0.0.1

 

Remote host config-

hostname remote_host
ifconfig eth0 192.168.0.10 netmask 255.255.255.0
route add default gw 192.168.0.1

 

Overlapping IP Space

The easiest way to deal with the possibility of overlapping IP space is to NAT to a public IP (or at least an IP agreed upon by both parties). With Cisco L2L VPNs, the crypto ACL is processed after NAT. This is why you must use a NAT exemption rule for L2L VPN when not NATing on either end. This means that the crypto ACLs must have the NATed IPs, rather than the private IP addresses.

 Local ASA config-

!
!--- Objects for the resource
object network local_host
 host 10.0.0.10
object network local_host_nat
 host 1.1.1.10
!
!--- NAT for the resource
nat (inside,outside) source static local_host local_host_nat
!
!--- ACL with NATed IP
access-list crypto-acl extended permit ip host 1.1.1.10 host 2.2.2.10
!
!---- Apply the ACL to the crypto map
crypto map outside-map 1 match address crypto-acl
!
!--- Turn IPSec on 
crypto ikev1 enable outside

 

Remote ASA config-

!
!--- Objects for the resource
object network remote_host
 host 192.168.0.10
object network remote_host_nat
 host 2.2.2.10
!
!--- NAT for the resource
nat (inside,outside) source static remote_host remote_host_nat
!
!--- ACL with NATed IP
access-list crypto-acl extended permit ip host 2.2.2.10 host 1.1.1.10
!
!---- Apply the ACL to the crypto map
crypto map outside-map 1 match address crypto-acl
!
!--- Turn IPSec on 
crypto ikev1 enable outside

 

Now, we will ping and SSH to the local host from remote host –

root@remote_host:~# ping 1.1.1.10
PING 1.1.1.10 (1.1.1.10): 56 data bytes
64 bytes from 1.1.1.10: seq=0 ttl=64 time=185.055 ms
64 bytes from 1.1.1.10: seq=1 ttl=64 time=82.989 ms
64 bytes from 1.1.1.10: seq=2 ttl=64 time=102.215 ms
64 bytes from 1.1.1.10: seq=3 ttl=64 time=70.191 ms
64 bytes from 1.1.1.10: seq=4 ttl=64 time=40.177 ms
^C
--- 1.1.1.10 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 40.177/96.125/185.055 ms

root@remote_host:~# ssh [email protected]
[email protected]'s password:

 

Netstat on local host –

root@local_host:~# netstat -ant | grep EST
tcp        0      0 10.0.0.10:22         2.2.2.10:33743  ESTABLISHED

You can see that the local host sees the public IP (2.2.2.10) of the remote host. We have solved the overlapping IP address space issue.

 

Restricting Resource Access

Now we that have the VPN established between the two organizations, we can secure the access by restricting the connection to only the protocols and ports needed. There are a few ways that this can be done, but there is one I believe provides the greatest level of granular control.

Method #1 – outside ACL

By default, traffic flowing through a VPN tunnel bypasses the interface ACLs. You can change this behavior with the no sysopt connection permit-vpn command. Then, any inbound traffic transiting the VPN tunnel must be evaluated by the outside interface ACL.

The downside is that this affects all VPN tunnel traffic, including your remote access VPN and any other VPN tunnels you might have. It also would allow access to the resource without it having to go through the VPN tunnel, because the outside interface would still accept un-tunneled traffic.

Method #2 – Crypto ACL

On the configs listed above, the crypto ACL is set to permit IP. You could narrow that down to the ports needed.

The downside is that every entry in the ACL would establish another security association and therefore another tunnel (i.e.) 10 lines in the crypto ACL would lead to 10 VPN tunnels, even though the source and destination IP are the same. This uses more system resources which limits its scalability and makes it a little harder to troubleshoot all the different SAs for every port. Cisco recommends that this method not be used, but for the life of me I can’t remember where I saw that bit of Cisco documentation.

Method #3 – VPN filter applied to group-policy

One thing you will notice about the above VPN configuration is that in the tunnel group, we did not use the default group policy, but made a different group policy named vpn-grp-policy. With this, we can apply a vpn-filter with an ACL to control the inbound access on a per-tunnel basis. This gives quite a bit of granular control. If you have 20 other organizations with VPNs tunnels, you can have 20 different group-polices and 20 different ACLs.

!
access-list vpn-gp-filter extended permit tcp host 2.2.2.10 host
 1.1.1.10 eq 100
access-list vpn-gp-filter extended deny ip any any
!
group-policy vpn-grp-policy attributes
 vpn-filter value vpn-gp-filter

Note: You must clear the existing SA for this to take effect.

One item you will notice is that NATed addresses are used in the access list. In ASA code 8.3 and above, the access-list format for interfaces changed to the real IP addresses instead of NATed addresses. However, VPN filter ACLs are like 8.2 and below, and use the NATed IP address.

We will use a netcat server on the local host to test connectivity -

root@local_host:~# nc -l -p 100

On the remote host we send a message to the local host -

root@remote_host:~# nc 1.1.1.10 100
Hello this is a test !
^C punt!

And this is what we see on the local host -

root@local_host:~# nc -l -p 100
Hello this is a test !
[1]+  Done

Now we test the SSH connectivity that had worked earlier and see it time out -

root@remote_host:~# ssh [email protected]
ssh: connect to host 1.1.1.10 port 22: Connection timed out

And the local ASA logs the ACL drop -

%ASA-6-106102: access-list vpn-gp-filter denied tcp for user ''
 outside/2.2.2.10(58634) -> inside/1.1.1.10(22) hit-cnt 1 first
 hit [0xdc2d972e, 0x0]

 

About Eric Flores

Eric is a network engineer with 6 years in the field. By day he works for a major real estate company and by night (when he gets away from the kids) is a nerd with a passion for anything related to technology. Find him on Twitter @nerdofnetworks.

  • Alexander Hartmaier

    We used method #3 until we discovered that the vpn filter acls are stateless, a Cisco TAC confirmed this, which makes the acl much more complex because now you suddenly have to allow the reply-packets of an outgoing connection too.

    • Eric Flores

      What version are you running. I am using this in my production environment right now and don’t need an ACL for the return traffic.

  • Anonymous1

    Alexander is right. When you use method #3 your ACLs for permitting traffic aren’t stateful anymore so you have to specifically allow return traffic in your vpn-filter ACL. Example, allow the new connection inside to outside:

    access-list inside_access_in extended permit tcp host 10.0.0.10 host 2.2.2.10 eq 22

    Now specify return traffic in vpn-filter ACL, otherwise it won’t work:

    access-list vpn-filter-acl extended permit tcp host 2.2.2.10 eq 22 host 1.1.1.10

    If this, or some form of this permit, isn’t in the vpn-filter ACL, then the resulting SYN+ACK coming back from 2.2.2.10 as part of the three way handshake will be denied. Stateless. Connections originating from the outside coming in is not this way though, it is permitted in the vpn-filter ACL and the ASA has the state information and knows to bypass inside_access_in for the return traffic. Another issue with this is that if a bad guy on the other end is clever enough he can mitigate what you’re allowing/denying. Given my above example, the device coming across as 2.2.2.10 can nmap my entire local 10.0.0.10 host as long as they use source port 22 while attempting TCP connections, so they can connect to RDP, PC-Anywhere, filesharing, etc….Method #1 does not have this weakness.

  • lkaczmarski

    Hello, I’m facing an issue where the customer requires us to translate our traffic from internal network into another private address space before it enters the VPN (at our end). Basically they want to see our traffic as it was coming from the IP range they specify (and not from our internal LAN). Do you guys know what would the best way to achieve this?