Add a default-deny nftables ruleset for the fips0 mesh interface as
a packaged operator asset, with a companion fips-firewall.service
oneshot unit for systemd hosts. Both are shipped disabled — the
baseline is an operator conffile and the unit is intentionally not
enabled in postinst. Activation is an explicit one-liner:
sudo systemctl enable --now fips-firewall.service
This is deliberate: silently mutating host firewall state on package
install is hostile across the axes that matter (collisions with
existing operator nftables / Docker / OPNsense rulesets, surprise
behaviour for hosts that already filter elsewhere, conversion of an
explicit security decision into an invisible one). The opt-in
posture preserves operator agency.
The baseline closes a real default-exposure gap: any service on a
mesh host bound to a wildcard address (0.0.0.0 or [::]) is
reachable from every authenticated peer in the mesh by default.
Identity on the mesh is the peer's npub but identity is not
authorization, and the mesh is closer to a shared LAN than to the
public internet. With this filter loaded, the surface is closed
unless a drop-in opens it explicitly.
Baseline shape:
- Early-return for non-fips0 traffic (every other firewall left
undisturbed)
- conntrack established/related accept (replies to outbound flows)
- ICMPv6 echo-request accept (ping6 reachability)
- include "/etc/fips/fips.d/*.nft" — operator-supplied allowances
- counter drop default
The accompanying docs/fips-security.md lays out the threat model
(npub-authenticated mesh is closer to a shared LAN than to the
public internet — identity is not authorization), the activation
workflow, drop-in extension recipes (allow inbound SSH from a
specific peer fd97:.../128, allow HTTP from one /64, etc), drop
visibility / debugging via the journal log rule and the drop
counter, coexistence with the runtime-managed `inet fips_gateway`
table, what the baseline does NOT cover (outbound, application
auth, mesh handshake ACL = PR #50 / IDEA-0047 territory), and
future cross-OS work (macOS PF baseline, OpenWrt fw4, gateway
abstraction).
Packaging:
- packaging/common/fips.nft → /etc/fips/fips.nft (conffile)
- packaging/debian/fips-firewall.service → /lib/systemd/system/
- docs/fips-security.md → /usr/share/doc/fips/
- postinst creates /etc/fips/fips.d/ (mode 0755) on configure
- prerm stops/disables fips-firewall.service on remove/purge
OpenWrt fw4 path and macOS PF baseline are deferred — separate
asymmetries, separate work.
Debian packaging via cargo-deb:
- Add [package.metadata.deb] to Cargo.toml with assets, dependencies,
and conffiles declarations
- Maintainer scripts: postinst (create fips group, enable services,
restart on upgrade), prerm (stop/disable on remove, stop-only on
upgrade), postrm (purge config, keys, group)
- Systemd units (fips.service, fips-dns.service) with /usr/bin/ paths
for .deb installs
- tmpfiles.d entry for /run/fips/ runtime directory
- build-deb.sh wrapper script for building packages
README rewrite:
- Replace run-from-source Quick Start with Building section
- Add Installation options: Debian .deb (cargo-deb) and generic Linux
(systemd tarball)
- Add full Configuration reference with default fips.yaml
- Add Usage sections: DNS resolution, monitoring (fipsctl + fipstop),
service management, and testing
- Update project structure and features list