Wire schema v1 into a manual Supabase migration and vendor the real stack
- Move db/schema.sql to supabase/migrations/ as the first supabase CLI migration (manual `db push` only, no automated runner); re-add the gebos_ingest role + grants there since init.sql never re-runs - Add gebos-postgres-passwords oneshot on db-host: syncs role passwords from sops (LoadCredential, journal-safe), makes supabase_admin SUPERUSER and hands the auth schema to supabase_auth_admin to match the upstream supabase/postgres image; add pg_hba rule for 10.0.0.0/8 - Vendor the official docker-compose (studio/kong/auth/rest/meta only, external Postgres, loopback Studio with no Kong dashboard route) plus kong.yml (trimmed) and kong-entrypoint.sh (verbatim); tested: compose config, Kong config parse, migration applied on TimescaleDB pg17 - Document decisions as ADRs 0001-0004 (migrations, passwords, vendored stack, JWT API keys incl. verify/mint procedure) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# ADR-0002: Postgres role passwords are synced by a one-shot systemd unit
|
||||
|
||||
Date: 2026-07-08
|
||||
Status: Accepted
|
||||
|
||||
## Context
|
||||
|
||||
The Supabase services on app-host and the ingester on mqtt-ingest connect to
|
||||
db-host over TCP and need password auth, but every login role
|
||||
(`supabase_admin`, `supabase_auth_admin`, `authenticator`, `gebos_ingest`)
|
||||
was created passwordless.
|
||||
|
||||
NixOS deliberately offers **no declarative option** for Postgres passwords:
|
||||
anything the configuration references lands world-readable in `/nix/store`,
|
||||
and `initialScript` — the only built-in hook that could set one — runs solely
|
||||
at first initdb. Passwords are data, not configuration.
|
||||
|
||||
Two supporting gaps surfaced at the same time:
|
||||
|
||||
* NixOS's default `pg_hba.conf` covers only local sockets and loopback, so
|
||||
connections from 10.0.0.0/8 were rejected before password auth even
|
||||
started, firewall rule notwithstanding.
|
||||
* The upstream `supabase/postgres` image ships role *attributes* our vanilla
|
||||
Postgres lacked: `supabase_admin` is a SUPERUSER there (Studio/postgres-meta
|
||||
connect as it), and `supabase_auth_admin` owns the `auth` schema (GoTrue
|
||||
runs its own migrations in it at startup).
|
||||
|
||||
## Decision
|
||||
|
||||
A oneshot unit, `gebos-postgres-passwords` (`nix/modules/gebos-postgres.nix`),
|
||||
runs on db-host after `postgresql.service` on every boot/deploy:
|
||||
|
||||
* Runs as the `postgres` OS user (local peer auth); reads the sops-rendered
|
||||
env file via systemd `LoadCredential`, so the root-owned 0400 file needs no
|
||||
permission widening.
|
||||
* Idempotently syncs: `postgres` ← `postgres_admin_password`;
|
||||
`supabase_admin` / `supabase_auth_admin` / `authenticator` ← the shared
|
||||
`supabase_postgres_password` (mirroring upstream's single
|
||||
`POSTGRES_PASSWORD` convention); `gebos_ingest` ←
|
||||
`ingester_postgres_password`.
|
||||
* Enforces the two upstream attributes: `supabase_admin SUPERUSER` and
|
||||
`ALTER SCHEMA auth OWNER TO supabase_auth_admin`.
|
||||
* Guards every role for existence (tolerates a cluster the schema-v1
|
||||
migration hasn't reached) and discards query output
|
||||
(`--output=/dev/null`) so passwords never reach the journal.
|
||||
* db-host enables the `supabase` and `ingester` secret toggles solely to get
|
||||
those keys into its env file; `.sops.yaml`'s single key group already
|
||||
permits this.
|
||||
* `pg_hba` gains `host all all 10.0.0.0/8 scram-sha-256`.
|
||||
|
||||
## Consequences
|
||||
|
||||
* No password ever exists in git, the nix store, or SQL files; rotation is
|
||||
`sops nix/secrets/secrets.yaml` + deploy + `systemctl restart
|
||||
gebos-postgres-passwords` (the unit does not auto-rerun on secret-content
|
||||
changes alone).
|
||||
* The three Supabase roles share one password by design — per-role passwords
|
||||
would diverge from the vendored compose, which interpolates a single
|
||||
`${POSTGRES_PASSWORD}` everywhere.
|
||||
* db-host can decrypt the Supabase JWT/API-key secrets it doesn't strictly
|
||||
need; acceptable until `.sops.yaml` moves to per-prefix rules (noted there).
|
||||
Reference in New Issue
Block a user