Network isolation: egress firewall + named bridge
Adds the host-level egress firewall recommended by the upstream DeerFlow team's "run in a VLAN" guidance, adapted to a Fritzbox-only home network where LAN VLANs are not available. - docker/docker-compose.override.yaml: pins the upstream deer-flow Docker network to a stable Linux bridge name br-deerflow so the firewall can address it without guessing Docker's auto-generated br-<hash>. Used as a -f overlay on top of the upstream compose file. - scripts/deerflow-firewall.sh: idempotent up/down/status wrapper that installs DOCKER-USER iptables rules. Allowlist for 10.67.67.1 (Searx) and 10.67.67.2 (XTTS/Whisper/Ollama-local), hard block for 192.168.3.0/24 (home LAN), 10.0.0.0/8, 172.16.0.0/12. Stateful return rule keeps inbound LAN access to published ports working. - scripts/deerflow-firewall.nix: NixOS module snippet defining a systemd unit ordered After=docker.service so the rules survive dockerd restarts and follow its lifecycle. Copy into configuration.nix and nixos-rebuild switch. - HARDENING.md: new section 2.7 "Network isolation (egress firewall)" with allow/block tables, bring-up steps, and smoke-test commands. Guarantees: rules match on -i br-deerflow, so if the bridge does not exist, the rules are no-ops and do not affect any other container (paperclip, telebrowser, openclaw-gateway, ...). Stopping the container leaves the rules in place but inert; stopping the systemd unit removes them.
This commit is contained in:
49
scripts/deerflow-firewall.nix
Normal file
49
scripts/deerflow-firewall.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
# NixOS module snippet for the DeerFlow egress firewall.
|
||||
#
|
||||
# Copy the systemd.services block below into your /etc/nixos/configuration.nix
|
||||
# (or import this file from there). After `sudo nixos-rebuild switch`, the
|
||||
# unit `deerflow-firewall.service` is started automatically after Docker and
|
||||
# stays "active (exited)" so the rules persist for the lifetime of dockerd.
|
||||
#
|
||||
# Activation order:
|
||||
# docker.service -> deerflow-firewall.service
|
||||
#
|
||||
# The unit pulls the script straight from the repo at
|
||||
# /home/data/deerflow-factory/scripts/deerflow-firewall.sh — change the path
|
||||
# below if you check the repo out somewhere else.
|
||||
#
|
||||
# Disable / remove:
|
||||
# sudo systemctl stop deerflow-firewall # rules go down
|
||||
# sudo systemctl disable deerflow-firewall # no auto-start
|
||||
# ...then remove the block from configuration.nix and rebuild.
|
||||
#
|
||||
# Verify:
|
||||
# systemctl status deerflow-firewall
|
||||
# sudo /home/data/deerflow-factory/scripts/deerflow-firewall.sh status
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
systemd.services.deerflow-firewall = {
|
||||
description = "DeerFlow container egress firewall";
|
||||
|
||||
# Make sure dockerd has created the DOCKER-USER chain before we touch it,
|
||||
# and rerun the unit when docker restarts so our rules are reapplied.
|
||||
after = [ "docker.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
partOf = [ "docker.service" ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
path = [ pkgs.iptables pkgs.iproute2 pkgs.bash ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
|
||||
# Adjust this path if you store the repo elsewhere.
|
||||
ExecStart = "/home/data/deerflow-factory/scripts/deerflow-firewall.sh up";
|
||||
ExecStop = "/home/data/deerflow-factory/scripts/deerflow-firewall.sh down";
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user