ADR-0002: Auth-Proxy PgBouncer mTLS
- Status: accepted (CN-Mapping superseded durch ADR-0031; Proxy/mTLS bleibt)
- Datum: 2026-08-26
- Phase: P-SEC
- Lastenheft: INF-04, INF-05, INF-06, Q-05
Kontext
QGIS spricht das Postgres-Wire-Protokoll. Zuvor: gemeinsames Passwort, plain TCP :3401 hinter WireGuard. Apps (Editor, Dashboard) brauchen Postgres nicht öffentlich. Design: Datenbankzugang.
Entscheidung
PgBouncer 1.24.x (edoburu/pgbouncer:v1.24.1-p1 per Digest, nicht :latest) als mTLS-Auth-Proxy:
client_tls_sslmode=verify-full,client_tls_protocols=secure(TLS 1.2/1.3)- interne CA; Client-Zertifikat pro Person/Gerät
- Mapping CN → Mandanten-Rolle
{slug}_edit/{slug}_read(ADR-0031); Control-DB behältlinetra_edit/linetra_read - keine per-Person-Postgres-Rollen
- Passwort-Auth von außen aus; Audit loggt CN
- PostGIS unpublished (nur Compose-Netz)
QGIS: sslmode=verify-full + Client-Zertifikat + CA. Development-API auf der Workstation darf denselben Proxy nutzen (ADR-0013); Production-FastAPI bleibt intern postgres:5432.
Begründung
Es gibt bereits genau zwei GRANT-Profile. Geteiltes Passwort ist das Problem, nicht die zwei Rollen. Widerruf = Zertifikat sperren, nicht DROP ROLE. PgBouncer spricht libpq/SSLRequest korrekt; Traefik-TLS auf 3401 nicht.
Verworfene Alternativen
| Alternative | Warum verworfen |
|---|---|
| Teleport Database Access | Zusätzliche Identity-Plattform für ein kleines Team; Betriebskosten ohne Mehrwert solange zwei Rollen reichen |
Login-Rolle pro Person (INHERIT) |
RLS/GRANT personenscharf ist nicht nötig; Pflege von Dutzenden Rollen |
Traefik-TLS auf TCP :3401 |
libpq sendet SSLRequest, kein TLS-ClientHello — silent failure |
| Passwort + TLS öffentlich | Geteiltes linetra_edit, brute-force, kein Gerätebezug |
| Nur API, kein Live-Postgres für QGIS | INT-01-Export reicht nicht für den Übergang; QGIS bleibt Produktions-Write-UI bis P3 abgenommen |
Folgen
Compose-Profil mtls ist der live QGIS-Pfad. Traefik TCP :3401 auf wg0 ist zu (ADR-0003). FastAPI verbindet weiter intern nach postgres:5432. TLS steckt in PgBouncer, nicht in Traefik.