AWS One-Off Series: Enabling NAT in AWS VPN


The ask seems innocent enough: Can I tunnel publicly routable IP addresses through a VPN to my AWS environment? The answer however, isn't.

Throughout many years of configuring IPsec tunnel overlays for customers, B2B partners every now and then will sneak in the seemingly unsurpassable restriction of RFC1918 (ie. private IP subnets) space allowed through the tunnel. In the past, through the traditional network engineering technique of terminating a VPN on physically-owned router or firewall hardware, this is solved easily enough by including a simple NAT configuration and utilizing either the publicly-routable IP address of the device itself or a separate PI prefix. Problem solved.

However this little requirement presents quite a problem for AWS users, who ask: How do I connect my IPSec VPN to a partner/provider who says I cannot tunnel RFC1918/internal IP space to them? The short answer is, when using AWS VPC VPN, you can't. However, using third-party virtual router/firewalls, you relatively easily can get away with it. In this entry I will attempt to illustrate how to do so at reasonable cost.

I've personally been involved with a few customers who've specifically asked how they can get around this limitation in AWS. Here's how to launch a solution which will establish a tunnel to a remote VPN endpoint using a single, /32 elastic IP address as the 'local' encryption domain. All traffic sent from your VPC will NAT as the elastic IP address, meaning that without port forwarding, this is mostly a one-way solution.

Forward disclaimer: I'm a bit of fan of VyOS. If you haven't used VyOS (or Vyatta) before, it's an excellent, light-weight virtual router running a JunOS-like CLI capable of OSPF, BGP, seamless VTI tunneling and more. Best of all, it's free. Other, more commercially available solutions such as Cisco CSR and Juniper vSRX, also exist in the marketplace, and while their configurations aren't much more complicated, they're just much more expensive, so I wont cover them here.

Step 1: Launch Time

Provision a VyOS instance from the AMI marketplace. VyOS is open source freeware, so your only cost will be that of the instance itself. As for the size of the instance size, I leave that for you to decide.

Make sure to launch the instance into a public subnet (in otherwords a subnet with an IGW attached) without auto-assigning a public IP.

After the instance has launched, attach an elastic IP address. This IP address needs to not change since it will be your VPN peer address which you will give to your second party to configure their VPN appliance.

The security group for this instance will probably need to allow at least the following inbound: ESP (custom protocol 50), UDP port 500, ICMP and SSH.

Step 2: Base Configuration

Now that the instance is running, make sure you're able to access it. Login to your newly assigned and associated elastic IP via the 'vyos' username.

Also, since this instance will be hair-pinning traffic in/out of a single interface, be sure to disable the pesky 'Source/Destination Check'. From the EC2 console, right click the VyOS instance, "Networking > Change Source/Dest. Check" then click "Yes, Disable"

We're now allowed to have some routing fun with our instance.

Once logged into VyOS, type 'configure' and start by providing a new hostname and creating a static IP route back toward the VPC, then finally commit the changes. The following example assumes a VPC configured with IP space 172.31.0.0/16:
vyos@VyOS-AMI:~$ configure
vyos@VyOS-AMI# set system host-name 'VPN-CE-01'
vyos@VyOS-AMI# set protocols static route 172.31.0.0/16 next-hop 172.31.32.1
vyos@VyOS-AMI# commit
[ system host-name VPN-CE-01 ]
Stopping enhanced syslogd: rsyslogd.
Starting enhanced syslogd: rsyslogd.
vyos@VyOS-AMI# save
Saving configuration to '/config/config.boot'...
Done
vyos@VyOS-AMI# exit
vyos@VyOS-AMI:~$

Step 3: VPN Configuration

At this point you will need to have a conversation with your remote party to exchange the details of your VPN (Peer IP address, Encryption domain/Interesting traffic, Phase 1 encryption, Phase 2 encryption) settings. While the decided-upon params of the phase 1 and 2 encryption are not super relevant here, it is important to note that you need to supply the remote end with your new elastic IP address as both the VPN peer IP address and the local encryption domain/interesting traffic. For example, the assigned elastic public IP address for my VyOS instance is 34.192.251.180, so this is the address I will supply to the third party.

Further, let's assume that the remote party's peer IP address is 1.2.3.4 and their remote encryption domain is 192.168.116.0/24, and that we've decided upon AES-256 payload encryption w/ SHA1 integrity hashing, with DH group in phase 1 and no phase 2 PFS. Finally, our PSK is 'soSecretY0'.

