Pakkit.net
← Back to blog

Security

IPv6 Has No NAT to Hide Behind

A lot of "security" on IPv4 networks is really just an accident of NAT — and the moment you give a host a routable IPv6 address, that accidental privacy is gone and your firewall intent has to be explicit.

  • Security
  • Networking
  • IPv6
  • Architecture

I wanted a friendlier way to reach a service I was running on an IPv6 address, and working through the options forced me to say out loud something that’s easy to forget: on IPv6, there is no NAT quietly hiding your hosts from the internet. A big chunk of what people treat as security on IPv4 networks is really a side effect of address translation, not a deliberate control. Take NAT away — which is exactly what a routable IPv6 address does — and you find out how much of your “private by default” was actually “private by accident.”

On IPv4, NAT was doing security work nobody assigned it

Most internal IPv4 lives in private ranges behind NAT. A host on 10.x or 192.168.x can’t be reached from the public internet not because someone wrote a rule, but because there’s no route to it — the translation layer only forwards connections that were initiated from inside, or that someone explicitly mapped. That’s a real barrier, and we leaned on it for years without admitting it.

The problem is it’s implicit. The host isn’t protected because of a policy; it’s protected because of an addressing accident. Nobody decided “this service should be unreachable from outside” — it just happened to be true, which means it can quietly stop being true the moment the addressing changes. Security that you didn’t choose is security you can’t rely on.

NAT was never a firewall. It just did a convincing impression of one, for free, until IPv6 stopped paying.

A routable IPv6 address is reachable by default

Give that same host a global IPv6 address and the math flips. IPv6 was designed to restore end-to-end addressing: every host gets a globally unique, routable address, and there’s no translation layer standing between it and the internet by default. That’s a feature — it’s the internet working the way it was supposed to — but it means reachability is now the default, and unreachability is the thing you have to create on purpose.

So the firewall stops being optional cleanup and becomes the actual control. On IPv6 your intent has to be explicit: this port is open to the world, that one only to a prefix, everything else denied. The good news is that’s better security than NAT ever gave you, because it’s a decision you made and can audit. The bad news is that if you carried over an IPv4 mindset — “it’s internal, so it’s fine” — you may have just published a service you thought was private.

Routable is not the same as reachable, and resolvable is neither

Working through how to expose the service cleanly, I had to keep three things separate that people blur together:

  • Resolvable — a name has a record pointing at the address. Costs nothing, proves nothing about access.
  • Routable — the address is globally unique and the internet could carry packets to it. True for a real public IPv6, false for one that only routes inside your own network.
  • Reachable — packets actually arrive and something is listening and the firewall allows it.

You need all three for a service to work from outside, and they fail independently. A name can resolve to an address nothing can route to. An address can be routable but firewalled shut. The reason this matters for security is the inverse: a service can be reachable when you only meant it to be resolvable, because on IPv6 “routable” came for free and you forgot to close the door.

Three ways to expose a service, three different risk postures

When I mapped out how to actually reach the thing, the options sorted into a clean range from “most exposed” to “least,” and choosing among them is the security decision:

  • Direct — a record straight to the host’s IPv6. Simplest, and the host’s real address is now public and reachable on whatever port you opened. Fine for something genuinely meant to be public; reckless for anything else, because the origin is exposed with no layer in front.
  • Reverse-proxied through an edge. A provider’s edge terminates TLS and forwards to your origin, so clients hit the edge, not your box. You get HTTPS, a hidden origin, and a place to attach protections. The catch: the origin still has to be reachable from that edge, so it has to be genuinely public, just no longer directly.
  • An outbound tunnel. A daemon on the host makes an outbound connection to a service that then routes traffic back through it. No inbound exposure at all — works even when the host isn’t publicly reachable — and it’s the natural place to bolt authentication in front. Most work to set up, least exposed.

There’s no universally right answer; there’s a right answer for how exposed you’re willing to be. The point is to choose deliberately instead of defaulting to “direct” because it was easiest.

Publishing is a security event, not a convenience

The trap I almost walked into: I had an unauthenticated service that was “safe” only because it was annoying to reach. The instant I gave it a nice name and a routable path, “annoying to reach” evaporated and “unauthenticated” was all that was left. A friendly URL in front of a wide-open service doesn’t add a door; it just hands out the address.

So the rule I came away with: treat making something easier to reach as making it easier to attack, and add the access control in the same change that adds the convenience — not in a follow-up you’ll forget. Put authentication in front before you share the link, not after someone finds it.

The bigger lesson outlasts IPv6. A lot of what we call security is really ambient friction — NAT, obscure ports, “nobody knows it’s there” — and ambient friction has a way of disappearing the moment you make something more usable. Real controls are the ones you chose and can point to. IPv6 just removes the comfortable illusion earlier than IPv4 did, which is a gift if you treat it like one. This is the same “security is architecture, not decoration” thread I keep pulling on; if you’re untangling exposure on your own v6 rollout, I’m easy to reach.