Using “hostnames” to create ipsec tunnels with NAT in the middle

In previous posts I talked about creating route-based site-to-site ipsec tunnels. In those scenarios, both endpoints addresses were known and fixed.

Things might be a little more complex sometimes.

Let’s think of this use-case:

We have two spoke devices that need to create a tunnel with a hub device. Between spokes and hub we have a device performing source NAT. This means that traffic originated at the spokes will have the same source IP when reaching the hub. As a consequence the IKE gateways configured on the hub cannot use the IP address to distinguish between the two tunnels. In order to overcome this, IKE will rely on something else to distinguish the two spokes.
This is also the use-case where an endpoint has a dynamic ip so we cannot rely on that to establish tunnels.

If we think about the Juniper SDWAN solution, this is what we might face when using CSO as a cloud service. In that case, CSO is deployed at Juniper premises, not at customer premises. This means CSO server, vRR and OAM hubs are deployed outside the customer network. Juniper SDWAN architecture requires tunnels to be created between each device (spokes and hubs) and the OAM hubs. As a result, it might happen that between customer devices and cloud-based OAM we have a device performing NAT. For example, spokes are assigned private addresses so, for sure, at a certain point, some NAT operation will be needed in order to reach CSO which runs on the Internet.

Let’s see how this works.

At first, we assuem the nat device is not performing nat. This means we are going to create two standard route-based site-to-site ipsec vpns.

On spoke1 we configure:

set security ike proposal ike-prop authentication-method pre-shared-keys
set security ike proposal ike-prop dh-group group14
set security ike proposal ike-prop authentication-algorithm sha-384
set security ike proposal ike-prop encryption-algorithm aes-256-cbc
set security ike policy ike-pol mode main
set security ike policy ike-pol proposals ike-prop
set security ike policy ike-pol pre-shared-key ascii-text "$9$FCAZ3A0EclLxdhSvLX-2g5QznApBIE"
set security ike gateway gw1 ike-policy ike-pol
set security ike gateway gw1 address 192.168.3.0
set security ike gateway gw1 dead-peer-detection
set security ike gateway gw1 external-interface ge-0/0/0.0
set security ike gateway gw1 version v2-only
set security ipsec proposal ips-prop protocol esp
set security ipsec proposal ips-prop authentication-algorithm hmac-sha-256-128
set security ipsec proposal ips-prop encryption-algorithm aes-256-cbc
set security ipsec policy ips-pol proposals ips-prop
set security ipsec vpn vpn1 bind-interface st0.0
set security ipsec vpn vpn1 ike gateway gw1
set security ipsec vpn vpn1 ike ipsec-policy ips-pol
set security ipsec vpn vpn1 establish-tunnels immediately
set security policies default-policy permit-all
set security zones security-zone ge host-inbound-traffic system-services all
set security zones security-zone ge host-inbound-traffic protocols all
set security zones security-zone ge interfaces ge-0/0/0.0
set security zones security-zone st interfaces st0.0

Configuration on spoke2 is omitted but almost identical to spoke1.

On hub we configure:

set security ike proposal ike-prop authentication-method pre-shared-keys
set security ike proposal ike-prop dh-group group14
set security ike proposal ike-prop authentication-algorithm sha-384
set security ike proposal ike-prop encryption-algorithm aes-256-cbc
set security ike policy ike-pol mode main
set security ike policy ike-pol proposals ike-prop
set security ike policy ike-pol pre-shared-key ascii-text "$9$RCiElM7-waZjNd2aJDmPO1IhlK8X7"
set security ike gateway gw1 ike-policy ike-pol
set security ike gateway gw1 address 192.168.1.0
set security ike gateway gw1 dead-peer-detection
set security ike gateway gw1 external-interface ge-0/0/0.0
set security ike gateway gw1 version v2-only
set security ike gateway gw2 ike-policy ike-pol
set security ike gateway gw2 address 192.168.2.0
set security ike gateway gw2 dead-peer-detection
set security ike gateway gw2 external-interface ge-0/0/0.0
set security ike gateway gw2 version v2-only
set security ipsec proposal ips-prop protocol esp
set security ipsec proposal ips-prop authentication-algorithm hmac-sha-256-128
set security ipsec proposal ips-prop encryption-algorithm aes-256-cbc
set security ipsec policy ips-pol proposals ips-prop
set security ipsec vpn vpn1 bind-interface st0.0
set security ipsec vpn vpn1 ike gateway gw1
set security ipsec vpn vpn1 ike ipsec-policy ips-pol
set security ipsec vpn vpn1 establish-tunnels immediately
set security ipsec vpn vpn2 bind-interface st0.1
set security ipsec vpn vpn2 ike gateway gw2
set security ipsec vpn vpn2 ike ipsec-policy ips-pol
set security ipsec vpn vpn2 establish-tunnels immediately
set security policies default-policy permit-all
set security zones security-zone ge host-inbound-traffic system-services all
set security zones security-zone ge host-inbound-traffic protocols all
set security zones security-zone ge interfaces ge-0/0/0.0
set security zones security-zone st interfaces st0.0
set security zones security-zone st interfaces st0.1

