Creating a dual NAT lab gateway router

keep_calm_and_nat_on

Often times during an infrastructure project you need to create a quick mirror network environment to stage equipment or systems that will later be moved into production networks.  But having to go sit in the lab plugged into the lab isn’t always an option for efficient work-flows!

These setups typically are:

- short-lived environments that will be destroyed when the systems are moved to production

- duplicates of current VLAN(s) and IP address space(es)

- should not require any changes to the production network to accommodate their creation and deletion

Typically you have to go “plug in” to the sandbox to work.  Or you have to establish separate VPN gateways into the environment.  The VPN gateway approach (without using split tunnels) is a great approach if you have the ability, although it does mean you are either “in the lab” or “in the office”, not both, preventing access to email and Slack and other systems while working on the staging environment.

Since many times we only need to access a select set of hosts in the “sandbox” area, it’s feasible to leverage a NAT device with static translations to reach those endpoints.  But, since there is no routing between the sandbox and production networks (because we likely have duplicate networks and hosts!), we need to also fully nat the source and destination addresses of all traffic flowing in both directions through the gateway to ensure that hosts on each side of the NAT gateway have no knowledge of the IP addresses in use on the other side of the NAT gateway.

Since we all have a few extras lying around, let’s leverage a Cisco IOS router to server as a gateway for us!

Cisco’s IOS implementation of NAT is some times considered confusing to understand because of its terminology.

I find it helpful to remember the following when looking at its configurations:

  • INSIDE = the network to hide
    • INSIDE LOCAL = addresses on the inside before they are translated to the outside
    • INSIDE GLOBAL = addresses on the inside as they appear after translation to the outside
  • OUTSIDE = the public network
    • OUTSIDE GLOBAL = outside public addresses before they are translated to the inside
    • OUTSIDE LOCAL = outside public addresses after they are translated to the inside
  • Refer to Cisco’s overview of the terms HERE for a more clinical definition when in doubt ;)
  • All NAT rules are bi-directional and handle the corresponding return traffic automatically
    • A “nat inside source <local> <global>” rule performs:
      • NAT of source IP for traffic going in -> out (translates source from local to global ip to hide the private IP)
      • NAT of destination IP for traffic going out-> in (translates destination from global ip to local ip to reach the internal host)
    • A “nat outside source <global> <local>” rule also performs :
      • NAT of source IP for traffic going out -> in (translates source from global to local ip to hide the public IP from internal hosts)
      • NAT of destination IP for traffic going in->out (translates destination from local ip to global ip to reach the external host)

First, let’s setup our gateway’s interfaces to the two networks.  10.13.0.1/16 will be our lab network that is a duplicate of some production subnet.  10.6.0.0/16 will be our simulated production management network that is routable in our production environment.  In real use-cases we will need 1 or more available IP addresses in this network to create NATs pointing to our staging hosts.   For this lab, we’ll use a router as our lab host @ 10.13.0.2 and a router to emulate a host on the production network (such as our laptop) that needs to connect into the lab host as 10.6.0.2.  We will snag a production IP of 10.6.0.20 to use as our NAT ip to access the lab host from the production network.

NAT gateway interface configurations:

interface GigabitEthernet0/1
 description to lab
 ip address 10.13.0.1 255.255.0.0
 ip nat inside
 ip virtual-reassembly in
 duplex full
 speed auto
 media-type rj45
end
interface GigabitEthernet0/3
 description to prod
 ip address 10.6.0.1 255.255.0.0
 ip nat outside
 ip virtual-reassembly in
 duplex full
 speed auto
 media-type rj45
end

Next, we configure our static NAT to allow our 10.13.0.2 host to be reachable at 10.6.0.20 from the outside so that externally we don’t need to be aware of the 10.13.0.0/16 network:

ip nat inside source static 10.13.0.2 10.6.0.20

Normally you would add one static NAT for each lab host you want to access.  Or you could leverage PAT and map specific TCP ports on a single address to different hosts in the lab if you prefer.

Lastly, we add a NAT pool to eliminate the need for the 10.13.0.0/16 network to know about the 10.6.0.0/16 network at all!  Using this, all traffic that comes into the static NAT will then be NAT’d again as it is handed to the inside lab network, resulting in the lab hosts only communicating with 10.13.0.0/16 addresses:

access-list 2 permit 10.6.0.0 0.0.255.255
ip nat pool net-in 10.13.0.10 10.13.0.100 prefix-length 16
ip nat outside source list 2 pool net-in add-route

In our lab topology we are only matching access-list 2 on 10.6.0.0/16, but in a real use-case you would match all production network IP ranges that need to access the lab.  Also, the pool in our example is 90 IP addresses.  You can size that larger or smaller depending on many machines are expected to be accessing hosts in the lab.

This should result in us building a topology like this:

nat_lab

Let’s look at the resulting NAT translation tables before any connections are made:

nat-gateway#sh ip nat trans
Pro Inside global Inside local Outside local Outside global 
--- 10.6.0.20     10.13.0.2    ---           ---

Here we see just our static translation as expected.

Now let’s test it out by trying to telnet from 10.6.0.2 to the static NAT 10.6.0.20 to access our lab router!

prodhost#telnet 10.6.0.20
Trying 10.6.0.20...
Connected to 10.6.0.20.
Escape sequence is '^^q'.
User Access Verification
Username: cisco
Password: 
lab_host#

It worked! Let’s now look at the NAT translation tables while we’re connected through the NAT router:

nat-gateway#sh ip nat trans
Pro Inside global Inside local Outside local Outside global
--- ---           ---          10.13.0.15    10.6.0.2
tcp 10.6.0.20:23  10.13.0.2:23 10.13.0.15:29219 10.6.0.2:29219
--- 10.6.0.20     10.13.0.2    ---           ---
nat-gateway#

Here we can see the 10.6.0.2 router connecting to 10.6.0.20, which is then NAT’d into the lab at 10.13.0.2.  As the traffic is delivered to the 10.13.0.2 host it’s source is NAT’d to an address from our pool as 10.13.0.15.  So on the inside, the traffic appears as the LOCAL columns (session between 10.13.0.2 and 10.13.0.15), and on the outside the traffic appears as the GLOBAL columns (session between 10.6.0.2 and 10.6.0.20).  The router is handling the ARP responses for the corresponding NAT addresses allowing hosts on each side to talk to only their local subnets.

All that’s required is to then add one additional static NAT for each host in the lab that you wish to access.  You can do 1:1 IP based NATs if you have enough addresses or need to accommodate lots of services to each target host (telnet/ssh/tftp/etc/etc), or you can PAT to the hosts using a single production IP.  Below is an example of using PAT to access SSH on 2 routers with 1 production IP address:

ip nat inside source static tcp 10.13.0.100 22 10.6.0.10 10100 extendable
ip nat inside source static tcp 10.13.0.101 22 10.6.0.10 10101 extendable
nat-gateway#sh ip nat trans
Pro Inside global Inside local Outside local Outside global
tcp 10.6.0.10:10100 10.13.0.100:22 --- ---
tcp 10.6.0.10:10101 10.13.0.101:22 --- ---

Hopefully that helps make your lab time more productive!