NAT Configuration on ASA 8.4+, Part 2

NetCraftsmen®

Note: This post was edited by Marilyn Outerbridge

This is a second blog post of a series. For the series, please click here.

This blog post will cover all of the major Dynamic PAT “flavors” that one might encounter in production networks and some that may show up on the CCIE lab. A detailed explanation of the applicability in production of the scenario being discussed is deemed outside the scope of this series. Most ASA books pre 8.4 cover those aspects in much detail. The reader is encouraged to reference one of these books.

The NAT examples in the article are taken from the following topology:

ASA Nat Topology

Figure 2-1: ASA NAT Topology

Generally, in production networks, more than two interfaces exist. The configuration examples herein assume that either 2+ interfaces are already in use, or will be used in the future, making it somewhat future-proof.

Without further ado, here are the major NAT types and sub-types that most scenarios fit into.

  • Dynamic NAT
  • Static NAT
  • Identity NAT
  • NAT Exemption

Dynamic NAT

Dynamic NAT on the ASA can be configured to appear in any of the three sections discussed in Part 1. That, combined with the fact that there are various types of Dynamic PAT applicable to a scenario makes for a decent size list.

Dynamic PAT to ASA Interface IP Address

In the most simplistic case, a block of IP addresses residing on the Inside interface will be translated either to the ASA Outside or DMZ interface address.

The keyword any cannot be used for the external interface if the mapped IP is the interface IP. One NAT statement (NON or Twice NAT) for each external interface must be configured.

Using Network Object NAT (NON)

With Auto NAT or NON, an object would have to be created for each interface where the rule is applied.

In the example topology, the ASA is translating the inside IP block, 192.168.13/24 to the Gi0/0 IP for traffic leaving the outside interface and to the Gi0/2 IP for traffic leaving the DMZ1 interface.

Configuration

ASA1(config)# object network obj_192.168.13.0_outside
ASA1(config-network-object)# subnet 192.168.13.0 255.255.255.0
ASA1(config-network-object)# nat (inside,outside) dynamic interface
ASA1(config-network-object)#exit
ASA1(config)# object network obj_192.168.13.0_dmz1
ASA1(config-network-object)# subnet 192.168.13.0 255.255.255.0
ASA1(config-network-object)# nat (inside,dmz1) dynamic interface

Verification

ASA1# sho run object
object network obj_192.168.13.0_outside
 subnet 192.168.13.0 255.255.255.0
object network obj_192.168.13.0_dmz1
 subnet 192.168.13.0 255.255.255.0

ASA1# sho run nat
!
object network obj_192.168.13.0_outside
 nat (inside,outside) dynamic interface
object network obj_192.168.13.0_dmz1
 nat (inside,dmz1) dynamic interface

ASA1# sho nat detail

Auto NAT Policies (Section 2)
1 (inside) to (dmz1) source dynamic obj_192.168.13.0_dmz1 interface 
 translate_hits = 0, untranslate_hits = 0
 Source - Origin: 192.168.13.0/24, Translated: 192.168.34.3/24
2 (inside) to (outside) source dynamic obj_192.168.13.0_outside interface 
 translate_hits = 0, untranslate_hits = 0
 Source - Origin: 192.168.13.0/24, Translated: 192.168.23.3/24

 

This illustrates the two different types of NAT verification on the ASA. Essentially, the show run object is for configuration verification whereas show nat gives an insight into the operation of the ASA.

Caveat: Note that during configuration, the IP block of the object as well as the NAT operations are configured at the same time, seemingly under the same object group. But the ASA actually stores the code in two different sections, albeit under the same parent category - i.e. the object network category.

Thus, the IP block definition is stored with the other objects and object-groups but the NAT portion is stored under an object with the same name in the NAT portion of the configuration.

This can make the configuration verification a bit tedious and unintuitive for some.

Finally, the packet tracer verification will identify the exact rule used to translate the packet.

Packet Tracer Verification

ASA1# packet-tracer input inside tcp 192.168.13.1 10000 192.168.23.2 23

Phase: 1
Type: ROUTE-LOOKUP
Subtype: input
Result: ALLOW
Config:
Additional Information:
in   192.168.23.0    255.255.255.0   outside

Phase: 2
Type: IP-OPTIONS
Subtype:
Result: ALLOW
Config:
Additional Information:

Phase: 3
Type: NAT
Subtype:
Result: ALLOW
Config:
object network obj_192.168.13.0_outside
  nat (inside,outside) dynamic interface
Additional Information:
Dynamic translate 192.168.13.1/10000 to 192.168.23.3/16014

