How to setup an IPsec connection between two NATed peers: using id's and RSA keys

In the previous post from this series, we've discussed setting up an IPsec tunnel from a NATed router to a non-NATed one. The key point is that in the presence of NAT, the non-NATed side cannot identify the NATed peer by its public address, so a manually configured id is required.

What if both peers are NATed though? Suppose you are setting up a tunnel between two EC2 instances. They are both NATed, and this creates its own unique challenges: neither of them know their public addresses or can identify their peers by their public address. So, we need to solve two problems.

In this post, we'll setup a tunnel between two routers, let's call them "east" and "west". The "east" router will be the initiator, and "west" will be the responder.

A note on pre-shared keys

While there are many issues with PSKs that public key cryptography solves in an elegant way, such as the problem of exchanging them securely, there's also a specific pitfall associated with them in VyOS: if the local-address of the peer is set to 'any' and the peer is identified by an id rather than public address, it won't allow you to use a pre-shared key for that peer. I have to admit I don't remember if this is a fundamental issue or an implementation detail, and perhaps we can lift this limitation at some point, but as of 1.1.8 and the current builds of 1.2.0, you have to use RSA keys or x.509 for authentication in this kind of setup.

Setting up RSA keys

We will not touch x.509 just yet and will focus on "certless" RSA keys in this post. They are very fast and easy to setup. The only real disadvantage is that some IPsec implementation do not support them and require either pre-shared keys or x.509 certificates, but in our example both sides are running VyOS and this is not an issue.

To generate an RSA key, use this command: "run generate vpn rsa-key bits 2048 random /dev/urandom".

Adjust the key length to match the size and style of your tinfoil hat. Mine looks fine with 2048, though setting it to 4096 won't harm. There is also an option to use /dev/random, but on virtual machines it can be impractical due to long blocking time, and contrary to the popular misconception, neither is /dev/random a source of "true" (information theoretically secure) random numbers, nor is /dev/urandom always inherently insecure. Let's generate a key on the West router.

vyos@west# run generate vpn rsa-key bits 2048 random /dev/urandom 
Generating rsa-key to /config/ipsec.d/rsa-keys/localhost.key

Your new local RSA key has been generated
The public portion of the key is:

0sAQO8DJuyosdeE1VQnRUdsPGYFJ5gBsj4qYurjUv+/Jn5qSJJSvLYONNCDYfRDj/me5WGAtGwqmikD00oiLdCqR0FOZJTEQoEWeEh7YnOd4MEIWdeOLFRnGeETcoxGX63S7mxfol4/CVw/9n/kXRRHCnNsgYROsygZLlQIRK7hWAq3L6O1WT7Y3s7dHekXN+Ev6UbtZWQq8lejgmO0TR2ZAF3y6iBETW4Q93ARlhUva/ubBjg2oqtuX9u5UpxWTowuNycY44jm3+vjWczPtcYvvlXNt6nSGoORoHPdBeVyzU7yGIf+TcPKXTiro1JO20gwFv1dPTOLucmgEhjhuO86fFf

Save the public key somewhere. If you clear the screen before copying it, don't worry, you can always find the public key in /config/ipsec.d/rsa-keys/localhost.key file, in its "pubkey=..." section.

Now add the West key to the East router so that we can reference it in the IPsec settings:


vyos@east# set vpn rsa-keys rsa-key-name east rsa-key 0sAQO8DJuyosdeE1V...

Repeat the procedure on the second router.

IPsec setup

Now that both routers have each other's keys, we can setup the actual tunnel. The key points:

  1. Since both routers do not know their effective public addresses, we set the local-address of the peer to "any".
  2. On the initiator, we set the peer address to its public address, but on the responder we only set the id.
  3. On the initiator, we need to set the remote-id option so that it can identify IKE traffic from the responder correctly.
  4. On the responder, we need to set the local id so that initiator can know who's talking to it for the point #3 to work.
  5. Don't forget to enable NAT traversal on both sides, "set vpn ipsec nat-traversal enable".

Let's look at the configs:

The East side:

vyos@east# show vpn 
 ipsec {
     [SNIP, IKE/ESP groups are irrelevant]
     ipsec-interfaces {
         interface eth0
     }
     nat-traversal enable
     site-to-site {
         peer 192.0.2.60 {
             authentication {
                 id @east
                 mode rsa
                 remote-id west
                 rsa-key-name west
             }
             connection-type initiate
             default-esp-group Foo
             ike-group Foo
             local-address any
             tunnel 1 {
                 local {
                     prefix 10.36.63.0/24
                 }
                 remote {
                     prefix 10.45.54.0/24
                 }
             }
         }
     }
 }
 rsa-keys {
     rsa-key-name west {
         rsa-key 0sAQO8DJuyosdeE1VQnRUdsPGYFJ5gBsj4qYurjUv+/Jn5qSJJSvLYONNCDYfRDj/me5WGAtGwqmikD00oiLdCqR0FOZJTEQoEWeEh7YnOd4MEIWdeOLFRnGeETcoxGX63S7mxfol4/CVw/9n/kXRRHCnNsgYROsygZLlQIRK7hWAq3L6O1WT7Y3s7dHekXN+Ev6UbtZWQq8lejgmO0TR2ZAF3y6iBETW4Q93ARlhUva/ubBjg2oqtuX9u5UpxWTowuNycY44jm3+vjWczPtcYvvlXNt6nSGoORoHPdBeVyzU7yGIf+TcPKXTiro1JO20gwFv1dPTOLucmgEhjhuO86fFf
     }
 }

The West side:

vyos@west# show vpn 
 ipsec {
     [SNIP]
     ipsec-interfaces {
         interface eth0
     }
     nat-traversal enable
     site-to-site {
         peer @east {
             authentication {
                 id west
                 mode rsa
                 rsa-key-name east
             }
             connection-type respond
             default-esp-group Foo
             ike-group Foo
             local-address any
             tunnel 1 {
                 local {
                     prefix 10.45.54.0/24
                 }
                 remote {
                     prefix 10.36.63.0/24
                 }
             }
         }
     }
 }
 rsa-keys {
     rsa-key-name east {
         rsa-key 0sAQO7OF/FKgx33E5I29HSy2cqLnL9hNZ6CMbR8kVRIKhqAowIAskh13+gJN2QKOvLfbjN29uy94W02tty5G7+S+xOPeMsCJyz+ofD/v5tJpqIUughngCAGEoB6uveRRfqF15sOetEgjUGPmcVU+neOJ822E2T1sYbnEVfd+vilNPFopzlY61gtWgq7m7ANe2logwSB5XWyQkgCDNi+8IqVyFhNTVbmxDyfJQ1T4/3sRgcEh5XdZhSqRIwxI7/m2jH1FfIGg0FX5+5ok0bBmRU3tMkUKMB1A4QqgXPXR5P0SMDEkfo6zkbsueAX1NEOKXO443r5aKzA1qAGKV0Zp0sriuR
     }
 }

Now if we look in the logs, we will see the following picture:

Jan 12 06:24:23 east pluto[28278]: "peer-192.0.2.60-tunnel-1" #1: enabling possible NAT-traversal with method 3
Jan 12 06:24:23 east pluto[28278]: "peer-192.0.2.60-tunnel-1" #1: NAT-Traversal: Result using RFC 3947: both are NATed
Jan 12 06:24:23 east pluto[28278]: "peer-192.0.2.60-tunnel-1" #1: we don't have a cert
Jan 12 06:24:23 east pluto[28278]: "peer-192.0.2.60-tunnel-1" #1: Peer ID is ID_FQDN: 'west'
Jan 12 06:24:23 east pluto[28278]: "peer-192.0.2.60-tunnel-1" #1: ISAKMP SA established
Jan 12 06:24:23 east pluto[28278]: "peer-192.0.2.60-tunnel-1" #2: initiating Quick Mode PUBKEY+ENCRYPT+TUNNEL+PFS+UP {using isakmp#1}
Jan 12 06:24:23 east pluto[28278]: "peer-192.0.2.60-tunnel-1" #2: sent QI2, IPsec SA established {ESP=>0xc9bf71e1 <0xc32e1a3a NATOA=0.0.0.0}

This concludes the all-NATed IPsec setup.