feature: the web service creates its key and database itself and shows its starting phase.
Release / release (push) Successful in 29s

This commit is contained in:
slawek committed 2026-10-24 09:07:28 +02:00
1 parent 4f1aa282f6
commit 2e2bacee7d
8 files changed
+245 -37

No files matched your search

+27 -3
View File
@@ -64,7 +64,7 @@ The service listens on plain HTTP on the internal network.
Decision: `/config`, `/users` and `/groups` need a JWT in an `Authorization: Bearer` header,
HS256, verified with `hmac` and `hashlib`; no other algorithm is accepted. The key is
`/etc/vpn-router/web.key`, random, made by `vpn-router-setup` on the router and readable by root
`/etc/vpn-router/web.key`, random, made by the web service on its first run and readable by root
only; it is never configured or output, and `web.jwt_secret` is ignored. The router itself issues
the tokens: `POST /auth` checks a user's password and TOTP code with a bind (ADR-14) and answers
an access token naming the user in `sub`, valid for 5 minutes, and a refresh token valid for 8
@@ -337,8 +337,8 @@ sessions in PostgreSQL too.
Decision: Refresh tokens are random strings, stored as their SHA-256 with the user name and the
expiry in the table `refresh_tokens`, through psycopg 3 (`python3-psycopg`). The database is
`web.database`, or by default the database and role `vpn-router` on the router, which
`vpn-router-setup` creates with `runuser -u postgres -- psql` and a random password in
`web.database`, or by default the database and role `vpn-router` on the router, which the web
service creates on its first run (ADR-16) with `runuser -u postgres -- psql` and a random password in
`/etc/vpn-router/database.secret`, reached over TCP on `localhost`, as Ubuntu's `pg_hba.conf`
takes peer authentication on the local socket. A refresh token is used once: refreshing deletes
it and issues a new one, after checking that the user is neither disabled nor locked.
@@ -347,3 +347,27 @@ Consequences: The package depends on `postgresql` and `python3-psycopg`. A stole
no usable token. Changing a user's password, disabling, unlocking or removing the user, and
signing out, end the user's sessions at once; an access token already issued lives out its
5 minutes.
## ADR-16: Each service creates what it needs on its first run and shows its starting phase
Status: Accepted
Context: The package manager configures packages in an order of its own; on a new VM the Router
Manager was configured before the PostgreSQL server, so a database created at installation was
missing. PostgreSQL may also start after the services at boot. A router whose setup fails can
be unreachable, and the reason must be visible without a shell where possible.
Decision: The web service makes its signing key and creates the refresh tokens' database itself,
and the Router Manager its sessions database; neither `vpn-router-setup` nor a maintainer script
creates them. Each service starts with a starting phase: an initialization thread does the work
and retries every 15 seconds until it succeeds, and meanwhile the service listens as usual but
serves only a page of its phase and the failure of the last attempt, answering 503. The web
service also shows the state, the step and the failure of the last run of `vpn-router-setup`,
which setup records in `/run/vpn-router/setup.json` at every step; `vpnrouter.fail` ends with a
`SystemExit` carrying its message, so setup records it. Once the initialization succeeds, the
service serves its real pages.
Consequences: The order of installation and of the start of PostgreSQL does not matter; a
database that cannot be created shows why on the status page and is created once the cause is
gone. The web unit may write `/etc/vpn-router` for the key and the database password. While the
web service starts, `/status` is not the router's status, and clients see 503.