Phase: 4
Type: IP-OPTIONS
Subtype:
Result: ALLOW
Config:
Additional Information:

Phase: 5
Type: FLOW-CREATION
Subtype:
Result: ALLOW
Config:
Additional Information:
New flow created with id 5, packet dispatched to next module

Result:
input-interface: inside
input-status: up
input-line-status: up
output-interface: outside
output-status: up
output-line-status: up
Action: allow

The result of this configuration is visible when R1 makes a TCP connection to R2 or R3.

Results
R1#telnet 192.168.23.2
Trying 192.168.23.2 ... Open

R2#who
Line         User    Host(s)     Idle       Location
0 con 0              idle       00:31:42
* 98 vty 0           idle       00:00:00   192.168.23.3

Interface    User        Mode         Idle     Peer Address 

R2#exit

[Connection to 192.168.23.2 closed by foreign host]
R1#telnet 192.168.34.4
Trying 192.168.34.4 ... Open

R4#who
Line         User    Host(s)     Idle       Location
0 con 0               idle     00:30:01
* 98 vty 0            idle     00:00:00     192.168.34.3

Interface    User        Mode         Idle     Peer Address 

USING MANUAL OR TWICE NAT

For Twice NAT, a single object can be defined for the source IP or IP block. Having said that, two NAT statements will still exist to perform the actual NAT as the keyword any is not allowed as per the note at the beginning of the section.

Configuration

ASA1(config)# object network obj_192.168.13.0
ASA1(config-network-object)# subnet 192.168.13.0 255.255.255.0
ASA1(config-network-object)# exit
ASA1(config)# nat (inside,outside) source dynamic obj_192.168.13.0 interface
ASA1(config)# nat (inside,dmz1) source dynamic obj_192.168.13.0 interface

Verification

ASA1(config)# show nat detail 
Manual NAT Policies (Section 1)
1 (inside) to (outside) source dynamic obj_192.168.13.0 interface  
    translate_hits = 0, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.23.3/24
2 (inside) to (dmz1) source dynamic obj_192.168.13.0 interface  
    translate_hits = 0, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.34.3/24

Auto NAT Policies (Section 2)
1 (inside) to (dmz1) source dynamic obj_192.168.13.0_dmz1 interface  
    translate_hits = 1, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.34.3/24
2 (inside) to (outside) source dynamic obj_192.168.13.0_outside interface  
    translate_hits = 3, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.23.3/24

The notable observation in the above output is that Section 1 was populated with the two new configured rules. Comparing it to the show nat detail output of NON section, notice there was no Section 1 (it is empty) in the NON only output. Now, Section 1 entries show up in the output before Section 2 entries. They also appear in the same order as they were configured on the CLI. Thus, the NAT rule order can be determined simply by looking at this output.
Once again, packet tracer will provide a definitive answer as to which rule is used for the actual translation:

Packet Tracer Verification

ASA1(config)# packet-tracer input inside tcp 192.168.13.1 10000 192.168.23.2 23

Phase: 1
Type: ROUTE-LOOKUP
Subtype: input
Result: ALLOW
Config:
Additional Information:
in   192.168.23.0    255.255.255.0   outside

Phase: 2
Type: IP-OPTIONS
Subtype: 
Result: ALLOW
Config:
Additional Information:

Phase: 3
Type: NAT
Subtype: 
Result: ALLOW
Config:
nat (inside,outside) source dynamic obj_192.168.13.0 interface
Additional Information:
Dynamic translate 192.168.13.1/10000 to 192.168.23.3/24233

Phase: 4      
Type: IP-OPTIONS
Subtype: 
Result: ALLOW
Config:
Additional Information:

Phase: 5
Type: FLOW-CREATION
Subtype: 
Result: ALLOW
Config:
Additional Information:
New flow created with id 8, packet dispatched to next module

Result:
input-interface: inside
input-status: up
input-line-status: up
output-interface: outside
output-status: up
output-line-status: up
Action: allow

As the packet tracer output shows, the packet is being translated by the Twice NAT rules.

Results
R1#telnet 192.168.23.2
Trying 192.168.23.2 ... Open

R2#who
Line         User    Host(s)     Idle       Location
0 con 0               idle     00:00:14
* 98 vty 0            idle     00:00:00    192.168.23.3

Interface    User        Mode         Idle     Peer Address 

R2#exit

[Connection to 192.168.23.2 closed by foreign host]
R1#telnet 192.168.34.4
Trying 192.168.34.4 ... Open

R4#who
Line         User    Host(s)     Idle       Location
0 con 0               idle     00:00:10
* 98 vty 0            idle     00:00:00   192.168.34.3

