Files
nix-config-ryan4yin/modules/nixos/base/networking/firewall.nix
T
ryan4yin | 二花 3acb5d4ee5 fix(nfs,libvirt): restrict the golden export and bind VNC to loopback (#400)
* fix(nfs): restrict the golden export to its real clients

* fix(libvirt): bind VNC consoles to loopback

* fix(firewall): drop VNC ports on every host

* docs(security): record the NFS and VNC boundaries
2026-10-07 15:10:52 +08:00

59 lines
2.3 KiB
Nix

{ lib, myvars, ... }:
let
inherit (myvars.networking) lanCidr;
# The host that scrapes the exporters (VictoriaMetrics runs on youko).
monitoringHost = myvars.networking.hostsAddr.youko.ipv4;
in
{
# Hosts bring their own firewall as defence in depth behind the router's
# (which stays on, with port mappings for the few ports we need): the home
# LAN and the tailnet are trusted equally (tighten the tailnet with Tailscale
# ACLs), and everything else is denied on both address families.
networking.nftables.enable = true;
networking.firewall = {
enable = true;
# Nothing is opened to the Internet. LAN/tailnet/local-container access
# comes from the rules below; per-service `openFirewall` ports are
# suppressed.
allowedTCPPorts = lib.mkForce [ ];
allowedUDPPorts = lib.mkForce [ ];
extraInputRules = ''
# node_exporter is scraped only by the monitoring host, not the whole
# LAN/tailnet/local containers.
ip saddr != ${monitoringHost} tcp dport 9100 drop
# The NVIDIA GPU exporter (desktop only) is likewise scraped only by the
# monitoring host.
ip saddr != ${monitoringHost} tcp dport 9835 drop
# smartctl_exporter (drive/SSD SMART health) is scraped only by the
# monitoring host.
ip saddr != ${monitoringHost} tcp dport 9633 drop
# Monitoring uses the stable IPv4 address above. Deny IPv6 exporter
# connections before broad LAN/tailnet/container trust can accept them;
# this does not restrict other IPv6 services or loopback access.
meta nfproto ipv6 tcp dport { 9100, 9835, 9633 } drop
# VNC consoles (libvirt on the VM hosts, and x11vnc inside the guests)
# are never exposed to the LAN, tailnet, or containers: reach them
# through an SSH tunnel. Loopback is accepted by the firewall's own rule.
tcp dport { 5900, 5901, 5902, 5903, 5910 } drop
# The local container bridge and the tailnet have the same access as the
# LAN. Kept after the drop above so neither can reach node_exporter.
iifname "podman0" accept
iifname "tailscale0" accept
# The home LAN is the trusted core.
ip saddr ${lanCidr} accept
ip6 saddr fe80::/10 accept
# Tailscale's WireGuard port, for direct (non-DERP) connections.
udp dport 41641 accept
'';
};
}