Please notice, IKE gateways use ip addresses: 192.168.1.0 and 192.168.2.0.

As a result, IKE and IPSEC SAs are up:

root@hub# run show security ike sa
Index   State  Initiator cookie  Responder cookie  Mode           Remote Address
422472  UP     35266cb312b452fb  a678b35f8c4f9552  IKEv2          192.168.1.0
422474  UP     164a3eaa311a2846  6bec4ab1a2272c61  IKEv2          192.168.2.0

[edit]
root@hub# run show security ipsec sa
  Total active tunnels: 2     Total Ipsec sas: 2
  ID    Algorithm       SPI      Life:sec/kb  Mon lsys Port  Gateway
  <131073 ESP:aes-cbc-256/sha256 9474399d 3308/ unlim - root 500 192.168.1.0
  >131073 ESP:aes-cbc-256/sha256 43bb6fc6 3308/ unlim - root 500 192.168.1.0
  <131074 ESP:aes-cbc-256/sha256 e156b734 3316/ unlim - root 500 192.168.2.0
  >131074 ESP:aes-cbc-256/sha256 b7331ed0 3316/ unlim - root 500 192.168.2.0

Now, we add source NAT on the NAT device between spokes and hub:

set security nat source rule-set rs1 from zone spokes
set security nat source rule-set rs1 to zone hub
set security nat source rule-set rs1 rule r1 match source-address 192.168.0.0/16
set security nat source rule-set rs1 rule r1 match destination-address 0.0.0.0/0
set security nat source rule-set rs1 rule r1 then source-nat interface
set security policies default-policy permit-all
set security zones security-zone spokes host-inbound-traffic system-services all
set security zones security-zone spokes host-inbound-traffic protocols all
set security zones security-zone spokes interfaces ge-0/0/0.0
set security zones security-zone spokes interfaces ge-0/0/1.0
set security zones security-zone hub host-inbound-traffic system-services all
set security zones security-zone hub host-inbound-traffic protocols all
set security zones security-zone hub interfaces ge-0/0/2.0

At this point, hub is not supposed to know about 192.168.1.0 and 192.168.2.0 as those addresses are hidden by NAT.

Hub only knows about the ip address used by NAT device to source NAT packets, 192.168.3.1:

root@hub# delete security ike gateway gw1 address 192.168.1.0
root@hub# delete security ike gateway gw2 address 192.168.2.0
root@hub# set security ike gateway gw2 address 192.168.3.1
root@hub# set security ike gateway gw1 address 192.168.3.1

Result, SAs down:

root@hub> show security ike sa
Index   State  Initiator cookie  Responder cookie  Mode           Remote Address
422478  DOWN   ba4e87a9798983d7  0000000000000000  IKEv2          192.168.3.1

Let’s check sessions on NAT device:

root@nat# run show security flow session
Session ID: 35, Policy name: self-traffic-policy/1, Timeout: 48, Valid
  In: 192.168.3.0/500 --> 192.168.3.1/500;udp, Conn Tag: 0x0, If: ge-0/0/2.0, Pkts: 15, Bytes: 8190,
  Out: 192.168.3.1/500 --> 192.168.3.0/500;udp, Conn Tag: 0x0, If: .local..0, Pkts: 0, Bytes: 0,