Interface    User        Mode         Idle     Peer Address 

MANUAL NAT GENERALIZATION

But what if the user wanted to live by a maxim and avoid unnecessary thinking? Can Manual NAT still be utilized while adhering to the static before dynamic generalization? The answer is yes; as long as a decision is taken to always place the dynamic NAT entries in Section 3 instead of Section 1.

There is a caveat here as well. Entries in Section 3, just like Section 1 do not order themselves automatically. This section should be treated just like Section 1 and the entries should be configured using a logic similar to ACL logic.

USING MANUAL DYNAMIC NAT IN SECTION 3

This is accomplished using just one keyword, after-auto, over the Manual NAT configuration already discussed above.

On an ASA where a current rule resides in Section 3, like this lab ASA, it is imperative to delete the current rules and reconfigure them with the after-auto keyword. Otherwise the old command never gets over written and the after-auto command will not be shown in the configuration at all.
ASA Configuration

ASA1(config)# no nat (inside,outside) source dynamic obj_192.168.13.0 interface
ASA1(config)# no nat (inside,dmz1) source dynamic obj_192.168.13.0 interface
ASA1(config)# nat (inside,outside) after-auto source dynamic obj_192.168.13.0 interface
ASA1(config)# nat (inside,dmz1) after-auto source dynamic obj_192.168.13.0 interface

The results are obvious in both the configuration and operational verification:

Verification

ASA1(config)# sho run nat
!
object network obj_192.168.13.0_outside
 nat (inside,outside) dynamic interface
object network obj_192.168.13.0_dmz1
 nat (inside,dmz1) dynamic interface
!
nat (inside,outside) after-auto source dynamic obj_192.168.13.0 interface
nat (inside,dmz1) after-auto source dynamic obj_192.168.13.0 interface

ASA1(config)# sho nat detail 

Auto NAT Policies (Section 2)
1 (inside) to (dmz1) source dynamic obj_192.168.13.0_dmz1 interface  
    translate_hits = 0, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.34.3/24
2 (inside) to (outside) source dynamic obj_192.168.13.0_outside interface  
    translate_hits = 0, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.23.3/24

Manual NAT Policies (Section 3)
1 (inside) to (outside) source dynamic obj_192.168.13.0 interface  
    translate_hits = 0, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.23.3/24
2 (inside) to (dmz1) source dynamic obj_192.168.13.0 interface  
    translate_hits = 0, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.34.3/24

Looking at the two outputs above, the problem should be obvious. If the intention was to NAT the packets using Manual NAT, then this configuration is deemed a failure. The packet tracer output illustrates this further:

Packet Tracer Verification
ASA1# packet-tracer input inside tcp 192.168.13.1 10000 192.168.23.2 23 

Phase: 1
Type: ACCESS-LIST
Subtype: 
Result: ALLOW
Config:
Implicit Rule
Additional Information:
MAC Access list

Phase: 2
Type: ROUTE-LOOKUP
Subtype: input
Result: ALLOW
Config:
Additional Information:
in   192.168.23.0    255.255.255.0   outside

Phase: 3
Type: IP-OPTIONS
Subtype: 
Result: ALLOW
Config:
Additional Information:

Phase: 4      
Type: NAT
Subtype: 
Result: ALLOW
Config:
object network obj_192.168.13.0_outside
 nat (inside,outside) dynamic interface
Additional Information:
Dynamic translate 192.168.13.1/10000 to 192.168.23.3/30999

Phase: 5
Type: IP-OPTIONS
Subtype: 
Result: ALLOW
Config:
Additional Information:

Phase: 6
Type: FLOW-CREATION
Subtype: 
Result: ALLOW
Config:
Additional Information:
New flow created with id 1, packet dispatched to next module
              
Result:
input-interface: inside
input-status: up
input-line-status: up
output-interface: outside
output-status: up
output-line-status: up
Action: allow
Caveat: Even though the ASA allows for the configuration of identical unmapped blocks (192.168.13/24) in Sections 1/3 and Section 2, during operation, the rule that takes precedence is the one that is used for the actual translation.

This does not cause trouble in the above scenario as all of the configured rules are performing the same translation. In the case where the rules in Section 3 were using a different mapped IP, however, the configuration would be deemed as misconfigured.

Results (Just for completeness)
R1#telnet 192.168.23.2
Trying 192.168.23.2 ... Open

R2#who
Line         User    Host(s)     Idle       Location
0 con 0              idle      00:05:15
* 98 vty 0           idle      00:00:00   192.168.23.3

