Files
esh-pfi-infrastructure/services/sudo-io-archive
vh d3f59aa2c5 feat(albok): move albok-service to a dedicated VM, nh3-albok (VM 110 on nh3-pve-2)
albok-service leaves nh3-docker before unit 4 puts the personal vault and
licensed books into restricted wings. On nh3-docker, portainer, portainer_agent,
dockge (socket rw) and dockerd on plaintext tcp/2375 were each root over
/srv/albok. The new host runs only albok-service: no socket containers and no
TCP Docker API, so its Homepage tile is a static services.yaml entry.

- nh3-pve-2: vmbr0 made VLAN-aware (applied by reboot, no guests running);
  pbs-ana storage in the new namespace nh3-pve-2, plus a 21:30 vzdump job
  (pbs-nh3's recursive sync mirrors it)
- VM 110 nh3-albok, 10.100.50.44 on VLAN 50, Debian 13 cloud-init, 4 vCPU
  x86-64-v3 / 12 GiB / 100 GB; built to fleet conventions (vh 1000,
  infra-ops 850, docker 851)
- compose: mem_limit 4g -> 8g, homepage labels removed; host port 8392 kept
- cutover by tar stream, verified by digest (contents plus owner, group, mode,
  mtime and type identical); albok.nh3.internal now points at nh3-albok
- old /srv/albok stays on nh3-docker (container removed, compose renamed)
  until acceptance and the operator's approval to delete it
- sudo-io archive hosts and ops-log STACK_HOSTS include nh3-albok
2026-10-04 23:33:24 -07:00
..

sudo-io-archive — fleet sudo session recordings: archive, back up, clear

Every /etc/sudoers.d/infra-ops carries Defaults:infra-ops log_output, so sudo records each infra-ops session (command line, timing, stdin/stdout/stderr) under /var/log/sudo-io/XX/YY/ZZ, with no retention. fv-ml1 had 16 G and esh-docker-vm 15 G by 2026-10-04. Prime: "those audits should be archived and backed up, then cleared. That should be a regular thing."

What runs

  • Weekly, Sunday 05:40 PT: sudo-io-archive.timer → sudo-io-archive.service (nh3-dev user units, installed from this folder into ~/.config/systemd/user/). A failure pages infra-ops via althing-notify-failure@.
  • Collector sudo-io-archive (nh3-dev): for each host in hosts, asks the host to pack every session older than 30 days (SUDO_IO_DAYS), pulls the archive, checks sha256 + gzip integrity, keeps it as ~/archive/sudo-io/<host>/<host>-<UTC stamp>-older-than-30d.tar.gz (+ .sha256, mode 600), then tells the host to delete exactly what it archived. One ops-log line per host.
  • Host side sudo-io-archive-host.sh, streamed over ssh into sudo -n bash -s, phases pack <days>, commit <sha256>, status. Works under /var/log/sudo-io-archive/ (outbox, list, cutoff).

Safety properties

  • A session is eligible only when nothing in it changed after the cutoff, so running sessions are never touched.
  • The host deletes nothing until the collector has the archive and has matched its sha256. Removal is tar --remove-files over the same list the archive was built from (no rm on a variable; the list is refused if any entry is absolute or contains ..). A failed run leaves the host's logs and outbox; the next run re-ships it.
  • The archives are covered by nh3-dev's backup: VM 102 is in nh3-pve's nightly vzdump to pbs-ana, mirrored to pbs-nh3.

Run by hand

services/sudo-io-archive/sudo-io-archive                  # all hosts
services/sudo-io-archive/sudo-io-archive fv-ml1           # one host
ssh infra-ops@<ip> 'sudo -n bash -s -- status' < services/sudo-io-archive/sudo-io-archive-host.sh

Replay an archived session: untar it anywhere, then sudoreplay -d <dir> <XX/YY/ZZ> (as root).

Bulk data is not kept (Prime 2026-10-04: "we don't need to durably back up weights and rsyncs forever")

Almost all of the volume was DATA piped through sudo, not commands: a 14.45 G recording of sudo tar -C /tank/aimodels -cf - erp-tune-v6-nvfp4a16 on fv-ml1, a ~380 M sudo rsync --server --sender of the Home Assistant volume every night on esh-docker-vm, Worldtree volume rsyncs on corviduo-dev, a docker save. Three layers now keep it out:

  1. Not recorded. Every infra-ops sudoers file carries a BULK_DATA exemption (rsync, tar, cat, dd, zstd, zcat, gzip, pv, docker save|export|cp): Defaults!BULK_DATA !log_output. sudo still logs who ran the command; it no longer records the bytes. playbooks/sudoers-infra-ops-bulk-no-log-output.yaml rolled it out to all 19 recording hosts on 2026-10-04 (controls on each: sudo id adds a session, sudo tar --version does not), and playbooks/bootstrap-infra-ops-user.yaml writes it for new hosts.
  2. Not archived. pack leaves out any stdout/stdin/tty stream over 64 MiB (the session's log, log.json, timing and stderr are still archived) and commit deletes it with the rest. Proven with a labelled 70 MB test session (TE/ST/OV in the 2026-10-04 pfi-pteradactyl archive).
  3. Pruned once (2026-10-04). The 36 existing bulk streams on hosts (≈31 G: fv-ml1 15 G, esh-docker-vm 15 G, corviduo-dev, nh3-dev, nh3-docker) were deleted with literal-path rm, keeping each session's metadata, and the three collected archives that held bulk streams were rebuilt without them (*-bulk-pruned.tar.gz; the store went from 4.8 G to 83 M).

Lessons kept in the scripts: pull the outbox WITHOUT sudo (sudo ≥ 1.9.14 truncated piped output, and log_output re-recorded the archive); read the host list on fd 3 (ssh swallowed it from stdin); GNU tar reads -X NUL-separated under --null and only honours it BEFORE -T. Each of those was caught by a check, not by luck.