Skip to content

Super Admin Recovery

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:

Terminal window
./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.

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