Here is what the configuration would look like to accomplish building the tunnel. After entering configuration mode by typing 'configure' again, paste the following:
vyos@VyOS-AMI:~$ configure
[edit]
vyos@VyOS-AMI# [paste below]
set nat source rule 10 destination address '192.168.119.0/24'
set nat source rule 10 outbound-interface 'eth0'
set nat source rule 10 source address '172.31.0.0/16'
set nat source rule 10 translation address '34.192.251.180'
set vpn ipsec esp-group ESP-AES256-SHA1 compression 'disable'
set vpn ipsec esp-group ESP-AES256-SHA1 lifetime '1800'
set vpn ipsec esp-group ESP-AES256-SHA1 mode 'tunnel'
set vpn ipsec esp-group ESP-AES256-SHA1 pfs 'disable'
set vpn ipsec esp-group ESP-AES256-SHA1 proposal 1 encryption 'aes256'
set vpn ipsec esp-group ESP-AES256-SHA1 proposal 1 hash 'sha1'
set vpn ipsec ike-group IKE-AES256-SHA1 ikev2-reauth 'no'
set vpn ipsec ike-group IKE-AES256-SHA1 key-exchange 'ikev1'
set vpn ipsec ike-group IKE-AES256-SHA1 lifetime '3600'
set vpn ipsec ike-group IKE-AES256-SHA1 proposal 1 dh-group '2'
set vpn ipsec ike-group IKE-AES256-SHA1 proposal 1 encryption 'aes256'
set vpn ipsec ike-group IKE-AES256-SHA1 proposal 1 hash 'sha1'
set vpn ipsec ipsec-interfaces interface 'eth0'
set vpn ipsec site-to-site peer 1.2.3.4 authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer 1.2.3.4 authentication pre-shared-secret 'soSecretY0'
set vpn ipsec site-to-site peer 1.2.3.4 ike-group 'IKE-AES256-SHA1'
set vpn ipsec site-to-site peer 1.2.3.4 local-address '172.31.39.21'
set vpn ipsec site-to-site peer 1.2.3.4 tunnel 0 esp-group 'ESP-AES256-SHA1'
set vpn ipsec site-to-site peer 1.2.3.4 tunnel 0 local prefix '34.192.251.180/32'
set vpn ipsec site-to-site peer 1.2.3.4 tunnel 0 remote prefix '192.168.119.0/24'
You may notice the NAT statements at the top of this configuration. This is a necessary 'one-to-many' source nat (or "SNAT") rule to translate all traffic originating from our VPC space of 172.31.0.0/16 to translate as coming from our elastic IP address instead, 34.192.251.180.

Write the above configuration ("# commit", "# save").

Step 4: VPC Route Table Updates

At this point the VPN should be considered configured, however you now need to allow all other EC2 instances the ability to route to it for network resources on the other end. For this, you rather simply need to update your relevant VPC route tables with a route for the IP space on the other end of the tunnel to point to your VPC instance. For a default route table, this can be accomplished clicking the 'Routes' tab and adding your entry there:


In the above you can see a route has been added which points the 192.168.0.0/16 IP space toward our VyOS instance. Note: there's no reason this couldn't be a more specific prefix of 192.166.119.0/24 as well, I just used the full class B /16 space as an example.

Step 5: "Tunnels Up" Verification

Here now is the often painful portion where you will need to get the third party on the phone and confirm that your end of the VPN tunnel is configured and that you're ready to test connectivity. Once you and the remote end have each verified all of the fun bits of IPsec (PSK, Phase 1/2 settings, Encryption domains, Peer IPs) you should eventually see both IKE (Phase 1) and ESP (Phase 2) security associations appear as 'up' on your VyOS instance by running 'show vpn ike sa' and 'show vpn ipsec sa' respectively:


Voila! At this point, any instance in my VPC should be able to successfully connect across the tunnel, via VyOS, to the remote resources.

Downsides, Trade-offs and Alternative Approaches

It's probably important to mention that we've effectively recreated a wheel here. One issue about that  too is that this wheel has No N+1 Redundancy, similar to what the native VPC VPN would provide by default, where two peering endpoints are provided to peer a CGW with. However since VyOS runs as an EC2 instance, it can rely on native EC2 high availability mechanisms in the event of underlying compute hardware issues. In this case, VyOS would be restarted and recovery times would be on the order of minutes, even without a high-availability pair. Further, VyOS only supports HA through VRRP, so a true N+1 setup would not be possible in AWS.

Running a multi-VPC deployment, or planning to? I suggest not using VyOS here and instead investing instead in Cisco CSR running in a designated transit VPC. A properly configured transit VPC in AWS will give you automated scale between existing or newly provisioned VPCs. That instance could then also be used to incorporate the NAT required for the above topic, and also supports HA in AWS.

While another topic really, for those curious a transit VPC with CSR is basically a lambda python operation which periodically probes all VPCs existing in specified AWS accounts looking for a certain tag on VGWs. Once found, another function will login to the same Cisco CSR and automatically configure the VPN tunnels required for VPC VPN and bring up connectivity. All of this is simply deployed via a Cloud Formation template. This is quite a smart way to connect your VPCs together if you have, say, a multi-region private connectivity requirement.


Questions? Please ask or contact me directly!

Popular posts from this blog

Configuring Cisco ASA for Route-Based VPN

Up and Rawring with TRex: Cisco's Open Traffic Generator

Running ASA on Firepower 2100: An End-to-End Guide