Files
mac/.claude/handoffs/2026-09-15-203133-mac-ssh-aliases.md
T
Mortdecai c204d99dc6 docs: session handoff — ssh aliases + two-key split
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 20:32:28 -04:00

8.7 KiB

Handoff: ssh aliases + two-key split (mac)

Session Metadata

  • Created: 2026-09-15 20:31:33
  • Project: /home/claude/bin/mac
  • Branch: master
  • Session duration: ~30 min

Recent Commits (for context)

  • 2028508 feat(ssh): full homelab alias set on the Mac + separate interactive key
  • 43877eb docs(checklist): kitty needs the Local Network grant — else LAN ssh = No route to host
  • dc29b7a docs: session handoff — kitty titlebar fix
  • 3399829 fix(kitty): keep macOS titlebar — it's the only drag handle; color it to match bg
  • d86ede0 docs: session handoff — mac base setup shipped & verified

Handoff Chain

Review the previous handoff for full context before filling this one.

Current State Summary

Seth asked for ssh aliases on the Mac. config/ssh_homelab already existed with 6 hosts, but the Mac's only key (id_ed25519) is rrsync-jailed on pve173, so ssh pve173 would have hit the jail and nothing else was authorized. Shipped: the curated alias set from ~/bin/CLAUDE.md (pve nodes, machines, key CTs, switch, tailscale hosts), a second key id_ed25519_homelab for interactive use (Host * default), backup.sh pinned to the jailed key, and scripts/authorize-mac-key.sh (runs on steel141, pushes the interactive pubkey via claude's aliases, wired into run.sh). Applied without a full run.sh: rsync + keygen over ssh + the authorize script. 12 aliases verified from the Mac as the right user@host; jail proven with id; backup.sh ran clean. Five hosts were offline and did not get the key. Committed + pushed (2028508).

Codebase Understanding

