LIVE โ both laptops verified
๐ฏ Quick reference
When Aria needs the laptops
Aria SSHes via ssh mba or ssh mbp. First time in ~12h, you get a Tailscale auth URL โ tap on iPhone, Face ID, done. One tap covers both laptops for the next 12h.
Panic button (real incident)
iPhone โ Tailscale admin โ Machines โ m4max36gb โ โฏ โ Remove. Aria loses ALL SSH access within 30 seconds. Recovery requires physical/screen-share access to M4 + ~2 min.
Aria's sudo password locations
- MBA: 1Password item "Aria - MBA sudo"
- MBP: 1Password item "Aria - MBP sudo"
- Rotate quarterly
Check session lasts
~12 hours from the moment Topher taps the auth URL. After expiry, next SSH triggers fresh URL.
๐บ How the JIT flow works
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ M4 Max (Aria's host) โ
โ โ
โ ssh mba "command" โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Brew tailscaled (com.tailscale.tailscaled) โ โ
โ โ - holds Tailscale identity (topher@gmail.com) โ โ
โ โ - checks for valid check token โ โ
โ โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ negotiate via tailnet
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Tailscale coordination server โ
โ - evaluates SSH rule: src=topher@gmail.com, dst=autogroup:self, โ
โ users=[autogroup:nonroot, root], action=check โ
โ - if no valid check โ returns auth URL to caller โ
โ - if valid โ forwards SSH โ MBA/MBP โ
โโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโ
โ โ
โ (no valid check) โ (valid check)
โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Aria surfaces URL โ โ MBA (or MBP) sshd โ
โ to Topher in chat: โ โ - authenticates as 'aria' โ
โ "tap to approve" โ โ - runs requested command โ
โโโโโโโโโโโฌโโโโโโโโโโโโโโโ โ - sudo prompts for password โ
โ โ (from 1Password if needed) โ
โผ โ - nuclear cmds blocked at โ
โโโโโโโโโโโโโโโโโโโโโโโโโโ โ /etc/sudoers.d/ โ
โ iPhone Safari opens โ โ aria-deny-nuclear โ
โ โ Google sign-in โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ Face ID โ
โ โ check valid for 12h โ
โโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ Daily usage
๐งโ๐ป Topher โ When Aria needs to do something on a laptop
- Aria attempts SSH from M4. First time per ~12h window, Tailscale prompts for re-auth.
- Aria surfaces the auth URL in chat: "Need your approval โ tap this on your phone."
- Tap the URL on iPhone โ Safari opens โ Face ID through Google โ approve.
- Aria's next SSH attempt succeeds. All subsequent SSH for the next ~12h is silent.
~10 seconds when prompted; zero overhead otherwise
๐ค Aria โ When asked to do laptop ops
- Aria runs `ssh mba "command"` (or `ssh mbp "command"`) from M4.
- If check is valid โ command runs as `aria` user, returns output.
- If check expired โ SSH prints the auth URL โ Aria surfaces it to Topher and waits.
- For sudo work: Aria fetches the aria-on-MBA / aria-on-MBP password from 1Password, supplies via `sudo -S`.
Same session as ops conversation
โ๏ธ SSH config on M4
# === Aria JIT access (~/.ssh/config on M4) ===
# Gated by Tailscale SSH check mode + aria user with locked sudoers
Host mba topher-mba macbook-air
HostName 100.103.172.103
User aria
Host mbp jaime-mbp jaimes-macbook-pro
HostName 100.105.54.125
User aria Stored at ~/.ssh/config (mode 600). If the tailnet IP of a laptop changes (re-enrollment), update the HostName line.
๐ก Security model โ defense in depth
Network access
Control: Tailscale SSH `action: check`
Fails closed: If check token absent or expired, SSH attempt times out โ no port-22 attack surface exposed
Identity verification
Control: Tailscale IdP flow (Google OAuth + Face ID on iPhone)
Fails closed: If Topher doesn't tap, no check token issued, no SSH succeeds
User isolation
Control: Dedicated `aria` user on each laptop (UID 502, standard with admin group)
Fails closed: Aria's actions never run as `topher`/`jaime`; `last | grep aria` shows clean session history
Privilege escalation
Control: sudo requires password (stored in 1Password; no NOPASSWD)
Fails closed: Non-interactive sudo fails outright; interactive sudo requires fetching from 1Password
Destructive command guard
Control: `/etc/sudoers.d/aria-deny-nuclear` blocks dd, diskutil eraseDisk, nvram, rm -rf /
Fails closed: Even with correct sudo password, these commands return "user aria is not allowed to execute"
๐งช Verification โ all tests passed 2026-05-27
| Test | MBA | MBP | Notes |
|---|---|---|---|
| First SSH triggers Tailscale check URL | โ | โ | Both laptops require fresh tap when no check token present |
| Subsequent SSH within window is silent | โ | โ | ~12h check cached at the Tailscale coordination layer |
| One tap covers ALL owned devices | โ | โ | MBP SSH worked without fresh tap โ check keyed to source identity, not destination |
| sudo -n (no password) fails | โ | โ | "sudo: a password is required" |
| sudo + correct password + denied command blocked | โ | โ | "Sorry, user aria is not allowed to execute '/bin/dd...'" |
| sudo + correct password + allowed command succeeds | โ | โ | `sudo whoami` returns `root` |
| Panic button (Remove M4 in admin) cuts access in <30s | โ | โ | `Operation timed out` returned on next SSH |
๐จ Panic button โ three severity levels
๐ด Real incident (M4 suspected compromised)
Action: iPhone โ Tailscale admin โ Machines โ m4max36gb โ โฏ โ Remove
Blast radius: All Aria SSH dies within 30s. Rest of tailnet (NAS, M3, your phone) unaffected.
Recovery: ~2 min (physical access to M4 to run `sudo tailscale up`)
๐ก Lighter (just want to end an Aria session)
Action: iPhone โ Tailscale admin โ Users โ SSH sessions โ revoke the check
Blast radius: Aria has to re-auth via URL flow on next SSH. M4 stays on tailnet.
Recovery: ~10 seconds (next time Aria SSHes, tap the URL)
๐ข Lightest (just wait)
Action: Do nothing โ let the 12h check token expire naturally
Blast radius: Aria loses SSH at the 12h mark
Recovery: Next SSH after expiry triggers fresh URL
๐ Recovery after panic button (Remove M4)
Topher: Confirm M4 is the actual problem (not the tailnet) โ check Tailscale admin for "offline" status
Topher: Get physical/screen-share access to M4 (or use existing tailnet access from another device if not yet revoked)
Topher on M4: Run `sudo /opt/homebrew/bin/tailscale up` โ Tailscale prints a fresh auth URL
Topher on iPhone: Tap the URL โ Google sign-in โ approve M4 rejoining the tailnet
Aria from M4: Run `ssh mba "uptime"` โ verify SSH works again; tap URL once more for the fresh check session
Total recovery time: ~2 minutes. The check token from before the Remove may still be valid; if not, tap the URL once more during step 5.
๐ Maintenance checklist
| Cadence | Task | How |
|---|---|---|
| Quarterly | Rotate aria password on MBA | Generate new via `openssl rand -base64 24`. Update 1Password "Aria - MBA sudo". `sudo passwd aria` on MBA. |
| Quarterly | Rotate aria password on MBP | Same as MBA but on MBP. Update 1Password "Aria - MBP sudo". |
| Annually | Audit sudo log on both laptops | `log show --predicate 'process == "sudo"' --last 365d | grep aria` โ should show only legitimate Aria ops sessions |
| On macOS upgrade | Verify Tailscale SSH still works | After major macOS version bump (e.g., 26โ27), run `ssh mba "whoami"` โ confirm still returns `aria`. macOS sometimes resets sshd-related state. |
| On Tailscale upgrade | Verify `tailscale up --ssh` setting still active on laptops | On each laptop: `tailscale debug prefs | grep -i ssh` โ should show `RunSSH: true`. If not: `sudo tailscale up --ssh`. |
| Any time M4 is rebuilt | Re-add SSH config aliases | Restore `~/.ssh/config` entries for mba, topher-mba, macbook-air, mbp, jaime-mbp, jaimes-macbook-pro. (Snippet in OPS-81 + this runbook.) |
๐ Known quirks + workarounds
macOS overwrites /etc/ssh/sshd_config on system updates
Impact: If we ever add custom sshd_config (we currently don't โ Tailscale SSH replaces it), it would need re-fixing after each macOS update
Workaround: We use Tailscale's built-in SSH server, not macOS sshd, so this doesn't affect us today. If we ever add custom sshd_config: use `chflags simmutable` to make file immutable
tailscale ssh wrapper has DNS resolution issues on M4 post-brew-migration
Impact: Cannot use `tailscale ssh aria@hostname` from M4; plain `ssh` works fine
Workaround: SSH config aliases (`ssh mba` / `ssh mbp`) at `~/.ssh/config` on M4 resolve to IPs directly
App Store Tailscale daemons cannot be killed on M4 post brew-migration
Impact: NetworkExtension remnants visible in `launchctl list` (SIP-protected, cannot bootout)
Workaround: Cosmetic only โ brew daemon `com.tailscale.tailscaled` owns the actual tailnet; the remnants are idle. Will clean up on next macOS upgrade.
Device re-enrollment creates new tailnet IPs
Impact: If a laptop is "Removed" then re-added, it gets a new tailnet IP. SSH aliases on M4 must be updated.
Workaround: Update `~/.ssh/config` on M4: change `HostName` line. Get new IP via `tailscale status | grep <device-name>`.
Open bug tailscale/tailscale#16541
Impact: Check mode "keeps asking for auth even after first auth" โ rare, intermittent
Workaround: If it bites, just re-tap. If it bites repeatedly, raise checkPeriod from default (12h) by adding an explicit `checkPeriod: "24h"` to a user-identity-sourced SSH rule
๐ Architecture decisions (rejected โ chosen)
โ REJECTED: Tailscale Premium with custom posture attributes
$216/yr for a few API calls per week. Outsized cost for utility.
โ REJECTED: Tailscale tag-toggle + launchd polling timer on M4
Topher allergic to ops dependencies that need monitoring; polling cron has resource overhead even at small scale
โ REJECTED: Cloudflare Worker as toggle/timer
Over-engineered โ adds CF Worker maintenance to "use what you have" promise
โ REJECTED: SSH certificates signed on iPhone (a-Shell, etc.)
Research showed iOS terminal apps don't reliably support cert-signing; would be original engineering
โ REJECTED: Cloudflare Access for Infrastructure (per-session push)
Daemon on each laptop + push fatigue after months of use
โ CHOSEN: Tailscale SSH check mode (shipped policy default)
Free, zero new code, zero new infra, zero new vendor surface. Native expiry via wall-clock cryptographic check at connect time. The primitive was sitting in the default policy the whole time.
Full decision trail with research links: OPS-81
๐งน Cleanup task โ revoke unused OAuth client
During the architecture iteration, an OAuth client (k91gcK6tdL11CNTRL) was generated, never used, and removed from ~/.aria-secrets. Best practice is to also revoke it in Tailscale admin.
- Open https://login.tailscale.com/admin/settings/oauth
- Find the client with ID
k91gcK6tdL11CNTRL(description: "Aria JIT access (M4)") - Click the โฏ menu next to it โ Revoke (or Delete depending on UI version)
- Confirm
๐ฎ Future work (none urgent)
- Persistent NAS auto-mount on both laptops โ the actual reason this access was built. Solves the "we keep losing the NAS connection" problem permanently. Pending research + implementation.
- Test panic-button recovery flow on brew tailscale โ verify that `sudo tailscale up` from CLI prints fresh URL after a logout. Low priority โ architecture is sound, just want one tabletop confirmation.
- Fix MagicDNS quirk on M4 โ `tailscale ssh aria@hostname` doesn't resolve post-brew-migration. Workaround (SSH config aliases) works fine. Low priority.
- Upgrade to request-approve flow (Pushcut/ntfy webhook) โ if "Topher has to remember to tap first" becomes annoying, add a Pushcut intermediary that lets Aria proactively request access. Decided to defer until we have ~4 weeks of usage data.
๐ Related
- Linear OPS-81 โ full architecture iteration trail (5 architectures considered, decision log)
- Session journal:
memory/sessions/aria/2026-05-27-aria-jit-access.md - Reference memory (daily usage):
memory/reference_aria_jit_ssh_access.md - Feedback memory (architectural gotcha):
memory/feedback_tailscale_check_mode_no_tags.md - Tailscale SSH official docs โ including `checkPeriod` reference
- Tailscale blog: Frequent reauth doesn't make you more secure โ design rationale for event-driven re-auth (vs polling)