Skip to main content
IT BIBLESign in

Blog / Networking

Writing Firewall Rules for a Homelab IoT VLAN, One Allow at a Time

Creating a VLAN takes five minutes. The firewall rules are the real work. Here is the rule order I use for an IoT VLAN, how I test it, and the parts I'm still unsure about.

PriyaInTheCloset
· 4 min read · Networking
Writing Firewall Rules for a Homelab IoT VLAN, One Allow at a Time

Photo by Jakub Żerdzicki on Unsplash

Creating a VLAN is the easy part. You add a tag, a subnet, a DHCP scope, and an SSID. The segmentation only exists once the firewall rules do, and that is where I keep seeing (and making) mistakes. A VLAN with an allow-any rule is just a second flat network with extra steps.

This post covers how I'm structuring rules for an IoT VLAN on OPNsense. The logic should carry over to pfSense, since both are stateful and evaluate rules the same basic way. I'm describing the pattern, not exact menu paths, because those move between versions. I haven't finished migrating every device, so treat this as a working method.

The model: default deny, then explicit allows

On both platforms, a new interface with no rules blocks inbound traffic from that segment. That is the behavior I want. I start there and add one allow at a time, each tied to a reason I can write down.

Two things to keep in mind:

  • Rules apply to traffic entering the interface. An IoT rule describes what IoT devices may initiate, not what may reach them.
  • The firewall is stateful. If a laptop on the trusted VLAN opens a connection to a device on the IoT VLAN, the replies are allowed automatically. I don't need a rule for the return path.

The second point matters for the design. Direction of initiation is the whole question. Who is allowed to start a conversation with whom?

My example layout

These are placeholder IDs and subnets, not my real ones:

VLAN  Name    Subnet           Purpose
10    trusted 10.10.10.0/24    laptops, phones
20    iot     10.10.20.0/24    cameras, plugs, TV
30    guest   10.10.30.0/24    visitors, internet only
40    lab     10.10.40.0/24    VMs, test services
99    mgmt    10.10.99.0/24    switch, hypervisors, firewall UI

The management network is the one I care most about protecting. Nothing on IoT or guest should ever reach it, and only one or two admin devices on trusted should.

Rule order on the IoT interface

First match wins within an interface, so order is part of the design. This is the sequence I'm using:

1. Allow  UDP/TCP 53   iot net -> firewall/resolver address
2. Allow  UDP 123      iot net -> firewall address (NTP)
3. Allow  (specific)   iot net -> Home Assistant host, only needed ports
4. Block               iot net -> alias: RFC1918 private ranges
5. Allow  any          iot net -> any (internet)

The reasoning for each line:

  • DNS to the resolver only. I point IoT DHCP at my Pi-hole or Unbound address. A device with a hardcoded public resolver can still bypass it by going out through rule 5, so if I want to enforce DNS, I need a block rule for port 53 to anywhere else placed before the final allow. I haven't decided whether I want that. Some devices behave badly when their hardcoded DNS is blocked.
  • NTP. Cheap devices often want a time source. Giving them the firewall keeps them from phoning out for it.
  • Specific allows to services I run. If a device needs to talk to Home Assistant, I allow that host and those ports. Not the whole trusted VLAN.
  • Block RFC1918. An alias containing the private ranges means the IoT VLAN cannot reach any internal network that rule 3 did not explicitly permit. This is the line that makes it a real segment.
  • Allow the internet last. Because the block sits above it, "any" effectively means "anything that is not internal."

Put rule 4 above rule 3 and you break the Home Assistant allow. Put rule 5 above rule 4 and you've built nothing. I have done the second one. The traffic still worked, which is what made it easy to miss.

The rules going the other way

Trusted devices need to reach IoT devices sometimes, for example to open a camera stream or cast to a TV. I allow trusted to IoT on specific ports instead of everything. Because of statefulness, the devices answer without any IoT-side rule.

The awkward part is discovery. mDNS and similar multicast protocols do not cross VLAN boundaries on their own. Casting and some smart-home pairing depend on them. Both platforms have a way to relay mDNS (a plugin or package, depending on the firewall), but I'm still testing how well it works with my devices, and I'd rather not oversell it. Where a device supports it, adding it by IP in the app avoids discovery altogether.

Testing from inside the VLAN

I don't trust a ruleset I only read. From a machine on the IoT VLAN (a spare Pi works), I run a short check:

#!/usr/bin/env bash
# Run from a host in the IoT VLAN. Expect: PASS on allows, BLOCKED on denies.
check() {
  local label=$1 host=$2 port=$3
  if timeout 3 bash -c "</dev/tcp/$host/$port" 2>/dev/null; then
    echo "OPEN     $label ($host:$port)"
  else
    echo "BLOCKED  $label ($host:$port)"
  fi
}

check "internet"       1.1.1.1      443
check "home assistant" 10.10.40.20  8123
check "nas"            10.10.10.5   445
check "hypervisor UI"  10.10.99.10  8006
check "firewall UI"    10.10.99.1   443

I expect OPEN for the first two and BLOCKED for the rest. Then I check the firewall's live log view to confirm the blocks hit the rule I think they hit. A block from the wrong rule is a bug waiting for the next change.

The script only covers TCP, so it says nothing about UDP rules. That is a gap I know about.

Not breaking the household

The partner acceptance factor is real. If the TV stops working, nobody cares that the design is correct. My approach:

  • Move one device at a time, not the whole house.
  • Keep the old SSID up until the new one has run cleanly for a while.
  • Write down which devices need which ports as I find out, so the rules end up documented.
  • Export the firewall config before each batch of changes, so rollback is a restore and not a memory test.

Still open

I'm unsure about three things. How aggressively to force DNS through the resolver. Whether the mDNS relay is worth its complexity or I should just add devices by IP. And whether to log every block, which gets noisy fast.

How do you handle discovery across VLANs? Did you enforce DNS for IoT, and what broke when you did? And do you keep the IoT allow list in the firewall only, or mirror it somewhere version-controlled?

networkingvlanopnsense
Share

Sign in to comment.