Session ID: 36, Policy name: default-policy-logical-system-00/2, Timeout: 54, Valid
  In: 192.168.1.0/500 --> 192.168.3.0/500;udp, Conn Tag: 0x0, If: ge-0/0/0.0, Pkts: 1, Bytes: 116,
  Out: 192.168.3.0/500 --> 192.168.3.1/32066;udp, Conn Tag: 0x0, If: ge-0/0/2.0, Pkts: 0, Bytes: 0,

Session ID: 37, Policy name: default-policy-logical-system-00/2, Timeout: 58, Valid
  In: 192.168.2.0/500 --> 192.168.3.0/500;udp, Conn Tag: 0x0, If: ge-0/0/1.0, Pkts: 1, Bytes: 116,
  Out: 192.168.3.0/500 --> 192.168.3.1/10854;udp, Conn Tag: 0x0, If: ge-0/0/2.0, Pkts: 0, Bytes: 0,
Total sessions: 3

We can see spokes trying to establish IKE SAs (udp port 500) and source nat is performed. Anyhow, return traffic from the hub is missing and leads to SAs being down.

This is because the hub is no longer able to differentiate between spoke1 and spoke2.

As said before, we need another way to achieve that. Instead of relying on ip addresses (which might not be unique or might be dynamic), we rely on “logical names. On spokes we add:

spoke1:
set security ike gateway gw1 local-identity hostname spoke1
spoke2:
set security ike gateway gw1 local-identity hostname spoke2

Basically, we give each spoke a name!

Spokes still use hub ip address as ike gateway endpoint as that address is not affected by NAT and will not change.

On hub, we modify the configuration as follows:

root@hub# delete security ike gateway gw1 address 192.168.3.1
root@hub# delete security ike gateway gw2 address 192.168.3.1
root@hub# set security ike gateway gw1 dynamic hostname spoke1
root@hub# set security ike gateway gw2 dynamic hostname spoke2
root@hub# set security ike policy ike-pol mode aggressive

Let’s check SAs and see if “identity” information is there:

root@hub# run show security ike sa
Index   State  Initiator cookie  Responder cookie  Mode           Remote Address
422513  UP     007a6eeb9bb62804  9aca72623ebf37bc  IKEv2          192.168.3.1
422514  UP     c347b708b6c7fe63  09d9ce40db807812  IKEv2          192.168.3.1

[edit]
root@hub# run show security ike sa detail | match identity
    Local identity: 192.168.3.0
    Remote identity: spoke1
    Local identity: 192.168.3.0
    Remote identity: spoke2

root@hub# run show security ipsec security-associations
  Total active tunnels: 2     Total Ipsec sas: 2
  ID    Algorithm       SPI      Life:sec/kb  Mon lsys Port  Gateway
  <67108866 ESP:aes-cbc-256/sha256 253a965c 3445/ unlim - root 18733 192.168.3.1
  >67108866 ESP:aes-cbc-256/sha256 8d3828c1 3445/ unlim - root 18733 192.168.3.1
  <67108867 ESP:aes-cbc-256/sha256 753c94c 3469/ unlim - root 12333 192.168.3.1
  >67108867 ESP:aes-cbc-256/sha256 5730dccc 3469/ unlim - root 12333 192.168.3.1

Sessions on nat device now show bidirectional traffic:

root@nat# run show security flow session
Session ID: 55, Policy name: default-policy-logical-system-00/2, Timeout: 54, Valid
  In: 192.168.2.0/4500 --> 192.168.3.0/4500;udp, Conn Tag: 0x0, If: ge-0/0/1.0, Pkts: 14, Bytes: 1277,
  Out: 192.168.3.0/4500 --> 192.168.3.1/12333;udp, Conn Tag: 0x0, If: ge-0/0/2.0, Pkts: 5, Bytes: 984,

Session ID: 57, Policy name: default-policy-logical-system-00/2, Timeout: 50, Valid
  In: 192.168.1.0/4500 --> 192.168.3.0/4500;udp, Conn Tag: 0x0, If: ge-0/0/0.0, Pkts: 11, Bytes: 709,
  Out: 192.168.3.0/4500 --> 192.168.3.1/18733;udp, Conn Tag: 0x0, If: ge-0/0/2.0, Pkts: 2, Bytes: 432,
Total sessions: 2

Please notice, port 4500 is used. That port is ipsec nat traversal!

Tunnels up!

Ciao
IoSonoUmberto

Leave a comment