Skip to content

docs(hardening): fix nftables sketch + persist dedicated-server provisioning artifacts - #213

Merged
robercano merged 2 commits into
mainfrom
docs/nftables-skuid-fix
Aug 4, 2026
Merged

docs(hardening): fix nftables sketch + persist dedicated-server provisioning artifacts#213
robercano merged 2 commits into
mainfrom
docs/nftables-skuid-fix

Conversation

@robercano

Copy link
Copy Markdown
Owner

Follow-up to #212, from the same bare-metal Ubuntu 26.04 provisioning run.

The nftables fix

meta skuid != <agent> accept never matches kernel-generated packets — ICMPv6 MLD/ND and DHCP renewal carry no owning socket — so they fell through to the drop rule. Observed live: MLD listener reports (TYPE=131) from the box's own link-local address were dropped and alarmed on. The sketch now jumps on a positive UID match, so only packets the agent actually owns are filtered.

Also corrected in the same block: link-local multicast is dropped without the log prefix (mDNS is discovery noise, and an alarm that cries wolf gets ignored), the v6 set and the lo/established rules the sketch omitted are added, and statsig.anthropic.com is recorded as having no A record — Claude Code's telemetry goes to api.statsig.com / statsigapi.net / events.statsigapi.net / featureassets.org.

The artifacts

examples/dedicated-server/ carries the working files — nftables fence, egress alarm, auditd rules, divergence tripwire, systemd drop-in — with a README recording the reasoning, which is the part that cost the time:

  • The fence restricts protocol/port, not destination. IP-set allowlisting was built, tested and abandoned: GitHub rotates within its fleet and Google LBs serve addresses no DNS snapshot tracks, so it dropped real work. And since HARDENING.md already lists GitHub as a sanctioned exfil channel, an allowlist that must include GitHub could never have closed that path.
  • The alarm avoids set -e/pipefail deliberately — an address with no PTR made getent fail, which killed the follower and lost events silently. Only destinations with reverse DNS ever alerted.
  • Cooldown keys on destination and portexample.com:80 was being swallowed because example.com:443 had alerted minutes earlier.
  • ufw is left alone; nftables.service stays disabled so it cannot flush ufw's ruleset at boot.
  • The systemd drop-in is the user-unit-safe subset — the full block crash-loops a --user unit with 218/CAPABILITIES while is-active still reports active.

Three layers on this run looked correct in their configuration and did nothing in practice. The README's verification section tests each rather than reading it.

🤖 Generated with Claude Code

robercano and others added 2 commits August 4, 2026 12:50
`meta skuid != <agent> accept` never matches kernel-generated packets --
ICMPv6 MLD/ND and DHCP renewal carry no owning socket -- so they fell through
to the drop rule. Observed live: MLD listener reports (TYPE=131) from the
box's own link-local address were dropped and alarmed on. Restructure to jump
on a positive UID match, so only packets the agent actually owns are filtered.

Also from the same run: drop link-local multicast WITHOUT the log prefix
(mDNS/MLD is discovery noise, and an alarm that cries wolf gets ignored);
add the v6 set and the lo/established rules the sketch omitted; and record
that statsig.anthropic.com has no A record -- Claude Code's telemetry goes to
api.statsig.com / statsigapi.net / events.statsigapi.net / featureassets.org.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Working files from a real provisioning run on bare-metal Ubuntu 26.04, so the
next box does not rebuild them from the sketches in HARDENING.md: nftables
egress fence, egress alarm, auditd rules, divergence tripwire, and the
user-unit-safe systemd drop-in.

The README records the reasoning, which is the part that cost time:

- The fence restricts protocol/port, not destination. IP-set allowlisting was
  built, tested and abandoned -- GitHub and Google LBs rotate faster than a
  DNS refresh can track, and it dropped real work. HARDENING.md already lists
  GitHub as a sanctioned exfil channel, so an allowlist that must include
  GitHub could never close that path anyway.
- Jump on a positive skuid match; `skuid != <uid> accept` never matches
  kernel-generated packets and silently filters the host's own stack.
- The alarm runs as root, keys its cooldown on destination AND port, and
  deliberately avoids `set -e`/`pipefail` -- an address with no PTR made
  getent fail and killed the follower, losing events silently.
- ufw is left alone; nftables.service stays disabled so it cannot flush it.
- The systemd drop-in is the user-unit-safe subset; the full block crash-loops
  a --user unit with 218/CAPABILITIES.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@robercano robercano self-assigned this Aug 4, 2026
@robercano
robercano merged commit 0e2c23b into main Aug 4, 2026
9 checks passed
@robercano
robercano deleted the docs/nftables-skuid-fix branch August 4, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant