docs(hardening): fix nftables sketch + persist dedicated-server provisioning artifacts - #213
Merged
Conversation
`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>
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #212, from the same bare-metal Ubuntu 26.04 provisioning run.
The nftables fix
meta skuid != <agent> acceptnever 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, andstatsig.anthropic.comis recorded as having no A record — Claude Code's telemetry goes toapi.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:set -e/pipefaildeliberately — an address with no PTR madegetentfail, which killed the follower and lost events silently. Only destinations with reverse DNS ever alerted.example.com:80was being swallowed becauseexample.com:443had alerted minutes earlier.ufwis left alone;nftables.servicestays disabled so it cannot flush ufw's ruleset at boot.--userunit with218/CAPABILITIESwhileis-activestill reportsactive.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