Chapter 18 / 40

Baseline accounts playbook

Every engagement that stands up a Sodimo-shaped stack — Framework Desktop + Cloudflare + on-prem AI + chezmoi-driven quadlets — needs the same set of accounts in the same order. Skipping an account, or creating them out of order, produces a pile of orphan credentials and a handoff that can’t be verified. This chapter is the canonical checklist.

The playbook has one spine (Google Workspace) and four branches (GitHub, Cloudflare, Tailscale, leger.run / leger-labs). Each branch authenticates through the Google super-admin account — not as a separate identity pool. That’s the discipline that makes the vault handoff (The vault) actually work: one identity to rotate, one identity to revoke, one identity to hand over.


1. Why this order, why this spine

Google Workspace first. The super-admin account (e.g. admin@<client>.eu) is the root of trust for the entire engagement. CF Access federates against it. GitHub SSO optionally federates against it. Tailscale uses it for MagicDNS-tier identity. Every SaaS the engagement touches later (Anthropic, OpenAI, Meta Business, Strato, registrar) uses it for login. If this account is wrong — wrong email, wrong MFA device, no written recovery path — every downstream account inherits the problem.

Why not “whatever email the operator already uses”. A personal Gmail drifts when the operator leaves. A role-based admin@<client>.eu stays. The handoff rule is: nothing in the stack authenticates against an identity that the engagement can’t revoke.

MFA on day one, recovery codes on paper, paper in the vault. Every account below gets TOTP (not SMS) as second factor. Recovery codes are printed, signed in ink, scanned into Vaultwarden under the accounts/recovery/ collection, and the paper original goes into the site safe. This is the one redundancy the playbook refuses to optimize away — the cost of one lost phone vs. a locked-out super-admin is too asymmetric.


2. The spine — Google Workspace super-admin

Owner at handoff: the principal at the client (e.g. Paul at Sodimo). Tom sets it up, Paul takes the password on day one.

What gets created:

  • admin@<client>.eu super-admin mailbox (Google Workspace Business Standard or equivalent tier).
  • TOTP on a hardware token (YubiKey preferred) + a software TOTP (Aegis / 1Password) as second factor.
  • 10 recovery codes, printed, signed, filed in the safe, scanned into Vaultwarden.
  • One “break-glass” secondary super-admin on a separate device — Tom during the engagement, rotated to the principal’s spouse or co-founder at handoff. Documented in the Accounts chapter (ch6x+1 — see CONSIDERATION_MAINTAINANCE.md).
  • MX records left on the existing provider for now — the super-admin account can exist without the domain’s MX flipping (a domain can federate identity via DNS TXT without moving mail yet).

What it unlocks downstream: every federation / SSO step below. If the super-admin is not yet live, stop — don’t proceed to GitHub or Cloudflare.

Verification checklist before moving on:

  • Log in from a fresh incognito window using the password from Vaultwarden.
  • Prompt for TOTP succeeds.
  • One recovery code successfully consumes (use a real one — don’t test with a fake).
  • Super-admin can create a second user. Delete the test user.

3. GitHub — org + billing + deploy keys

Owner at handoff: the principal (same person as Google super-admin).

What gets created:

  • Personal GitHub account for the principal, email = the Google super-admin address.
  • GitHub organization (e.g. sodimo). Principal is the sole owner; Tom is added as owner for the engagement duration and removed at handoff.
  • Organization billing set against a company card (or invoice — request invoice billing if on an Enterprise tier).
  • Optional but recommended: Google Workspace SSO for the org, so GitHub login fails closed when the Google account is revoked.
  • Personal access token with scopes repo, workflow, write:packages — generated by the principal, stored in Vaultwarden under accounts/github/principal-pat. Tom’s own PAT is created separately and revoked at handoff.
  • Deploy keys for sodimo/changelog, sodimo/dotfiles, sodimo/harness, etc. — one keypair per repo per environment, not one “god key” across everything.