Interface    User        Mode         Idle     Peer Address 

R2#exit

[Connection to 192.168.23.2 closed by foreign host]
R1#telnet 192.168.34.4
Trying 192.168.34.4 ... Open

R4#who
Line         User    Host(s)     Idle       Location
0 con 0              idle      00:04:34
* 98 vty 0           idle      00:00:00   192.168.34.3

Interface    User        Mode         Idle     Peer Address 

Dynamic PAT to a Non-ASA IP

This scenario is almost exactly the same as the previous one. For this reason, the packet tracer portion of the verification is skipped.

Using Network Object NAT

Once again, a separate object has to be created for each external interface for reasons discussed in the previous section. Other than that, the mapped IP address is stated in place of the interface keyword.

An object that contains the mapped IP as a host statement can also be used. Using just a mapped IP inside the network object makes for slightly less configuration and subjectively, a little more readability.

Instead of a subnet statement, a range statement is used in this example for demonstration purposes.
ASA Configuration

ASA1(config)#object network obj_192.168.13.0-13.50
ASA1(config-network-object)# range 192.168.13.1 192.168.13.50
ASA1(config-network-object)# nat (inside,any) dynamic 192.168.33.3

Since there is no restriction placed on the external interface now, the use of the any keyword is shown. This configuration will translate packets going out of either the Outside or DMZ interfaces to 192.168.33.3.

Verification

ASA1# sho run nat
!
----SNIP----
object network obj_192.168.13.0-13.50
 nat (inside,any) dynamic 192.168.33.3
!

ASA1# sho nat detail 

Auto NAT Policies (Section 2)
1 (inside) to (any) source dynamic obj_192.168.13.0-13.50 192.168.33.3  
    translate_hits = 0, untranslate_hits = 0
    Source - Origin: 192.168.13.1-192.168.13.50, Translated: 192.168.33.3/32
2 (inside) to (dmz1) source dynamic obj_192.168.13.0_dmz1 interface  
    translate_hits = 2, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.34.3/24
3 (inside) to (outside) source dynamic obj_192.168.13.0_outside interface  
    translate_hits = 3, untranslate_hits = 0
    Source - Origin: 192.168.13.0/24, Translated: 192.168.23.3/24

Manual NAT Policies (Section 3)
----SNIP----
One thing that should be noted here is that the newest object has floated its way to the top of Section 2. The reason for this is that the IP block inside this object contains 50 addresses while each of the other blocks contains 254 IPs.
Caveat: For Auto NAT or NON, the order displayed in show run nat is different than the order shown in show nat. While show run nat shows the statements in the order of configuration, show nat shows the actual order of how the packets are matched against the statements. This is different than Section 1 and Section 3 where the orders are consistent between the two commands.
Result
R1#telnet 192.168.23.2
Trying 192.168.23.2 ... Open

R2#who
Line         User    Host(s)     Idle       Location
0 con 0               idle     00:00:32
* 98 vty 0            idle     00:00:00   192.168.33.3

Interface    User        Mode         Idle     Peer Address 

R2#exit

[Connection to 192.168.23.2 closed by foreign host]
R1#telnet 192.168.34.4
Trying 192.168.34.4 ... Open

R4#who
Line         User    Host(s)     Idle       Location
0 con 0               idle     00:00:30
98 vty 0              idle     01:42:35    192.168.34.3
* 99 vty 1            idle     00:00:00    192.168.33.3

Interface    User        Mode         Idle     Peer Address 

Using Manual NAT

With Manual NAT, there is no option of using the host IP address without an object for this scenario. Therefore, an object must be created for the mapped IP before the NAT can be configured.

As discussed in the first blog post of the series, the section where the statement will be placed is entirely up to the administrator and depends on many factors including current NAT configuration on the ASA and the logic used to match packets.

As an example, if the goal was to use the same range as used in the NON example above but translate those addresses to a different IP, there are two considerations. If one chose to delete the NON entry (as would be the norm in production networks), then the Manual NAT statement can be placed in either section with impunity. If, however, one were asked not to delete the NON entry (a typical CCIE lab scenario), then the only option would be to place the statement in Section 1. One can derive the reasoning by reading the discussion so far in this series.

Configuration

ASA1(config)# object network obj_192.168.33.33
ASA1(config-network-object)# host 192.168.33.33           
ASA1(config-network-object)# exit
ASA1(config)# nat (inside,any) source dynamic obj_192.168.13.0-13.50 
obj_192.168.33.33

Without the keyword after-auto, this statement should have been placed in Section 1, thus getting precedence over the existing NON statement.

Verification

