provision-env-db: revoke PUBLIC connect on the owner database too #108

Merged
admin_emi merged 2 commits from fix/harden-owner-db-connect into dev 2026-07-26 07:17:21 +00:00

2 commits

Author SHA1 Message Date
Emi Griffith
24b7ef4c86 runbook: chown the new Caddy log before reloading
All checks were successful
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / build-backend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 1s
`caddy validate` run as root creates the log files the config names, owned by
root. The caddy user then cannot open them and the reload fails with
'permission denied' on the log writer — which is exactly what happened on the
live cutover, and what the root-owned centralis.log in that directory is a
fossil of.

Caddy rejected the config atomically and kept serving prod on the old one, so
nothing broke; but the step reads as a no-op until it isn't.
2026-07-26 00:16:36 -07:00
Emi Griffith
1aeea6bdc5 provision-env-db: revoke PUBLIC connect on the OWNER database too
All checks were successful
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 6s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 1s
Revoking PUBLIC's CONNECT on the guest's own database is the half that does not
matter. A fresh Postgres database carries '=Tc' for PUBLIC — TEMP and CONNECT —
so as soon as a second role exists on the instance it can open a session against
every database still holding the default.

Provisioning beta and stopping there left thermograph_beta able to connect to
prod's database. The runbook's isolation check caught it on the live cutover;
this makes the script produce the state that check expects instead of a false
sense of it.

Grants the owner's read-only role an explicit CONNECT before the revoke, so the
ad-hoc query path (ops/dbq.sh, which connects as thermograph_ro) cannot lose
access to prod. The owner's app role owns the database and is a superuser, so it
is unaffected either way.
2026-07-26 00:12:25 -07:00