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
- Credentials in Vault at
secret/<service>with keysadmin_emailandadmin_password - First-run check in the playbook: query the user table, skip if users exist
- Account creation via one of:
- Direct SQLite insert (for apps with simple user tables)
- API call (for apps with registration endpoints, e.g. Karakeep's tRPC)
php artisan tinkeror equivalent (for apps with encrypted fields, e.g. Databasement)- 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.