ASA1(config)# sho run nat
nat (inside,any) source dynamic obj_192.168.13.0-13.50 obj_192.168.33.33
!
object network obj_192.168.13.0_outside
 nat (inside,outside) dynamic interface
object network obj_192.168.13.0_dmz1
 nat (inside,dmz1) dynamic interface
object network obj_192.168.13.0-13.50
 nat (inside,any) dynamic 192.168.33.3
!
nat (inside,outside) after-auto source dynamic obj_192.168.13.0 interface
nat (inside,dmz1) after-auto source dynamic obj_192.168.13.0 interface
ASA1(config)# 
ASA1(config)# sho nat
Manual NAT Policies (Section 1)
1 (inside) to (any) source dynamic obj_192.168.13.0-13.50 obj_192.168.33.33  
    translate_hits = 0, untranslate_hits = 0

Auto NAT Policies (Section 2)
1 (inside) to (any) source dynamic obj_192.168.13.0-13.50 192.168.33.3  
    translate_hits = 2, untranslate_hits = 0
2 (inside) to (dmz1) source dynamic obj_192.168.13.0_dmz1 interface  
    translate_hits = 0, untranslate_hits = 0
3 (inside) to (outside) source dynamic obj_192.168.13.0_outside interface  
    translate_hits = 0, untranslate_hits = 0

Manual NAT Policies (Section 3)
1 (inside) to (outside) source dynamic obj_192.168.13.0 interface  
    translate_hits = 0, untranslate_hits = 0
2 (inside) to (dmz1) source dynamic obj_192.168.13.0 interface  
    translate_hits = 0, untranslate_hits = 0
ASA1(config)# 

Packet tracer can again be utilized to see which statement will handle the translation. For brevity, that output is skipped and instead the telnet verification method is shown. Simply put, if R2 and R3 see R1’s IP as 192.168.33.33 and not 192.168.33.3, then it is the Manual NAT statement that is translating the traffic.

Results
R1#telnet 192.168.23.2
Trying 192.168.23.2 ... Open

R2#who
Line         User    Host(s)     Idle       Location
0 con 0               idle     00:25:22
* 98 vty 0            idle     00:00:00   192.168.33.3

Interface    User        Mode         Idle     Peer Address 

R2#
R2#exit

[Connection to 192.168.23.2 closed by foreign host]
R1#telnet 192.168.34.4
Trying 192.168.34.4 ... Open

R4#who
Line         User    Host(s)     Idle       Location
0 con 0               idle     00:26:07
* 98 vty 0            idle     01:42:35   192.168.33.3

Interface    User        Mode         Idle     Peer Address 

Leave a Reply

 

Nick Kelly

Cybersecurity Engineer, Cisco

Nick has over 20 years of experience in Security Operations and Security Sales. He is an avid student of cybersecurity and regularly engages with the Infosec community at events like BSides, RVASec, Derbycon and more. The son of an FBI forensics director, Nick holds a B.S. in Criminal Justice and is one of Cisco’s Fire Jumper Elite members. When he’s not working, he writes cyberpunk and punches aliens on his Playstation.

 

Virgilio “BONG” dela Cruz Jr.

CCDP, CCNA V, CCNP, Cisco IPS Express Security for AM/EE
Field Solutions Architect, Tech Data

Virgilio “Bong” has sixteen years of professional experience in IT industry from academe, technical and customer support, pre-sales, post sales, project management, training and enablement. He has worked in Cisco Technical Assistance Center (TAC) as a member of the WAN and LAN Switching team. Bong now works for Tech Data as the Field Solutions Architect with a focus on Cisco Security and holds a few Cisco certifications including Fire Jumper Elite.

 

John Cavanaugh

CCIE #1066, CCDE #20070002, CCAr
Chief Technology Officer, Practice Lead Security Services, NetCraftsmen

John is our CTO and the practice lead for a talented team of consultants focused on designing and delivering scalable and secure infrastructure solutions to customers across multiple industry verticals and technologies. Previously he has held several positions including Executive Director/Chief Architect for Global Network Services at JPMorgan Chase. In that capacity, he led a team managing network architecture and services.  Prior to his role at JPMorgan Chase, John was a Distinguished Engineer at Cisco working across a number of verticals including Higher Education, Finance, Retail, Government, and Health Care.

He is an expert in working with groups to identify business needs, and align technology strategies to enable business strategies, building in agility and scalability to allow for future changes. John is experienced in the architecture and design of highly available, secure, network infrastructure and data centers, and has worked on projects worldwide. He has worked in both the business and regulatory environments for the design and deployment of complex IT infrastructures.