|
| 1 | +--- |
| 2 | +name: tailssh |
| 3 | +description: > |
| 4 | + Set up permanent passwordless SSH into someone else's Mac over Tailscale — the exact playbook |
| 5 | + from the Kai's-laptop run (2026-07-10). Fires on "/tailssh", "set up ssh to <person>'s |
| 6 | + laptop/computer", "onboard <person>'s machine", "add <person> to tailscale", "make ssh <alias> |
| 7 | + work for <person>'s machine", or when the user is at (or coordinating with) a friend's/client's |
| 8 | + Mac and wants permanent remote access from their own Mac. Covers: Tailscale device share |
| 9 | + (one-directional), ~/.ssh/config alias, ssh-copy-id key install, end-to-end verification — and |
| 10 | + generates a plain-English instructions doc the machine owner can follow solo. |
| 11 | +user_invocable: true |
| 12 | +allowed-tools: Bash, Read, Edit, Write |
| 13 | +--- |
| 14 | + |
| 15 | +# tailssh — passwordless `ssh <name>` into someone's Mac over Tailscale |
| 16 | + |
| 17 | +End state: `ssh <alias>` from the user's Mac lands on the other person's Mac with no password, |
| 18 | +over Tailscale, with zero access granted in the reverse direction. |
| 19 | + |
| 20 | +## Security model (lead with this if the user hesitates) |
| 21 | + |
| 22 | +- **The share is one-directional.** Their device gets shared TO the user's tailnet. The user can |
| 23 | + reach that one machine; the machine's owner cannot see or reach any of the user's machines. |
| 24 | +- **Only the PUBLIC key lands on their Mac** (`~/.ssh/authorized_keys`). It's a lock, not a key — |
| 25 | + it lets the user in, it grants nothing back. The private key never leaves the user's machine. |
| 26 | +- **Their password auth stays on.** This setup stops the *user* from needing the password; it does |
| 27 | + not weaken or change how the owner logs in. |
| 28 | +- Direction check: putting THEIR key on the user's machine would be the reverse grant. Never do it. |
| 29 | + |
| 30 | +## Intake — ONE combined ask |
| 31 | + |
| 32 | +1. Alias for `ssh <alias>` (default: their first name, lowercase). |
| 33 | +2. Their macOS username (`whoami` on their machine — NOT their display name). |
| 34 | +3. Are you sitting at their machine now, or handing them instructions? (hand-off → generate the doc) |
| 35 | + |
| 36 | +Share-invite email defaults to `nate@lorecraft.io` — confirm silently unless it's clearly not Nate. |
| 37 | + |
| 38 | +## Phase 1 — on THEIR machine |
| 39 | + |
| 40 | +If handing off: fill `references/instructions-template.md` placeholders (`<OWNER>`, `<REQUESTER>`, |
| 41 | +`<EMAIL>`, `<ALIAS>`) and save to `~/Desktop/ssh-setup-<alias>.md` for AirDrop. If present in |
| 42 | +person, walk through live: |
| 43 | + |
| 44 | +1. **Remote Login ON** — System Settings → General → Sharing → Remote Login. Off by default on |
| 45 | + most Macs; skipping this is the #1 cause of "Connection refused" later. |
| 46 | +2. **Install Tailscale** — https://tailscale.com/download (or Mac App Store). |
| 47 | +3. **Sign in with THEIR OWN account** (Google/Apple/email — anything). They do not join the |
| 48 | + user's account or tailnet. |
| 49 | +4. **Share the device** — login.tailscale.com → Machines → this machine → **⋯ → Share** → enter |
| 50 | + the user's email → send invite. |
| 51 | +5. **Capture their username** — `whoami` in Terminal on their machine. |
| 52 | + |
| 53 | +## Phase 2 — on the USER'S machine |
| 54 | + |
| 55 | +1. **Accept the share invite** from the email link. The device appears as a shared node. |
| 56 | +2. **Get its Tailscale IP** (100.x.y.z) — `tailscale status` or the accept page / admin console. |
| 57 | +3. **Add the alias** — Read `~/.ssh/config` first, preserve everything, append: |
| 58 | + ``` |
| 59 | + Host <alias> |
| 60 | + HostName <100.x.y.z> |
| 61 | + User <their-username> |
| 62 | + ``` |
| 63 | +4. **Install the key** — interactive password prompt, so it must run in the user's own terminal, |
| 64 | + never through the agent's Bash tool. In Claude Code, tell them to run: |
| 65 | + ``` |
| 66 | + ! ssh-copy-id <alias> |
| 67 | + ``` |
| 68 | + They type the owner's password once. No keypair yet? `ssh-keygen -t ed25519` first. |
| 69 | +5. **Verify** (agent runs these): |
| 70 | + ```bash |
| 71 | + ssh -G <alias> | grep -E '^(hostname|user) ' |
| 72 | + ssh -o PasswordAuthentication=no -o BatchMode=yes <alias> true && echo PASS |
| 73 | + ``` |
| 74 | + PASS = done. Report both results. |
| 75 | + |
| 76 | +## Troubleshooting |
| 77 | + |
| 78 | +| Symptom | Fix | |
| 79 | +|---|---| |
| 80 | +| Connection refused | Remote Login off on their Mac (Phase 1 step 1) | |
| 81 | +| Timeout / no route | Tailscale not running on one side (`tailscale status`), or invite not accepted | |
| 82 | +| Still asks for password | ssh-copy-id didn't land — rerun; on their Mac check `chmod 700 ~/.ssh`, `chmod 600 ~/.ssh/authorized_keys` | |
| 83 | +| Permission denied | Wrong `User` — must be `whoami` output on their machine | |
| 84 | + |
| 85 | +Tailscale 100.x IPs are stable for the life of the node; if MagicDNS is on you can use |
| 86 | +`<machine>.<tailnet>.ts.net` as `HostName` instead — optional, not required. |
| 87 | + |
| 88 | +## Rules |
| 89 | + |
| 90 | +- Never place the other person's key on the user's machine. |
| 91 | +- Never change sshd config / disable password auth on their machine — not ours to harden. |
| 92 | +- All password entry happens in the user's own terminal (`!` prefix), never via agent Bash. |
| 93 | +- Read `~/.ssh/config` before editing; append, don't rewrite. |
0 commit comments