What it unlocks downstream:

  • Tailscale identity (Tailscale can use GitHub OAuth — fewer identity silos).
  • GHA workflows that deploy to Cloudflare Pages / R2 / ghcr.io.
  • The sodimo/dotfiles private-repo pull that chezmoi-on-harness needs (blocked on the private-repo auth decision — see harness#10).

Verification checklist:

  • Fresh incognito login using Google SSO hits the org.
  • gh auth status passes on the engagement laptop.
  • A trivial commit via GHA runs green end-to-end.

4. Cloudflare — DNS + Pages + Access + R2 + Workers + Tunnel

Owner at handoff: the principal.

What gets created:

  • Cloudflare account, email = Google super-admin address.
  • Domain zone(s) transferred in (or nameservers delegated) for <client>.eu + sibling domains. NS flip is a separate scheduled event; the account can exist with zero zones.
  • Cloudflare Access application registered against the Google Workspace IdP (SAML, not OAuth — SAML’s group-claim shape integrates more cleanly with Access policies).
  • One API token per concern, not a “master API key”:
    • pages-deploy — scope: Pages:Edit on the changelog project.
    • dns-admin — scope: DNS:Edit across all zones.
    • workers-deploy — scope: Workers Scripts:Edit + R2:Edit on the named buckets.
    • tunnel-admin — scope: Tunnel:Edit (for cloudflared token rotation).
  • R2 buckets pre-created per the architecture (<client>-archive, <client>-backup, <client>-dashboards, <client>-public) with the 90d Standard → IA lifecycle.
  • A single named CF Tunnel (<client>-prod) — the tunnel token is what cloudflared on the harness authenticates with. Token lives in Vaultwarden + home/dot_config/cloudflared/ on the harness.
  • Billing: corporate card or invoice. Same invoice-preference as GitHub.

What it unlocks downstream: the whole hybrid architecture — Pages for changelog.<client>.eu and the public site; Access gating for every on-prem service; Tunnel exposing the harness; R2 for backups.

Verification checklist:

  • Google SSO login to dash.cloudflare.com succeeds.
  • wrangler whoami (using pages-deploy token) returns the expected account.
  • An Access application bound to the Google IdP admits a test @<client>.eu user.
  • cloudflared tunnel info <client>-prod returns a healthy connector once the harness is up.

5. Tailscale — dev access for Tom, break-glass for the principal

Owner at handoff: the principal. Tom’s device is removed from the tailnet at handoff.

What gets created:

  • Tailscale account, login via GitHub OAuth (not a standalone email/password — keeps the identity count down).
  • Tailnet named after the engagement (e.g. sodimo.tailscale.net).
  • ACL policy: only the principal’s devices + Tom’s engagement laptop have access; Tom is removed at handoff.
  • A single auth-key rotation policy (90-day default) — documented in the Accounts chapter as a quarterly rotation task.
  • Subnet router on the harness only if LAN access to other boxes is needed (usually not — CF Tunnel handles the HTTP-reachable services, Tailscale is for SSH + cockpit + break-glass).
  • No MagicDNS domain override — Sodimo services live at *.<client>.eu via CF Access, not at *.ts.net. Tailscale is dev access, not the primary surface.

Why GitHub-backed login rather than Google-backed: fewer points of failure on the engagement laptop. The Tailscale client on Tom’s machine authenticates via gh auth that’s already warm; adding a second OAuth provider is noise.

Verification checklist:

  • tailscale status on Tom’s laptop shows the harness as a peer once the harness joins the tailnet.
  • SSH to the harness over Tailscale succeeds with Tom’s key.
  • A principal-owned phone can join the tailnet via GitHub OAuth in break-glass mode.

6. leger.run / leger-labs — quadlet configs, model drops, env secrets

Owner at handoff: this is the one account that stays Tom-owned by default, because leger-labs is Tom’s conceptual-fork source for the harness. The principal gets credentials and read-access at handoff but does not replace Tom as primary owner — any change to the quadlet pattern needs to propagate through leger-labs upstream, and that remains Tom’s surface.

What gets created / used:

  • leger.run account (if the engagement’s harness pulls a versioned leger-labs release): email = Google super-admin address, login via Google SSO. Billing (if any) on corporate card.
  • GitHub collaborator access from the engagement’s principal to the leger-labs/* repos the harness pins — specifically leger-labs/quadlet-setup/dotfiles1/ as the soft-fork upstream, leger-labs/helper-scripts/ for the OpenWebUI env-var catalog, leger-labs/model-store/schemas/ for the model registry.
  • A documented “resync runbook” pointer — the sodimo/dotfiles/docs/resync-runbook.md equivalent, explaining how to pull a new leger-labs release into the client’s harness without merging Tom’s personal drift.

What this account anchors (the interesting part):

  • Quadlet configs. home/dot_config/containers/systemd/*.container — the canonical shape. Updated quarterly or on upstream breaking changes. Local model drops land here (e.g. the Wednesday 2026-04-22 kyuz0 integration for Strix Halo — see docs/kyuz0-toolbox.md in sodimo/dotfiles).
  • Newest local model drops and configs. When a new model lands (gpt-oss-120b, qwen3-next, a new Whisper variant), the llama-swap.yaml + litellm.yaml entries flow through leger-labs first, are validated on Tom’s dev box, then propagate to client harnesses as a sodimo/dotfiles bump.
  • Env secrets scheme. The .env.tmpl / paperclip.env.tmpl pattern (chezmoi-templated with age-encrypted values at handoff) originates in leger-labs. Clients inherit the shape; the secret values are per-client and live in the client’s Vaultwarden — nothing client-specific goes into leger-labs.

The handoff line. At engagement end, the principal gets:

  • Read access to the pinned leger-labs commit.
  • A frozen snapshot of the harness quadlets at /usr/share/harness/dotfiles/ (bootc-baked, per harness#10).
  • The documented resync procedure.
  • A commitment from Tom (or his successor) to flag breaking-change upstream bumps.

What they do not get is write access to leger-labs itself. The fork boundary is deliberate: Sodimo’s harness is a Sodimo concern; leger-labs is a Tom concern; when the two diverge, they diverge cleanly.


7. Per-engagement checklist (condensed)

Before writing a single quadlet, the following are all green:

  • Google Workspace super-admin live, TOTP + paper recovery codes filed.
  • Break-glass second super-admin on a separate device.
  • GitHub org + principal account + Tom-as-temporary-owner.
  • GitHub PAT for CI / deploy, scoped narrowly, in Vaultwarden.
  • Cloudflare account + Access app bound to Google IdP.
  • Cloudflare domain zones delegated (or ready to delegate) + R2 buckets provisioned.
  • Four CF API tokens (pages, dns, workers, tunnel), each in Vaultwarden.
  • Tailscale account via GitHub OAuth + ACL restricting to the right devices.
  • leger.run account + collaborator access on leger-labs pinned repos + resync runbook captured.
  • All credentials into Vaultwarden under the accounts/<service>/ collections.
  • All recovery codes printed + filed + scanned.
  • Accounts chapter (ch6x+1 per CONSIDERATION_MAINTAINANCE.md) drafted with the per-account owner, vault path, MFA method, and escalation contact filled in.

Only then does the harness get its first bootc upgrade.


8. What this chapter deliberately does not cover

  • Anthropic / OpenAI / Meta Business / Strato / registrar. These are SaaS accounts that also authenticate through the Google super-admin, but they’re service-specific and live in ch6x+1 rather than the playbook. The playbook is the spine; the downstream SaaS accounts are branches off the vault.
  • Passwords for individual team members (Rani’s Twenty login, Paul’s OpenWebUI login). Those are provisioned by the Google Workspace super-admin after the playbook is green — they’re ch61-launchpad material, not spine.
  • Revocation procedures. Belongs in the Accounts chapter (ch6x+1) alongside rotation cadences. Draft TK.
  • Age-encrypted secrets within Vaultwarden. The Vaultwarden → age handoff for long-lived machine secrets is documented in The vault; not duplicated here.

9. Open questions — for the second engagement to validate

This playbook was written after one engagement (Sodimo) and promoted into the manual sequence as the spine that every subsequent engagement walks. Specific things to validate against the next engagement:

  • Does the Google-first spine hold up for engagements where the client already has a non-Google IdP (Azure AD, Okta)? Probably not — note the adaptation.
  • Is Tailscale via GitHub OAuth still the right call, or does a second engagement justify standing up Tailscale’s Google SSO? Revisit.
  • Is leger.run as a deliberate Tom-retained account a durable pattern, or does the second engagement need a fully client-owned equivalent? Likely evolves as leger-labs matures.
  • The CF API token split (4 tokens) — is it too granular, too coarse? Revisit after two engagements.
  • MFA on hardware tokens — has the YubiKey actually survived a real handoff, or did the principal lose it in month 2? Track.