Harden deployment: configurable Postgres TLS, auth logging, multi-audience verify - #14
Merged
Conversation
…ience verify Fixes from a real self-hosted production setup (RDS + Cloudflare + Google Chat): - Postgres TLS is now configurable and libpq-compatible by default. The driver resolves `ssl` itself instead of letting node-pg treat sslmode=require as verify-full (which crash-loops on RDS/Cloud SQL/Neon with SELF_SIGNED_CERT_IN_CHAIN). Default: require = encrypt-without-verify; DB_SSL=verify-full + DB_SSL_CA for strict; DB_SSL=disable to turn off. A cert error now prints the exact fix instead of crash-looping. - /chat/events logs every arrival and the concrete 401 reason (missing header / aud mismatch / issuer mismatch / signature) using decoded claims only — never the token. Self-hosting is now debuggable. - The request verifier accepts multiple audiences, so a token whose aud is the app URL (Chat API "Audience" = App URL) is accepted as well as the project number; the dashboard field accepts a number and/or https URL. Tested against a real self-signed-cert Postgres: old raw sslmode=require fails (DEPTH_ZERO_SELF_SIGNED_CERT), new default connects, verify-full rejects without a CA and connects with DB_SSL_CA. Full suite (111) passes on SQLite and over TLS via Repo.postgres.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes surfaced by a real self-hosted production deployment (RDS + Cloudflare mTLS + Google Chat). See the three highest-impact issues from that setup.
Fix 1 — Postgres TLS is configurable, libpq-compatible by default 🔴
The driver now resolves the
ssloption itself instead of letting node-pg interpretsslmode. Recentpgtreatssslmode=requireas verify-full, which rejects managed databases (RDS/Cloud SQL/Neon/Supabase) using a private CA →SELF_SIGNED_CERT_IN_CHAINcrash-loop on first boot.require= encrypt-without-verify (what libpq/psycopg/JDBC/pgx all do)DB_SSL=verify-full+DB_SSL_CA=/path/ca.pemfor strict verificationDB_SSL=disableto turn TLS offFix 2 — request + auth-failure logging 🔴
/chat/eventswas a black box: a bad token returned a bare401and logged nothing, so "app not responding" was undebuggable. Now it logs every arrival (type=…) and, on rejection, the concrete reason —missing header/aud mismatch: got X, expected Y/issuer mismatch/signature— from decoded claims, never the token.Fix 3 — verifier accepts project number or app URL audience 🟡
Google Chat's "Audience" can be the project number or the app URL. The verifier hard-coded project-number-only, so an app-URL token was rejected even when correctly configured. It now accepts a list; the dashboard audience field takes a number and/or an https URL (space-separated).
Testing
sslmode=requirefails (DEPTH_ZERO_SELF_SIGNED_CERT), new default connects,verify-fullrejects without a CA and connects withDB_SSL_CA.Repo.postgres..env.example, configuration, server-setup).Not in this PR