Architecture Overview

  • ~/.ssh/config on the Mac is ONE line: Include ~/mac/config/ssh_homelab. The repo file is the whole config; Host * at its bottom is the default block (first-obtained-wins semantics).
  • Two-key design: id_ed25519 (seth@mac) = backup only, jailed by restrict,command="/usr/bin/rrsync /tank/backups/mac" on pve173 line 19; id_ed25519_homelab = interactive, unrestricted everywhere. sshd matches the FIRST authorized_keys line per key, so a single key cannot serve both roles on pve173.
  • Proxmox nodes share /etc/pve/priv/authorized_keys (root's ~/.ssh/authorized_keys is a symlink) — one append covers all four nodes; that's why the push printed [set] pve112 then [skip] for the rest.

Critical Files

File Purpose Relevance
config/ssh_homelab all aliases + Host * defaults edit here, then rsync -a config/ssh_homelab mac:mac/config/; must stay mode 600 (ssh refuses a group-writable Include)
scripts/authorize-mac-key.sh pushes the interactive pubkey to LAN hosts from steel141 idempotent; re-run for hosts that were offline
scripts/backup.sh nightly rsync -o IdentitiesOnly=yes -i $HOME/.ssh/id_ed25519 pins the jailed key; do not drop it
scripts/setup.sh generates both keys [skip] on rerun
DECISIONS.md two-key rationale, alias-set scope, bedroom=root

Key Patterns Discovered

  • Config-only tweaks: rsync the file, don't run run.sh (it installs/removes a temp sudoers drop-in).
  • Remote one-liners take data via env in the command string (PUB='$PUB' H=$H bash -s with the script on stdin) — same trick as tank-side.sh; avoids ssh re-splitting the key line.
  • rrsync whitelists true as a connectivity ping (if command == 'true': sys.exit(0)). A jail check must use id, not truetrue returning 0 looked like a broken jail and cost a diagnosis loop.

Work Completed

Tasks Finished

  • config/ssh_homelab: full curated alias set, Host * -> id_ed25519_homelab, StrictHostKeyChecking accept-new
  • id_ed25519_homelab generated on the Mac (setup.sh now does this; ran the same keygen by hand)
  • backup.sh pins the jailed key; verified jail (id refused) and backup run (exit 0, Documents on tank)
  • scripts/authorize-mac-key.sh written, run: key on all 4 pve nodes, vdj-rig, caddy, rtorrent, emby, mcsmanager, pihole, arr, steel141 (seth)
  • 12 aliases verified from the Mac (ssh <alias> 'whoami@hostname')
  • DECISIONS.md + CLAUDE.md updated; committed + pushed

Files Modified

File Changes Rationale
[no modified files detected]

Decisions Made

Decision Options Considered Rationale
Second key rather than re-keying the backup (a) rename existing key to _backup + regenerate default; (b) add id_ed25519_homelab (b): no migration, no change to run.sh's tank-side push, server side untouched
bedroom alias user seth -> root keep seth (previous session, undocumented) matches steel141's alias + CLAUDE.md table; avoids a sudo special-case in the push. One-word revert if Seth wants seth
Alias scope = CLAUDE.md curated table, not claude's full ~/.ssh/config mirror everything nixos/thinkpad-nano/mortdec-auth/vast are stale or claude-only
StrictHostKeyChecking accept-new (not no) no like steel141 TOFU still detects later key changes; same zero-prompt first connect

Pending Work

Immediate Next Steps

  1. When bedroom / thinkcentre / seth-pi / pinail / openclaw2 are powered on: scripts/authorize-mac-key.sh from steel141 (idempotent, prints [set]/[skip]/[FAIL] per host).
  2. Confirm with Seth that bedroom as root is what he wants from the Mac.
  3. Carried from previous handoffs: Seth relaunches kitty; docs/manual-checklist.md; install Ableton Live 12 then scripts/run.sh --no-tank; audio interface + AC session test.

Blockers/Open Questions

  • yoga / bebop aliases are dead until Tailscale is logged in on the Mac (manual-checklist item); their authorized_keys were not touched.
  • switch alias is password-only by design (TP-Link); needs sshpass on the Mac if Seth wants it non-interactive (not installed).

Deferred Items

  • Gitea ssh access from the Mac (git@git.sethpc.xyz) — not asked; would need the homelab pubkey added in Gitea, not authorized_keys.
  • Keys for rosy / matt-strix — other people's boxes, not Seth's call to make from here; aliases intentionally omitted.
  • Carried: SparkFun PPP service, Tailscale GUI login, AeroSpace, NSWindowShouldDragOnGesture.

Context for Resuming Agent

Important Context

Do NOT collapse the two keys back into one. If ssh pve173 from the Mac ever lands in rrsync error: ... does not run rsync, the homelab key is missing from pve173's authorized_keys — run authorize-mac-key.sh, don't touch the jailed line. If backup.sh ever gets an unjailed root shell (test: ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@192.168.0.173 id must be REFUSED), the -i pin in backup.sh was lost. true is NOT a valid jail test — rrsync allows it. This session's machine changes: one new key on the Mac, config/ssh_homelab + scripts/backup.sh rsynced, pubkey appended on the hosts listed above, seth@steel141 authorized_keys appended via sudo.

Assumptions Made

  • Seth wants root on pve nodes/CTs and his own user on his machines (mirrors how claude's aliases are documented).
  • The five offline hosts are just powered down, not decommissioned (bedroom/thinkcentre/seth-pi/pinail/openclaw2 all still in CLAUDE.md).

Potential Gotchas

  • rsync -a carries file mode: config/ssh_homelab must be 600 locally or the Mac's ssh silently ignores the Include (Bad owner or permissions).
  • authorize-mac-key.sh uses claude's steel141 aliases, which have the SAME names as the Mac's — easy to confuse which side you're on. It only runs from steel141.
  • sudo -u seth bash -c sets HOME to /home/seth on steel141 (verified) — ~/.ssh in the shared one-liner resolves correctly.

Environment State

Tools/Services Used

  • ssh mac (192.168.0.94, key auth). OpenSSH 10.0p2 on the Mac. gitea push. sudo -n on steel141 (passwordless, used for seth's authorized_keys).

Active Processes

  • Nothing new. Backup launchd agent unchanged (next run 03:30 uses the pinned key — first unattended run with the new -e string; check /tank/backups/mac next day).

Environment Variables

  • None used. (HOMELAB_PASSWORD still required for run.sh; authorize-mac-key.sh needs none.)
  • Previous handoff: .claude/handoffs/2026-09-15-200354-kitty-titlebar-fix.md (kitty relaunch still pending) and 2026-09-15-194209-mac-setup-shipped.md (machine state).
  • DECISIONS.md (two-key entry), ~/bin/CLAUDE.md ssh alias table (source of the alias set), scripts/tank-side.sh (how the jail line is written).

Security Reminder: Before finalizing, run validate_handoff.py to check for accidental secret exposure.