Skip to content

ADR-006 — IaC Admin Account Creation

Date: 2026-04-10 Status: Accepted

Decision

Every service playbook must create the holo admin account as part of first-run setup. No service should require manual UI signup to become operational after deployment.

Context

Several services (Databasement, Karakeep) required manual account creation through the web UI before they were usable. This breaks the core principle that everything is IaC — a full disaster recovery (PBS restore + playbook run) should result in a working service with no manual steps.

Pattern

  1. Credentials in Vault at secret/<service> with keys admin_email and admin_password
  2. First-run check in the playbook: query the user table, skip if users exist
  3. Account creation via one of:
  4. Direct SQLite insert (for apps with simple user tables)
  5. API call (for apps with registration endpoints, e.g. Karakeep's tRPC)
  6. php artisan tinker or equivalent (for apps with encrypted fields, e.g. Databasement)
  7. Lockdown after creation: disable signups, disable password auth, enable OIDC-only

The admin account is a bootstrap seed — after it exists, PocketID SSO takes over for daily login.

Service audit

Service Admin creation Method Status
Karakeep Playbook tRPC signup + SQLite API key Done
Databasement Playbook SQLite insert (bcrypt password) Done
Forgejo Playbook forgejo admin user create Done (bootstrap)
Grafana Playbook Default admin + env var Done
N8N Manual Web UI signup Needs migration
Open-WebUI Manual Web UI signup Needs migration
Paperless Manual createsuperuser Needs migration
PocketID Manual First user is admin Needs migration
Jellyfin Manual Setup wizard Needs migration
Gatus N/A No user DB (config-only) N/A
Caddy N/A No user DB N/A
Vault N/A Token-based N/A
Ollama N/A No auth N/A

Trade-offs

Accepted

  • Passwords in Vault even though SSO is primary: The local password is a bootstrap mechanism. After OIDC is configured, it's unused but must exist to seed the admin user.
  • Service-specific creation methods: No universal approach works for all apps. Each playbook needs custom logic matching the app's user model.

Rejected

  • Skip local accounts, rely on OIDC auto-create: Many apps show a setup wizard or registration page when zero users exist. OIDC login buttons only appear after initial setup. A seed account is required.

Implementation

Add first-run admin creation blocks to all "Needs migration" services. Each should follow the pattern in karakeep.yml or databasement.yml.