An IPsec VPN with LibreSwan
A VPN is one of those things that feels like magic until you build one. I set up a site-to-site IPsec tunnel between two gateways with LibreSwan so that two hosts which could not see each other at all ended up able to talk, with every packet between them encrypted on the wire. This is the same kind of tunnel that links offices and clouds, just shrunk down to four VMs.
The setup
Four VMs in a line. The two on the ends are the hosts that want to talk; the two in the middle are the VPN gateways running LibreSwan. By default the end hosts are on different subnets with no route to each other, so they cannot ping at all. The job of the tunnel is to bridge that gap without touching the rest of the network.
Certificates in the NSS database
The two gateways authenticate to each other with X.509 certificates rather than a shared password. I created a certificate authority, signed a certificate for each gateway, and loaded them into the NSS certificate database that LibreSwan reads from. The same CA signs both ends, so each gateway can verify the other's certificate. With the certificates in NSS, the config only has to name the certificate by its nickname and LibreSwan pulls the key material itself.
Bringing up the tunnel
Each gateway gets an ipsec.conf connection describing its own public
address, the subnet sitting behind it, and the certificate to authenticate with.
Forwarding is enabled on both gateways, and each end host gets a single route pointing
the far subnet at its local gateway:
# on the gateways
echo 1 > /proc/sys/net/ipv4/ip_forward
# on the end hosts, route the far subnet via the local gateway
ip route add <far-subnet> via <local-gateway>
Starting the connection runs the IKEv2 negotiation between the gateways, and
ipsec status reports the tunnel as active on both sides. At that point the
two end hosts can ping each other and pull files from the web server, even though no
underlying route between their subnets was ever added; the traffic is being carried
inside the tunnel.
Seeing the encryption
Capturing the link between the two gateways is the payoff. The ICMP echo packets do not
appear as ICMP at all, they show up as ESP packets, the Encapsulating
Security Payload that IPsec uses to carry encrypted traffic. The original packet,
addresses and all, is wrapped inside an encrypted ESP packet between the gateways and
only unwrapped once it reaches the far side. You can see that something is flowing, but
not what.
Restricting what the tunnel carries
A tunnel that carries everything is blunt, so the last step was a traffic selector. By
pinning the connection to tcp/80 on both gateways, only web traffic to the
server is allowed into the tunnel and everything else is left out. It is the same
least-privilege idea as a firewall rule, expressed as part of the VPN policy itself:
the tunnel exists for exactly one service and nothing more.
Why it stuck
I have connected to plenty of VPNs without thinking about what happens at the gateway. Building both ends, watching two hosts that genuinely could not reach each other start exchanging pings, and then seeing those pings as opaque ESP packets in a capture, is what turned IPsec from a checkbox into something I understand the shape of.