Files
mac/.claude/handoffs/2026-09-15-203133-mac-ssh-aliases.md
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

136 lines
8.7 KiB
Markdown

# 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
- **Continues from**: [2026-09-15-200354-kitty-titlebar-fix.md](./2026-09-15-200354-kitty-titlebar-fix.md)
- Previous title: kitty titlebar fix (mac)
- **Supersedes**: None
> 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 `true``true` returning 0 looked like a broken jail and cost a diagnosis loop.
## Work Completed
### Tasks Finished
- [x] `config/ssh_homelab`: full curated alias set, `Host *` -> `id_ed25519_homelab`, `StrictHostKeyChecking accept-new`
- [x] `id_ed25519_homelab` generated on the Mac (setup.sh now does this; ran the same keygen by hand)
- [x] `backup.sh` pins the jailed key; verified jail (`id` refused) and backup run (exit 0, `Documents` on tank)
- [x] `scripts/authorize-mac-key.sh` written, run: key on all 4 pve nodes, vdj-rig, caddy, rtorrent, emby, mcsmanager, pihole, arr, steel141 (seth)
- [x] 12 aliases verified from the Mac (`ssh <alias> 'whoami@hostname'`)
- [x] 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.)
## Related Resources
- 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.