VPS access model (brioso-vps, decided 2026-10-13, BRI-433)
VPS access model (brioso-vps, decided 2026-10-13, BRI-433)
VPS access model (brioso-vps, decided 2026-10-13, BRI-433)
Who may log in to the new box, as which account, and how the root surface is limited. Read this before touching accounts, sudoers, keys or the Tailscale ACL.
Accounts
| Account | Used by | Auth | Privilege |
|---|---|---|---|
deploy |
GitHub Actions (pyinfra converge, activate, smoke, health) | ed25519 key VPS_PYINFRA_SSH_KEY, public half in deploy/ssh/ci-authorized-keys.pub, installed with restrict |
NOPASSWD: ALL (a converge needs arbitrary root). Only when ci_full_sudo is set |
brioso-admin-<name> |
one human each | personal key, Tailscale | full sudo, never used by automation, so logs stay separable |
diag |
teammates and cloud agents (tag:agent) |
Tailscale SSH | journald read, status of the four web slot units, restart of the two slots of its env. No shell as root |
web-services |
app and service units | none (no login) | rootless, owns /opt/brioso |
Decisions
- The legacy
deploy.yml(deploy-vps.sh) is not used on the new box.deployis elevated instead of adding a new CI account. The narrow script grant stays on the old box until it is retired, so the elevation is opt in:VPS_CI_FULL_SUDO=1(inventoryci_full_sudo), set as a repo variable together withVPS_SSH_USER=deployat the flip. - Human admin and automation never share an account. CI actions show up as
deployin the journal andauth.log. - Other tenants on this VPS run rootless (a dedicated user, podman or a quadlet) unless explicitly flagged. If a second, unrelated tenant arrives, the isolation decision (separate VM or container per tenant) is made then. On a shared host, root is root.
- Cheap hardening in place:
restricton the CI key (no forwarding, no pty),tag:cilimited by ACL to ports 22, 443, 6006 (Phoenix), 41230 (turbo), the key only in GitHub environment secrets (beta,production), sudo logged by the journal. Usenonokernel sandboxing for units that do not need broad access (litestream, cloudflared already do). - The CI Tailscale identity is an OAuth client that mints
tag:cinodes in theusebriosoteam tailnet. Tailscale SSH (tailscale set --ssh) is only needed fordiagand agents. Turn it on only after thesshACL section has rules for admins (brioso-admin-*,check),deployfortag:cianddiagfortag:agent(accept), or tailnet SSH for admins breaks.
Tailscale ACL checklist (usebrioso tailnet)
tagOwners:tag:brioso-vps-ovh,tag:ci,tag:agent.- grants: members to the box on 22 and 3900 and 443,
tag:cito 22, 443, 6006, 41230,tag:agentto 22 only. ssh: members to the box asbrioso-admin-*(check),tag:ciasdeploy(accept),tag:agentand members asdiag(accept).- OAuth client with
auth_keyswrite fortag:ci(GitHub), a separate client or ephemeral key fortag:agent.
Flip checklist for access
- GitHub environments
betaandproduction:TS_OAUTH_CLIENT_ID,TS_OAUTH_SECRET,VPS_TAILSCALE_HOST,VPS_PYINFRA_SSH_KEY(private half of the CI key). - Repo variables:
VPS_SSH_USER=deploy,VPS_CI_FULL_SUDO=1. - Converge
userswithVPS_CI_FULL_SUDO=1before the first CI run (done on the new box 2026-10-13). VPS_DEPLOY_SSH_KEYand the legacydeploy.ymlstay pointed at the old box and are retired with it.