Offboarding#

A person leaves in one merge request, on the day they leave. Everything below the first step happens on its own; the rest of the page is what to check and what the automation cannot know. The manager opens the merge request; a member of infra merges and applies. Together: fifteen minutes.

Same day#

  1. In the directory (https://id.profuse.ro/if/admin → Directory → Users → the person): clear Is active, and remove them from every group. Do not delete the account — it keeps their history and the audit trail; deletion is a later, separate decision (see "Later"). That single change is what closes everything else, and it takes effect immediately: no merge request, no apply, nothing to wait for.

  2. Cloudflare sessions: the apply disables the account and SCIM tells Access, which revokes the person's sessions and WARP registration within minutes. Check under Zero Trust → My Team → Users → the person: status revoked. If it is not (SCIM not yet configured, or in doubt), revoke by hand there, or:

    curl -X POST -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -H "Content-Type: application/json" \
      https://api.cloudflare.com/client/v4/accounts/fa3fedaca96d6834e5166640e2aee819/access/organizations/revoke_user \
      -d '{"email":"<person>@profuse.ro"}'
    
  3. sv1 (only if the person was in infra): open shells survive the directory change. On sv1:

    sudo sss_cache -u <username>; sudo pkill -KILL -u <username>
    

    The account disappears from getent passwd at once (only ak-active=TRUE accounts are visible).

  4. PostgreSQL: pg-directory-sync drops the role within five minutes. A role with an open session cannot be dropped, so end them first if the person may be connected:

    SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE usename = '<username>';
    

    on prod and staging, then sudo systemctl start pg-directory-sync and read its journal.

  5. Mail: mailcow-directory-sync switches the mailbox off within fifteen minutes (IMAP, SMTP and app passwords stop; nothing is deleted). Run it now if you want it now: sudo systemctl start mailcow-directory-sync. The manager decides forwarding and the auto-reply — set them in mailcow on the inactive mailbox — and the retention date.

  6. GitLab: gitlab-directory-sync blocks the account and drops it from both groups within five minutes (sudo systemctl start gitlab-directory-sync if you want it now). Issues and merge requests keep their author. Transfer anything the person owned alone: personal access tokens die with the block, but a project or a schedule owned by them keeps running under a blocked owner — reassign it. An instance administrator is never blocked by the sync: it says so and leaves the decision to you.

What the automation cannot know#

  • Secrets the person could read. Rotate every credential they had access to, the same day: for developers, the staging .env values they could see in a deploy log or on the box; for infra, additionally the authentik bootstrap token (/srv/authentik/.env, then the CI variable AUTHENTIK_TOKEN), the mailcow API key, the Cloudflare API tokens (infra-tofu-*), the GitLab people-provisioner and RELEASE_TOKEN tokens, the restic/R2 credentials. The list of CI variables on profuse/infra and guestget is the checklist; each one is a decision.
  • Devices. Their WARP device is revoked with the user; a company laptop is collected and wiped; passkeys on a personal device become useless once the account is disabled.
  • Things outside the directory. Cloudflare account membership, GitLab instance admin, registrar and hosting logins, Stripe, Channex, ANAF/SDI portals, the password vault: check each for the person's e-mail. The quarterly review (docs/access-review.md) will catch a miss, but a leaver should not wait for it.

Later#

  • Retention over (the date the manager set, default 90 days): delete the account in the directory, after exporting anything the company keeps from the mailbox. The GitLab account stays blocked rather than deleted, so its history survives.
  • Coming back: tick Is active again and put back their roles. The account, the database role, GitLab and the mailbox return on their own; the person sets a new password through a reset link (ak-recovery-link).