NAT'ing on the firewall versus host routes for public IPs

April 7, 2024

In a comment on my entry on solving the hairpin NAT problem with policy based routing, Arnaud Gomes suggested an alternative approach:

Since you are adding an IP address to the server anyway, why not simply add the public address to a loopback interface, add a route on the firewall and forgo the DNAT completely? In most situations this leads to a much simpler configuration.

This got me to thinking about using this approach as a general way to expose internal servers on internal networks, as an alternative to NAT'ing them on our external firewall. This approach has some conceptual advantages, including that it doesn't require NAT, but unfortunately it's probably significantly more complex in our network environment and so much less attractive than NAT'ing on the external firewall.

There are two disadvantages of the routing approach in an environment like ours. The first disadvantage is that it probably only works easily for inbound connections. If such an exposed server wants to make outgoing connections that will appear to come from its public IP, it needs to explicitly set the source IP for those connections instead of allowing the system to chose the default. Potentially you can solve this on the external firewall by NAT'ing outgoing connections to its public IP, but then things are getting complicated, since you can have two machines generating traffic with the same IP.

The second disadvantage is that we'd have to establish and maintain a collection of host source routes in multiple places. Our core router would need the routes, the routing firewall each such machine was behind would need to have the route, and probably we'd want other machines and firewalls to also have these host routes. And every time we added, removed, or changed such a machine we'd have to update these routes. We especially don't like to frequently update our core router precisely because it is our core router.

The advantage of doing bidirectional NAT on our external firewall for these machines is the reverse of these issues. There's only one place in our entire network really has to know about which internal machine is which public IP. Of course this leaves us with the hairpin NAT problem and needing split horizon DNS, but those are broadly considered solved problems, unlike maintaining a set of host routes.

On the other hand, if we already had a full infrastructure for maintaining and updating routing tables, the non-NAT approach might be easy and natural. I can imagine an environment where you propagate route announcements through your network so that everyone can automatically track and know where certain public IPs are. We'd still need firewall rules to allow only certain sorts of traffic in, though.


Comments on this page:

From 193.219.181.219 at 2024-04-08 01:17:07:

There are two disadvantages of the routing approach in an environment like ours. The first disadvantage is that it probably only works easily for inbound connections. If such an exposed server wants to make outgoing connections that will appear to come from its public IP, it needs to explicitly set the source IP for those connections instead of allowing the system to chose the default.

Linux allows you to set a source IP address hint on routes, so you could have this setup mostly working by adding 'src x.y.z.t' or PreferredSource=x.y.z.t to your default route definition.

The second disadvantage is that we'd have to establish and maintain a collection of host source routes in multiple places. Our core router would need the routes, the routing firewall each such machine was behind would need to have the route, and probably we'd want other machines and firewalls to also have these host routes. And every time we added, removed, or changed such a machine we'd have to update these routes. We especially don't like to frequently update our core router precisely because it is our core router.

That would usually be done by running OSPF or Babel on the routers and firewalls (or I guess modern cloud stuff would prefer BGP?), rather than updating the routes by hand. There are plenty of opportunities for things to go wrong, but it's still a different kind of beast than "ansible deploy a fresh config + reload everything".

Written on 07 April 2024.
« GNU Autoconf is not replaceable in any practical sense
Don't require people to change 'source code' to configure your programs »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Sun Apr 7 22:38:19 2024
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.