IPSec VPNs or really any site-to-site VPN works best when at least one of the sides or better yet both have Public IP addresses. But what if one is behind NAT, or even both? It gets increasing tricky to configure the correct IP addresses for authentication, and forward correct ports on protocols. As I recently discovered, using IKEv2 and/or GRE further complicates things. Consider this setup:

Both routers are behind NAT/PAT firewalls without static 1-to-1 NATs configured. There are still some requirements though:
- Both firewalls must allow for protocol 50 passthrough for IPSec, or protocol 47 passthough if using GRE, which most do
- At least one side must be forwarding ports udp/500 (isakmp) and udp/4500 (nat-t) to the router’s internet-facing interface so the connection can be established
- Both routers need crypto ipsec nat-transparency udp-encapsulation enabled, which is the default setting.
Let’s look at sample configs for each scenario. These assume 1921 ISR G2 routers but IOS-XE configs should be exactly the same.
IPSec with ISAKMP / IKEv1
The is the simplest way to do it since only public IPs need to be referenced.
1) The ISAKMP portion:
crypto isakmp invalid-spi-recovery
crypto isakmp disconnect-revoked-peers
crypto isakmp keepalive 10
crypto isakmp nat keepalive 900
! Policy supporting strong encryption
crypto isakmp policy 100
encr aes 256 ! 256-bit AES encryption
hash sha384 ! SHA-384 hashing
authentication pre-share ! Using pre-shared keys
lifetime 28800 ! 28000 seconds = 8 hours
group 14 ! group 14 = 2048 bit key
! Backup policy supporting weaker encryption support for older devices
crypto isakmp policy 200
encr aes ! 128-bit AES encryption
hash sha ! SHA-1 hashing
authentication pre-share ! Using pre-shared keys
lifetime 28800 ! 28000 seconds = 8 hours
group 2 ! group 2 = 1024 bit key
! FYI - default values are still des, sha, rsa-sig, 86400, group 1 :-O
2) And then pre-shared keys:
! Key for site 1 router
crypto keyring Site2
local-address GigabitEthernet0/0
pre-shared-key address 203.0.113.222 key 0 MySecretKey
! Key for site 2 router
crypto keyring Site1
local-address GigabitEthernet0/0
pre-shared-key address 198.51.100.111 key 0 MySecretKey
! Can also use "crypto isakmp key 0 MySecretKey address 1.2.3.4"
3) IPSec parameters. For encryption, I like to just use 128-bit AES with either SHA-256 or SHA-1 signing with a group 2 (1024-bit) key to make the tunnel negotiation quick as possible.
! Create some IPSec Transform sets for ESP & 128-bit AES
crypto ipsec transform-set ESP_AES128_SHA256 esp-aes esp-sha256-hmac
mode tunnel
crypto ipsec transform-set ESP_AES128_SHA esp-aes esp-sha-hmac
mode tunnel
! Create IPSec profile
crypto ipsec profile MY_IPSEC_PROFILE
set transform-set ESP_AES128_SHA256 ESP_AES128_SHA
set pfs group2 ! group 2 = 1024-bit key
Optional step: since the “client” side isn’t reachable on port udp/500, the “server” side may be configured as a responder. This cuts down superfluous traffic, especially when the client is unreachable.
crypto ipsec profile IPSEC_PROFILE
responder-only
5) The last step is build the tunnel interfaces. For the “client” side:
interface Tunnel1000
ip address 169.254.0.1 255.255.255.252
ip tcp adjust-mss 1379
keepalive 10 3
tunnel source GigabitEthernet0/0
tunnel mode ipsec ipv4
tunnel destination 203.0.113.222
tunnel protection ipsec profile IPSEC_PROFILE
Server side is exactly the same but with different IP addresses:
interface Tunnel1000
ip address 169.254.0.2 255.255.255.252
tunnel destination 198.51.100.111
Doing debug crypto isakmp on the server side while the tunnels come up shows the public IP address of the client. Note the client’s random source ports.
ISAKMP (0): received packet from 198.51.100.111 dport 500 sport 14972 Global (R) MM_SA_SETUP
ISAKMP (1003): received packet from 198.51.100.111 dport 4500 sport 51597 Global (R) MM_KEY_EXCH
ISAKMP (1003): received packet from 198.51.100.111 dport 4500 sport 51597 Global (R) MM_KEY_EXCH
ISAKMP:(1003):SA has been authenticated with 198.51.100.111
ISAKMP:(1003):Detected port floating to port = 51597
We never see client’s private IP, but we do see the server side’s private IP at the end when the SA is finally built:
ISAKMP:(1003): Process initial contact,
bring down existing phase 1 and 2 SA's with local 192.168.2.222 remote 198.51.100.111 remote port 51597
ISAKMP: Trying to insert a peer 192.168.2.222/198.51.100.111/51597/, and inserted successfully
Can also see the other site’s private IP by examining the SAs once built:
Site1#show crypto isakmp peers 203.0.113.222
Peer: 203.0.113.222 Port: 4500 Local: 192.168.1.111
Phase1 id: 192.168.2.222
Site2#show crypto isakmp peers 198.51.100.111
Peer: 198.51.100.111 Port: 51597 Local: 192.168.2.222
Phase1 id: 192.168.1.111
IPSec with IKEv2
IKEv2 is new to me, but it was a surprise to see slightly different behavior when using NAT. Run through of the configuration:
1) Set some global IKEv2 parameters
crypto logging ikev2
crypto ikev2 nat keepalive 900
crypto ikev2 dpd 10 2 periodic
2) Create an IKEv2 Proposal and Policy
3) Keys are defined in the IKEv2 keyring, which has each site’s public IP address:
crypto ikev2 keyring MY_IKEV2_KEYRING
! Use this on site 1 router
peer Site2
address 203.0.113.222
pre-shared-key MySecretKey1234 ! Must be 16 chars or longer
! Use this on site 2 router
peer Site1
address 198.51.100.111
pre-shared-key MySecretKey1234 ! Must be 16 chars or longer
4) Create IKEv2 Profile
crypto ikev2 profile MY_IKEV2_PROFILE
match address local interface GigabitEthernet0/0
match identity remote address 192.168.0.0 255.255.0.0
authentication remote pre-share
authentication local pre-share
keyring local MY_IKEV2_KEYRING
dpd 20 2 periodic
This is where is gets weird because the “remote address” parameter needs to match the internal IP address(es) of the other sides. The simple and lazy approach is use 0.0.0.0 since that will match anything. The other option is use a different profile for each peer.
5) Add IKEv2 profile to the existing IPSec profile. Note that doing so shouldn’t break IKEv1 clients as the IKEv2 stuff should just be ignored.
crypto ipsec profile MY_IPSEC_PROFILE
set transform-set ESP_AES128_SHA256_TUNNEL ESP_AES128_SHA1_TUNNEL
set pfs group2
set ikev2-profile MY_IKEV2_PROFILE
In the SAs, we can see our private IP, but not the other side’s:
Site1#show crypto ikev2 sa remote 203.0.113.222
Tunnel-id Local Remote fvrf/ivrf Status
1 192.168.1.111/4500 203.0.113.222/4500 none/none READY
Encr: AES-CBC, keysize: 128, Hash: SHA256, DH Grp:14, Auth sign: PSK, Auth verify: PSK
Life/Active Time: 86400/30 sec
Site2#sh crypto ikev2 sa remote 198.51.100.111
Tunnel-id Local Remote fvrf/ivrf Status
1 192.168.2.222/4500 198.51.100.111/51597 none/none READY
Encr: AES-CBC, keysize: 128, Hash: SHA256, DH Grp:14, Auth sign: PSK, Auth verify: PSK
Life/Active Time: 86400/71 sec
BTW, if NAT-T has been disabled but is required by the other end, debug crypto ikev2 will show this:
Oct 12 19:53:08.620: IKEv2-ERROR:(SESSION ID = 1075,SA ID = 2): NAT is found but it is not supported.: NAT-T disabled via cli
Oct 12 19:53:08.620: IKEv2-ERROR:(SESSION ID = 1075,SA ID = 2):: NAT-T disabled via cli