Super Admin Recovery
Why this exists
Section titled “Why this exists”The very first admin account a deployment ever creates – the bootstrap
admin – is write-protected against every in-app path by design: no
admin, however privileged, can demote, deactivate, or delete it, and no
other account can hold the super_admin role to act on its behalf (the
bootstrap account is how that role ever gets seeded in the first place).
That protection is exactly right for day-to-day operation, but it means
there’s no in-app “reset this admin’s password” button for that one
account if its password is lost, its MFA device is gone, or it gets
locked out. recover-admin.sh is the one supported way back in –
entirely outside the web app’s own API/RBAC, on the same trust boundary
as any other action that already requires root/shell access to the box
(same posture as upgrade.sh/add-machine.sh).
Run as root, or as a user in the docker group, from the repo root on the
host:
./recover-admin.sh --reset-password [--clear-mfa] [--unlock] [--regenerate-recovery-codes] [--yes]At least one action flag is required. All of them are safe to combine in
one run – the common “I’m fully locked out” case is
--reset-password --clear-mfa --unlock together.
| Flag | What it does |
|---|---|
--reset-password |
Generates a new one-time password, printed once to the terminal only – never written to a file, logged, or emailed. Forces a real password change at the very next login. |
--clear-mfa |
Disables the current TOTP enrollment and requires re-enrollment at next login. |
--unlock |
Clears both the password-lockout and MFA-lockout failed-attempt counters. |
--regenerate-recovery-codes |
Issues a fresh set of MFA recovery codes (skipped with a message if MFA isn’t enabled). |
--yes |
Skips the interactive re-type-the-username confirmation – for non-interactive/scripted use. |
--repo-dir DIR |
Defaults to the script’s own directory, same convention as upgrade.sh. |
Without --yes, the script asks you to re-type the bootstrap account’s
username before doing anything, as a deliberate confirmation step for a
break-glass action.
How it works
Section titled “How it works”The script finds the currently-running app container (same blue/green
slot detection upgrade.sh uses) and docker execs into it, running
python -m vpnadmin.cli_recover_admin with whichever flags you passed.
That module writes directly to the database, but reuses the same
password-hashing and recovery-code primitives the normal admin console
uses – a recovered account ends up in exactly the state a normal
in-app action would have left it in, never a parallel or weaker path.
Every recovery action is still written to the normal audit log, even
though it went around the API – a recovery run shows up in the admin
console’s own Audit Log like any other action, attributed to whoever ran
the script (captured from $SUDO_USER, falling back to the shell’s
current user) plus the host it ran on.
Developed by Cloudlative