Authority Bootstrap Modes

Audience: Operators and CI engineers preparing a fresh Stella Ops Authority deployment.

Purpose: Compare the supported ways to provision or recover administrative access, and explain which to choose for production, local, demo, and CI contexts.

Stella Ops Authority needs at least one administrative user before any client can obtain an OIDC token. There are five supported ways to create or recover that access, each appropriate for a different deployment context. Pick one primary bootstrap mode and document the recovery path in your deployment runbook.

ModeTargetTriggerIdentity created
Setup wizardProduction / customer installUI-driven, first browser visit to /setup-wizard/wizardOperator-chosen username + password
Runtime default admin bootstrapLocal / CI clean installSTELLAOPS_ADMIN_PASS at Authority startupadmin in tenant default, password read from private env
Demo seed migrationDev / demo / CI sample dataAUTHORITY_BOOTSTRAP_ENABLED=true at startupDemo users/clients/ABAC rows only; historical default admin hash is scrubbed
Driver-script setupCI / scripted re-bootstrapbash devops/compose/scripts/stella-connectors.sh setupAPI-key-driven POST /internal/users against the running Authority
Compose password recovery helperLocal source checkout / compose stackdevops/compose/scripts/authority-password-set.*Existing Authority user’s password is reset through the Stella CLI hashing path

The setup wizard is the primary production path. Runtime default admin bootstrap is acceptable for local and scripted clean installs only when STELLAOPS_ADMIN_PASS comes from a private environment file. Demo seed migration is sample-data opt-in and must not be enabled for production.

Mode 1 - Setup Wizard

The wizard is the default production behavior on a fresh install. Authority starts with Bootstrap:Enabled=false and RunSeedMigrations=false; demo user rows are not seeded. The console UI detects the empty authority.users table on first navigation and routes the operator to /setup-wizard/wizard, which collects:

Submitting the wizard form posts to Authority’s /internal/users endpoint with the bootstrap API key (STELLAOPS_AUTHORITY_AUTHORITY__BOOTSTRAP__APIKEY) sourced from the deployment env. After the first user is created, the wizard endpoint refuses additional creates; subsequent admins must be added via the regular admin console.

Production checklist:

Mode 2 - Runtime Default Admin Bootstrap

Clean local compose defaults keep AUTHORITY_BOOTSTRAP_ENABLED=false; Seed-category migrations stay manual-only. The standard plugin still bootstraps the structural first administrator when defaultAdminBootstrap.enabled=true in etc/authority/plugins/standard.yaml.

Authority reads the admin password from the environment variable configured by defaultAdminBootstrap.passwordEnvironmentVariable (default STELLAOPS_ADMIN_PASS). If the admin user is missing or has no password hash and the variable is unset or blank, startup fails closed with a clear configuration error. Stella Ops does not provide a repository default password.

The runtime bootstrap also ensures the admin role, full StellaOpsScopes.All permission catalog, and role assignment exist. First-party clients are provisioned from etc/authority/plugins/standard.yaml by StandardPluginBootstrapper.

Clean local/CI checklist:

Mode 3 - Demo Seed Migration

Set AUTHORITY_BOOTSTRAP_ENABLED=true only when you intentionally want demo/sample Authority rows. Authority’s Program.cs reads this and passes runSeedMigrations: true to AddAuthorityPostgresStorage, which causes the shared StartupMigrationHost to apply migrations in the seed category in addition to the default startup category.

The live seed file is src/Authority/__Libraries/StellaOps.Authority.Persistence/Migrations/S001_v1_authority_operational_baseline.sql — the collapsed pre-1.0 seed chain (S001_demo_seed.sqlS033_*). It is forward-only history and is not edited in place; the originals sit under Migrations/_archived/pre_1.0/mig061/ and are excluded from embedding, so new seed rows go into fresh forward S0xx_*.sql files after the baseline (e.g. S034_registry_read_scope.sql, S036_scope_catalog_parity_repair.sql).

Behaviour folded into that seed baseline (originally shipped as separate migrations, now archived):

Production safety properties:

Demo checklist:

Mode 4 - Driver-Script setup

For CI pipelines that wipe and rebuild on every run but cannot or do not want to use runtime default admin bootstrap (for example, they test the setup wizard flow itself or need a different admin username), the driver script ships a setup subcommand:

bash devops/compose/scripts/stella-connectors.sh setup

What it does:

  1. Counts authority.users via psql against stellaops_authority (overridable via POSTGRES_AUTH_DB).
  2. If the table is empty, starts a one-shot curlimages/curl container attached to the stellaops docker network and POSTs a BootstrapUserRequest to Authority’s internal port using the bootstrap API key resolved from private env or the running Authority container.
  3. Re-counts and exits non-zero if the row is missing.

stella-connectors.sh login auto-invokes setup once when the token endpoint returns HTTP 400 / invalid_grant / a body mentioning username; this is the self-healing path for CI scripts that do not want to reason about whether the seed migration is on or off.

CI checklist:

Mode 5 - Compose Password Recovery Helper

Use the compose recovery helper when a local source-checkout stack already has an Authority admin row, but the password in the operator’s ignored env file is stale, unknown, or the account is locked out. This is not a fresh bootstrap mode; it updates the existing user’s credential through the Stella CLI command and Authority password hashing path from a one-shot compose container.

PowerShell:

$env:STELLAOPS_ADMIN_PASS = '<new-private-password>'
$env:STELLAOPS_ADMIN_PASS |
  .\devops\compose\scripts\authority-password-set.ps1 -Username admin -Tenant default -PasswordStdin

Bash:

printf '%s\n' "$STELLAOPS_ADMIN_PASS" |
  ./devops/compose/scripts/authority-password-set.sh --user admin --tenant default --password-stdin

After recovery, update the ignored local .env value used by the stack, refresh browser sessions, and verify sign-in or POST https://stella-ops.local/connect/token.

The helper publishes the current Stella CLI from source before it runs the one-shot container. If publish fails with MSB3541 and Null character in path, the current helper treats that as corrupt generated MSBuild state, runs publish with build servers disabled, removes only the named generated obj directory inside this repository, and retries once. Do not wipe databases, edit authority.users, or enable demo seed to work around a stale local admin password.

Choosing Between Modes

Mode 2 (runtime default admin bootstrap) is the clean local/CI path. It is appropriate when:

Mode 3 (demo seed migration) is appropriate when:

Mode 4 (driver script) is appropriate when:

Mode 5 (compose password recovery helper) is appropriate when:

The runtime default admin bootstrap and demo seed can coexist. Demo seed no longer owns the real admin password; STELLAOPS_ADMIN_PASS remains the credential source. If the driver script also runs against a populated DB, it skips with the “admin already exists” message.

The driver-script setup path is not an existing-admin password reset. Once authority.users is populated, use the compose recovery helper instead:

$env:STELLAOPS_ADMIN_PASS = '<new-private-password>'
$env:STELLAOPS_ADMIN_PASS |
  .\devops\compose\scripts\authority-password-set.ps1 -Username admin -Tenant default -PasswordStdin
printf '%s\n' "$STELLAOPS_ADMIN_PASS" |
  ./devops/compose/scripts/authority-password-set.sh --user admin --tenant default --password-stdin

If the helper reports MSB3541 with Null character in path while publishing the local CLI, that is corrupt generated MSBuild state, not an Authority password failure. The current helper runs publish with build servers disabled, removes only the named generated obj directory inside this repository, and retries once. If the retry still fails, treat it as a code or documentation defect and fix the setup path before continuing.

Rotation And Rollback

After any mode creates a usable admin or demo developer, treat the credential as a starting point and rotate immediately. The standard plugin will not overwrite a non-empty password_hash, so an operator-rotated password is safe across restarts even if demo seed remains enabled.

To return a deployment to a “no admin” state before re-running the wizard for a clean install demo:

  1. bash devops/compose/scripts/wipe-postgres.sh --yes (full DB wipe, see Sprint 20260504_007).
  2. docker compose ... up -d with the desired bootstrap mode env vars.
  3. Browse to /setup-wizard/wizard (Mode 1), set STELLAOPS_ADMIN_PASS and use runtime bootstrap (Mode 2), enable demo seed (Mode 3), or run stella-connectors.sh setup (Mode 4).

Partial wipes (delete the row only) are not supported. The standard plugin caches user state, and an out-of-band delete will leave dangling sessions and break the audit chain.

See Also