Hairpin NAT and a Partner That Whitelists Only One ISP Address
A USG6000E at HQ provides Internet access to 1,200 staff and publishes an internal CRM at 203.0.113.25:443 through a NAT Server to 10.10.30.40:443. External users reach the CRM correctly. Internal staff who type the public URL fail, while the same staff reach the CRM fine by its private address. Two ISP links exist: ISP-A (500 Mbit/s, primary default route) and ISP-B (100 Mbit/s, floating static with preference 80, local address 192.0.2.10). Outbound translation is a single Easy IP rule in the trust→untrust interzone using address-group ISP-A-POOL. A new SaaS partner at 198.51.100.0/24 accepts connections only from 192.0.2.10, so that destination must both leave via ISP-B and be translated to the ISP-B address. The customer's DNS is external and split-horizon DNS is not available in this project phase.
1. Explain precisely why internal users fail when they use the public address, and give the fix with its side effects.
Read the worked answer
This is the classic NAT Server hairpin problem, and the give-away is that the private address works - so routing, policy and the server itself are healthy.
What happens: the client sends a packet to 203.0.113.25. The firewall's NAT Server translates the destination to 10.10.30.40 and forwards it into the DMZ. The server sees a source address of 10.10.x.x, so its reply is sent to its default gateway - or directly on the same subnet - and never traverses the firewall. There is no session for that return direction, so it is dropped and the client sees a timeout or reset. Externally, source NAT hides the client behind a public address and the return path happens to be correct, which is why only internal users are affected.
Fix: add source NAT for the hairpin flow. Create a NAT policy rule matched on zone trust → zone trust (or on destination 203.0.113.25) that translates the source to an address the CRM will route back through the firewall - typically the trust-side interface address or a dedicated loopback. Because NAT policy matching uses the pre-translation packet, the rule must match the public destination 203.0.113.25, not the private one, and it must sit above the Easy IP rule so it wins.
Side effects to state explicitly: the CRM logs will now show translated addresses instead of real client IPs for internal users, and per-user auditing on that server degrades; the hairpin flow consumes sessions and CPU on the same chassis; and the rule must be mirrored in the HA peer. Split-horizon DNS remains the cleaner long-term answer because it removes the hairpin entirely.
2. Design the change that forces 198.51.100.0/24 out of ISP-B with the ISP-B source address. What ordering and matching traps must you avoid?
Read the worked answer
Two mechanisms are needed, because routing and translation are decided independently.
1. Steering. A floating static with preference 80 loses to the ISP-A default, so the partner prefix needs policy-based routing: a traffic policy that matches destination 198.51.100.0/24 (optionally also the internal server subnets that must use it) and sets the next hop to the ISP-B gateway. Apply it to the trust-side inbound direction. If the ISP-B link is down, the PBR action must not black-hole the traffic - either rely on an NQA/ip-link track that withdraws the policy, or accept a documented hard failure.
2. Translation. Add a NAT policy rule above the Easy IP rule, matched on destination 198.51.100.0/24, translating source to the ISP-B address 192.0.2.10 (a one-address group, not Easy IP, so the address does not follow the egress interface). If Easy IP is left as the only rule, the partner will receive ISP-A-sourced packets on an ISP-B path and drop them.
Traps to avoid: NAT policy is evaluated on the original packet, so matching on 'outbound interface' will not help - match on destination. PBR is also evaluated on the pre-NAT packet, so the two rules must agree on the same match criteria or you will get translated-but-misrouted (or routed-but-untranslated) traffic. Verify with display ip routing-table, the PBR hit counters, display firewall session table verbose for the translated addresses, and a source-address check at the partner side. Confirm the ASA/partner ACL accepts the whole /24 as destinations while only 192.0.2.10 as source.