↓ Skip to main content
  1. Blog/

Hardening the Home Lab, Part 1: Assume Something Gets In

Hardening the Home Lab - This article is part of a series.
Part 1: This Article

My home lab was never designed. It accreted. A weather station on a Raspberry Pi Zero, then an all-sky camera (also on a Raspberry Pi), then a handful of meteor cameras (all Pi model 4s), a soil temperature probe, a lightning detector, a whole host of environmental monitors, a Stevenson screen (all these are networked ESP32 devices making a sort of distributed weather/environmental monitoring station), and a Docker host in the middle running the message broker, the time-series database and the dashboards that tie it all together. Every new gadget went on the same network as everything else, because that was the easy thing to do and it worked.

Additionally, other things in the house are on the network, such as a network connected TV box and so on.

It still works. That’s the problem: nothing about a flat home network tells you it’s fragile until the day it is. So this series is about rebuilding it on the assumption that, sooner or later, something on it will be compromised.

The threat I’m actually worried about
#

I’m not expecting a skilled human to sit down and target my garden sensors. The threat I care about is duller and more likely: something worm-like. It gets a foothold on the cheapest, least-maintained device on the network, then looks around, finds the next thing it can get into, and repeats.

Most home labs have an obvious first foothold. Typically it’s one of these:

  • An IoT device with an old firmware build, a web interface nobody remembers is switched on, or an over-the-air update endpoint protected by a shared password.
  • A message broker that, out of the box, lets anything on the network publish and subscribe without logging in.
  • A container that has the Docker socket mounted into it, which is root on the host in all but name.
  • SSH keys copied onto every machine years ago, which never expire and which nobody could list from memory.
  • Or some other weak point on the network such as a rogue network connected TV or fridge (no, my fridge is not on the internet!).

None of those is exotic. What has changed is who, or what, exploits them. Automated tooling has always been good at the boring part: scanning, trying default credentials, working through a list. AI agents make it good at the next part as well, reading what it finds and working out what to try next. It doesn’t need to be clever, just patient and cheap, and it doesn’t get bored.

On a flat network, that changes the maths. The whole network is only as strong as its weakest device, because once something is inside, every other device is one hop away and nothing is checking credentials at the door.

The goal: make every device a dead end
#

So rather than trying to make every device impregnable (I’d fail, and so would you), the plan starts from a different assumption: one device will fall, and when it does, it should be a dead end.

That breaks down into four principles, which the rest of this series keeps coming back to:

  1. Contain. Split the network so a compromised device can only reach the handful of things it genuinely needs.
  2. Least privilege. Each device gets its own credentials, with permission to do its one job and nothing else. A weather sensor can publish weather; it can’t read or write anyone else’s data.
  3. Credentials that expire. Anything long-lived and copied around is a liability. Short-lived certificates you can stop issuing beat static keys you have to hunt down.
  4. Notice. If something does go wrong, I want to hear about it from my own monitoring, not find out months later.

Here’s the shape of the change. Before, one flat network where anything can talk to anything:

flowchart LR
  A1[ESP32 sensors] --- H1[Docker host]
  A2[Pi cameras] --- H1
  A3[Desktop & laptop] --- H1
  A1 --- A2
  A2 --- A3
  A1 --- A3

After, zones with doors between them. Each zone only gets the specific doors it needs, and the guest zone, for devices I don’t manage, gets none into my kit at all:

flowchart LR
  I[IoT zone
sensors, cameras] -- "named services only" --> T[Trusted zone
servers, desktops] T -- "management" --> I G[Guest zone
devices I don't manage] -. "no access" .-x T G -. "no access" .-x I

The plan
#

These are the seven steps, in priority order. Each one gets its own post.

#StepWhat it meansWhy it matters
1Network segmentationSeparate VLANs for trusted machines, IoT devices and guests, with the router’s firewall deciding what crosses between themA compromised sensor can no longer even see most of the network
2Message broker authenticationEvery device logs in with its own username, and access rules limit it to its own topicsThe broker is the one service every IoT device must reach, so it can’t be a free-for-all
3ESPHome hardeningA per-device checklist: no web server, no native API, unique update and fallback passwords, data over MQTT onlyShrinks each microcontroller down to the one thing it’s for
4Protect the Docker hostAudit which containers can reach the Docker socket, and keep Docker’s own networks from colliding with real onesThe host running everything is the prize; it gets the most care
5Router hygieneFirmware current, UPnP off, nothing exposed that doesn’t need to beBoring, essential, easy to forget
6Configuration managementAnsible for every Linux host, with SSH access through short-lived certificates from a small certificate authorityConsistent machines, and access I can revoke in one place
7DetectionPatch monitoring, drift audits against a known-good baseline, and alerts to my phoneSo I notice when something changes that I didn’t change

Steps 1 to 3 are done together, one device at a time. There’s a practical reason for that: a Wi-Fi ESP32 has to be reflashed to move it onto a new VLAN anyway, so it might as well come back with its hardened configuration and its own broker credentials in the same flash. Touch each device once, and leave it finished.

Keeping track of it all
#

A project like this generates a lot of decisions, and a few of them get revisited. The guest network ended up on a different VLAN number than planned, for example, because the router’s built-in guest network did the job better than a hand-rolled one.

To stop myself working from stale ideas, I keep a single “source of truth” document for the network: current decisions only, a list of open questions, and a section for superseded decisions with a one-line reason each. Anything that proposes doing it differently has to argue against that document, not quietly replace it. It’s been surprisingly useful, and I’ll write about it properly another time.

Next time
#

Before carving a network up, you need to know what’s on it. Part 2 covers building an inventory: a small scanning script that keeps a spreadsheet of every device up to date, and getting every device a sensible, consistent name.

Hardening the Home Lab - This article is part of a series.
Part 1: This Article

Related