Add controlled first-admin enrollment
This commit is contained in:
@@ -57,6 +57,8 @@ PY
|
||||
| `GOVOPLAN_MIGRATION_TRACK` | `release` | Use the release track for normal runtime and deployments. Use `dev` only for fresh/disposable databases that intentionally replay detailed development migrations. |
|
||||
| `DEV_AUTO_MIGRATE_ENABLED` | `true` | Dev convenience only. Production should run migration commands explicitly during deployment. |
|
||||
| `DEV_BOOTSTRAP_ENABLED` | `false` | Dev bootstrap only. `govoplan_core.devserver` and `govoplan/tools/launch/launch-dev.sh` default it to `true`; use controlled first-admin creation outside dev. |
|
||||
| `FIRST_ADMIN_ENROLLMENT_TTL_SECONDS` | `1800` | Lifetime of a locally issued production enrollment credential. Allowed range: 60 seconds to 24 hours. |
|
||||
| `FIRST_ADMIN_ENROLLMENT_FILE` | `/run/govoplan/first-admin-enrollment.json` | Local operator artifact. The command creates it with mode `0600` and never prints the secret. |
|
||||
|
||||
Operator rule: take a database backup before applying migrations or destructive
|
||||
module retirement. For non-SQLite databases, configure deployment-specific
|
||||
@@ -300,8 +302,34 @@ configuration, not the core runtime contract. Store them in a local ignored
|
||||
3. Build the WebUI from `webui/package.release.json` or deploy a prebuilt
|
||||
artifact from the same release tag.
|
||||
4. Run database migrations with the target `DATABASE_URL`.
|
||||
5. Create the first tenant and system owner through the controlled bootstrap or
|
||||
one-time admin command for the deployment.
|
||||
5. Create the first tenant and system owner through the controlled bootstrap:
|
||||
|
||||
```bash
|
||||
python -m govoplan_core.commands.first_admin status
|
||||
python -m govoplan_core.commands.first_admin issue \
|
||||
--reason "initial production installation"
|
||||
```
|
||||
|
||||
The issue command fails when an active system administrator already exists,
|
||||
writes the random credential only to `FIRST_ADMIN_ENROLLMENT_FILE`, and does
|
||||
not print it. Check `GET /api/v1/bootstrap/status`, then submit the account
|
||||
and initial tenant fields to `POST /api/v1/bootstrap/first-admin` with the
|
||||
secret in `X-GovOPlaN-Enrollment-Token`. The operation creates the protected
|
||||
system owner and initial tenant-owner membership in one transaction and
|
||||
retires the credential. A repeated identical request returns the same result
|
||||
without creating another owner.
|
||||
|
||||
If the artifact is lost or expires before use, a local operator may rotate
|
||||
it only while no durable system administrator exists:
|
||||
|
||||
```bash
|
||||
python -m govoplan_core.commands.first_admin recover \
|
||||
--reason "expired installation handoff"
|
||||
```
|
||||
|
||||
Issue and recovery write hash-chained Core evidence and an audit event. They
|
||||
never enable or reuse `DEV_BOOTSTRAP_ENABLED`, `DEV_BOOTSTRAP_PASSWORD`, or
|
||||
`DEV_BOOTSTRAP_API_KEY`.
|
||||
6. Start the API service with `govoplan_core.server.app:app`.
|
||||
7. Start workers when `CELERY_ENABLED=true`.
|
||||
8. Start the WebUI/reverse proxy and verify CORS/cookie settings.
|
||||
|
||||
Reference in New Issue
Block a user