fix(firewall): skip the host firewall on Proxmox
Proxmox VE and Proxmox Mail Gateway are Debian, so os_detect classified them as debian and harden-firewall.sh installed the iptables backend on top of pve-firewall. The conflict is not the obvious one. pve-firewall does NOT delete third-party rules: it restores with `iptables-restore -n` (--noflush), only ever flushes chains matching its own patterns (PVEFW-*, tapNiM-*, vethNiM-*, fwbrN-*, GROUP-*), appends `-A INPUT -j PVEFW-INPUT` only when that hook is missing, and never sets a built-in chain's policy. Our rules survive it. We are the ones doing damage: - `-P INPUT DROP` is ours alone, and PVEFW-HOST-IN RETURNs on accept rather than ACCEPTing (it still has to check tap rules), so traffic Proxmox explicitly allowed falls out of its chain onto our DROP -- we silently override the platform's own accepts. - netfilter-persistent restores at boot with a full iptables-restore (no --noflush), wiping PVE's hook along with everything else until the daemon re-appends it ~10s later. - a deny-by-default chain has to enumerate the whole platform to stay usable: 8006, 5405-5412/udp corosync, 60000-60050, 5900-5999, 3128, 22, 111/udp, plus Ceph when hyperconverged -- and `-i lo`, or pveproxy loses pvedaemon on :85. - under the nftables backend (PVE 8.2+) an nft DROP beats an iptables ACCEPT, so our rules would not even be authoritative. So don't manage a firewall there at all: - oslib: is_proxmox() -- matches hosts shipping pve-firewall (VE/PMG), not PBS. - harden-firewall.sh: a third backend, "pve", that deliberately does nothing. apply explains and exits 0, allow/deny refuse loudly rather than fake success for a rule they didn't add, list shows pve-firewall status. It overrides an explicit FW_BACKEND; FW_IGNORE_PVE=1 is the one escape hatch. - harden-ssh.sh / harden-jumphost.sh: skip the firewall and install the standalone INPUT -> sshguard boot hook instead. That jump is safe alongside pve-firewall -- inserted with -I, it sits ahead of the appended PVEFW-INPUT hook and keeps first look at NEW connections. Detection only helps hosts built from here on, so `disable` cleans up one that was hardened earlier: it detects leftovers (and says which signal fired), sets INPUT ACCEPT *before* flushing so it can't drop the SSH session it runs over, deletes /etc/firewall and the engine, disables boot restore and renames the saved rulesets aside rather than persisting the open state, re-adds the sshguard jump, and restarts pve-firewall. `apply` points at it when it spots leftovers. Documented plainly that skipped is NOT protected: Proxmox's firewall is off by default (cluster-wide enable defaults to 0, and the daemon tears its chains down every ~10s while it is), so these hosts have no host firewall until someone enables it -- and the node panel's "Firewall: Yes" is ignored while the datacenter one says No. Also: svc_disable + fw_restore_services/fw_saved_files in oslib (fw_enable_restore now derives from the former), and usage() prints the whole header block instead of a hardcoded line range. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -285,6 +285,20 @@ EOF
|
||||
# standalone boot hook. Otherwise fall back to the minimal init-agnostic boot
|
||||
# hook that just (re)inserts the jump at every boot.
|
||||
: "${ENABLE_FIREWALL:=1}"
|
||||
# Proxmox (VE/PMG) is Debian underneath, but pve-firewall already owns the host
|
||||
# ruleset -- harden-firewall.sh skips those hosts, so fall through to the boot
|
||||
# hook and keep sshguard's jump. That jump is safe there: pve-firewall restores
|
||||
# with --noflush and only ever flushes its own PVEFW-* chains, and the hook it
|
||||
# adds to INPUT is APPENDED -- so a jump inserted with -I sits ahead of it and
|
||||
# keeps getting first look at NEW connections, firewall enabled or not.
|
||||
# FW_IGNORE_PVE=1 forces our firewall anyway.
|
||||
if [[ "$ENABLE_FIREWALL" == "1" && "${FW_IGNORE_PVE:-0}" != "1" ]] && is_proxmox; then
|
||||
warn "Proxmox detected -- pve-firewall owns the host firewall; installing only the sshguard jump hook."
|
||||
# A host hardened before the skip existed still has a live DROP chain that only
|
||||
# accepts the OLD port -- changing SSH_PORT here would lock you out of it.
|
||||
[[ -x /usr/local/sbin/firewall-apply || -d /etc/firewall ]] && warn " This host still has an older harden-firewall.sh ruleset. Run 'harden-firewall.sh disable' FIRST, especially if you are changing SSH_PORT."
|
||||
ENABLE_FIREWALL=0
|
||||
fi
|
||||
if [[ "$ENABLE_FIREWALL" == "1" && -f "$SCRIPT_DIR/harden-firewall.sh" ]]; then
|
||||
log "Installing host firewall (deny-by-default INPUT; carries the sshguard jump)..."
|
||||
SSH_PORT="$SSH_PORT" OPEN_PORTS="${OPEN_PORTS:-}" \
|
||||
|
||||
Reference in New Issue
Block a user