Skip to content

Epic: Transport B — Tailscale-SSH-native keyless multi-user gateway #110

Description

@pgebheim

Overview

Make the lilbox gateway work over Tailscale SSH with the caller's tailnet identity — no SSH keys, one local user, per-VM ownership in-app. End users install nothing: on the tailnet + ACL allows → ssh lilbox@host new --tailscale mybox just works.

De-risked in the spike #109 (findings there). Extends the gateway from #108 (key-based OpenSSH forced-command MVP).

Why an epic (not a sprint)

The children interlock on one runtime contract: the -c entry refactor gates identity resolution, identity gates ownership authz, both gate a meaningful install, and hardening/docs describe the assembled whole. Any one alone on main would ship a half-wired gateway — so they stack on a shared integration branch and squash to trunk once.

Base: the integration branch is cut from paulg/gateway-ssh-provisioning (#108's branch), since Transport B extends src/commands/gateway.rs which lives only there. If #108 merges to main mid-epic, the code is a superset — fine.

Children (stacked, foundation-first)

  1. Login-shell entry + -c dispatch
  2. Caller identity via tailscale whois (fail-closed)
  3. owner column + gateway-boundary authz + admin allowlist
  4. lilbox gateway install --user (+ RunSSH doctor check)
  5. SFTP/file-transfer hardening + Transport-B docs

Key correction from the spike: do not rely on $SSH_ORIGINAL_COMMAND — Tailscale SSH never sets it; read the command from the shell's own -c arg. And a restricted login shell does not block SFTP — close it at the server/ACL layer.

Activity

  1. added
    epicEpic parent (integration-branch workflow)
    on Aug 9, 2026
  2. pgebheim commented on Aug 9, 2026

    @pgebheim
    CollaboratorAuthor
  3. pgebheim commented on Aug 9, 2026

    @pgebheim
    CollaboratorAuthor

    Parked as backlog — the SSH gateway is deprioritized as non-core for now. Not in flight: the started-epic scaffolding (integration branch 110-transport-b-tailnet-gateway + local state file) was removed so this reads as filed tickets, not active work. Children #111–#115 remain as the captured plan; re-run /rig-epic start #110 to re-cut the integration branch when it's picked up. Design/rationale in spike #109; MVP code in #108.

  4. pgebheim commented on Aug 9, 2026

    @pgebheim
    CollaboratorAuthor

    Update: the base MVP #108 merged to main (squash c2a566b) and its branch was deleted. When this epic is picked up, re-cut the integration branch from origin/main (which now contains the gateway code), not the old #108 branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    epicEpic parent (integration-branch workflow)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions