BBetterSignΒ· Web app β Postgres, mutually authenticated
1 / 5
The app authenticates to Postgres with a password in its connection string
π
web app
π password in DATABASE_URL
βββΆ psql
π
Postgres
caller: ???
password only
π₯·
anyone with the password
looks the same to Postgres
gets in
The password sits in env files and code, gets copied across deploys, and leaks. Postgres cannot prove the caller is really your app.
πvlad-ca β trusts VLADs that pass enrollment
π Postgres enrolls
β prove control of its VLAD β challenge / signed response β vlad-ca issues its cert
π web app enrolls
β prove control of its VLAD β challenge / signed response β vlad-ca issues its cert
The vlad-ca trusts each instance because it enrolled β it cryptographically proved control of its VLAD, so the CA issues it a short-lived certificate.
The database owner decides which vlad-ca to trust as its one root
π’
in-house vlad-ca
the owner runs it
β or β
π€
trusted 3rd-party vlad-ca
a provider they trust
postgresql.conf ssl = on ssl_ca_file = the chosen vlad-ca root# trust ONLY this vlad-ca pg_hba.conf: hostssl β¦ clientcert=verify-full
Once the owner points Postgres at that root, it accepts a client because its certificate came from the trusted vlad-ca β including the web app's β and refuses anything that did not.
The web app connects β both sides prove themselves against the vlad-ca
π
web app
presents vlad-ca cert
β verified by Postgres
ββββΆ mutual TLS
π
Postgres
presents vlad-ca cert
β verified by app
π₯·
rogue app
cert from a different CA
β rejected β not signed by vlad-ca
Encrypted + mutually authenticated β no password in files or code. Imposters are rejected because their cert did not come from the vlad-ca.
The certificates are short-lived and renew with the vlad-ca on a regular cadence
π Postgres rotates
β new key β signed plog entry β‘ ask vlad-ca for a cert β’ β fresh cert for the new key
β» on a regular cadence
π web app rotates
β new key β signed plog entry β‘ ask vlad-ca for a cert β’ β fresh cert for the new key
β» on a regular cadence
Connections stay up. Rotation is just a plog update plus a cert request Β· no re-enrollment, no hand-rotation Β· Postgres keeps trusting because it trusts the vlad-ca, not a pinned cert