Network Segmentation Lab

Context and motivation

On a flat network, a compromised laptop at the front desk has the same route to the database as the administrator. Segmenting and denying by default is the textbook answer, and it leaves an uncomfortable question, how do you know that what you believe is blocked actually is. Reviewing rules by hand only checks the cases you think of.

Here the flows that should exist are declared in a single file, each with its reason written down, and two things come out of it, the firewall rules and the list of everything that must fail. That list is the cartesian product of sources, destinations and ports minus what's allowed, so it covers the combinations nobody would have thought to review.

Terraform brings up nine machines from scratch on a nested Proxmox VE 9 with 11 GB of RAM, the OPNsense firewall, four AlmaLinux servers with SELinux enforcing and four clients spread across the segments, one of them outside the perimeter to test web publishing and the VPN from the outside. Ansible installs BIND, PostgreSQL, Samba and Nginx idempotently, and a script syncs the firewall rules with the flows file through the API and warns if someone has touched them by hand.

Technologies

Proxmox VE 9TerraformAnsiblePython (pytest)AlmaLinux 9SELinuxWireGuard

Main features

  • 297 checks derived from 21 declared flows, 31 allows and 266 denies, all verified against the lab
  • 53 firewall rules generated from the flows file, with no drift between what's declared and what's applied
  • The tests never SSH into the network they're testing, they talk to the hypervisor and run inside each machine through a wrapper that first validates it belongs to the lab
  • A chaos command that inserts a permissive rule on purpose, runs the suite expecting to see it red, removes it and checks everything is green again
  • Idempotent playbook, second run with zero changes across the four servers and none in permissive mode
  • WireGuard VPN that reaches the management network and nothing else, verified from an external client
  • 22 issues documented with their diagnosis and their fix

Gallery

Conclusion

It's a lab and I say so in the repository. There's no high availability or intrusion detection, the credentials are throwaway and everything runs on nested virtualization. What it demonstrates is the network policy and its verification, not performance.

With everything up, the suite caught that guest clients could reach the DMZ website. The mistake was mine, I had translated going out to the Internet as destination `any`, and `any` includes the internal networks, so allowing browsing also opened the path to the other segments. The rule looked right and the intention was right. A hand-written deny list doesn't catch that, because nobody writes down the combination they haven't thought of.

Links

View code on GitHub