Viktor: emo may make any change; what matters is tracking what changed and why. ebarzin added to master push+merge whitelists (force-push stays disabled — append-only history). Tracking enforced three ways: - agent instructions (managed claudeMd + AGENTS.md): commit body MUST carry the user's plain-language intent; commits land on master directly; [ci skip] forbidden for non-admins - new notify-nonadmin-push step in .woodpecker/default.yml: Slack message for every non-admin master push (admin pushes silent) - PR flow remains the fallback for non-whitelisted users Accepted consequence (informed): emo's pushes auto-apply changed stacks via CI. Offboard runbook gains whitelist-removal step. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.3 KiB
Runbook: Offboard a User
Removing a user can span two surfaces — the in-cluster namespace-owner model
(Vault k8s_users / RBAC / namespace) and the devvm Workstation (roster /
OS account / t3 instance). Both are staged: a reversible cut (revoke access,
delete nothing) first, then an explicit, gated destructive removal. Do the
reversible cut immediately; only do the destructive step once you're sure.
Architecture:
../architecture/multi-tenancy.md. Workstation design:../plans/2026-06-07-multi-user-workstation-design.md.
Part A — DevVM Workstation offboarding
Driven by removing the user's entry from infra/scripts/workstation/roster.yaml.
roster_engine.py offboard_plan computes the staged actions (reversible cut vs the
gated userdel_archive, which is never auto-applied).
A1. Reversible cut (revoke access; delete nothing)
- Delete the user's entry from
roster.yaml; commit + push. - Reconcile (
sudo /usr/local/bin/t3-provision-users, or wait for the hourly timer). This regenerates/etc/ttyd-user-map+dispatch.jsonwithout the user →t3-dispatchnow returns 403 for them. (Automated.) - Disable their instance + lock login (manual today; Phase 7 will fold this into
the reconcile):
sudo systemctl disable --now t3-serve@<os_user>.service sudo passwd -l <os_user> - Revoke git + group access (manual):
Note: their already-running sessions keep dropped groups until cycled — restart# legacy secret-bearing group, if they were ever in it sudo gpasswd -d <os_user> code-shared # drop write access to the infra repo curl -X DELETE -H "Authorization: token <admin_pat>" \ https://forgejo.viktorbarzin.me/api/v1/repos/viktor/infra/collaborators/<forgejo_login> # if they were whitelisted for direct master push, remove them from the # branch-protection whitelists (PATCH with the remaining usernames) curl -X PATCH -H "Authorization: token <admin_pat>" -H 'Content-Type: application/json' \ https://forgejo.viktorbarzin.me/api/v1/repos/viktor/infra/branch_protections/master \ -d '{"push_whitelist_usernames":["viktor"],"merge_whitelist_usernames":["viktor"]}' # revoke their devvm git PAT (token name: devvm-infra-git; admin PAT may # manage other users' tokens — verified 2026-06-10; the CLI has no delete) curl -X DELETE -H "Authorization: token <admin_pat>" \ https://forgejo.viktorbarzin.me/api/v1/users/<forgejo_login>/tokens/devvm-infra-gitt3-serve@<os_user>to enforce immediately. - Verify: they can no longer reach
t3.viktorbarzin.me(302 → Authentik, then denied once removed from theT3 Usersgroup — Part C) and cannot log in. Nothing is deleted; re-adding the roster entry + reconcile fully restores them.
A2. Destructive removal (explicit, gated — NEVER automatic)
Only after the reversible cut and a deliberate decision:
sudo tar czf /mnt/backup/offboard/<os_user>-$(date +%Y%m%d).tar.gz /home/<os_user>
sudo userdel -r <os_user> # removes home + mail spool — IRREVERSIBLE
Rollback before this step: re-add the roster entry + reconcile. After it: restore from the archive.
Part B — In-cluster (namespace-owner) offboarding
- Reversible cut: remove the user's Authentik group membership (edge/RBAC blocked)
and their entry from the Vault
k8s_usersmap (secret/platform). - Apply:
scripts/tg applythevault→platform→woodpeckerstacks (drops the RBAC binding, Vault identity/policy, and per-user CI). Their OIDC kubeconfig stops authorizing immediately. - Destructive (gated): deleting their namespace(s) removes all their workloads + data — back up first (PVCs, DBs), then delete only on explicit decision.
Part C — Authentik (both surfaces)
Remove the user from the relevant Authentik group(s) — kubernetes-namespace-owners
(cluster) and/or T3 Users (workstation edge gate). This is the edge revocation; do
it as part of the reversible cut so they're locked out at the front door.
Order of operations
Reversible cut on all relevant surfaces first (Authentik group → roster removal +
reconcile → k8s_users removal + apply) → verify access is gone → only then the gated
destructive steps (userdel -r, namespace deletion), each after its own archive.