You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit f16dc5e
Browse filesBrowse the repository at this point in the historyBrowse files
Support sslcert/sslkey client certificate authentication for PostgreSQL (#441)
* Support sslcert/sslkey client certificate auth for PostgreSQL
PostgreSQL servers that enforce certificate authentication in pg_hba.conf
(`hostssl ... cert`, `clientcert=verify-*`) reject DBHub with "connection
requires a valid client certificate" because the DSN parser only read
sslmode and sslrootcert. Add the standard libpq `sslcert` / `sslkey`
parameters, accepted both as DSN query params and as TOML source fields.
Connector (src/connectors/postgres/index.ts):
- Read sslcert/sslkey and pass the PEM contents to node-postgres as TLS
`cert`/`key`, on top of whatever the sslmode branch already built
(require keeps rejectUnauthorized=false; verify-* keep CA handling).
- Fail fast on an inconsistent DSN: one of the pair without the other, or
a client cert with sslmode=disable / unset (node-postgres would silently
drop it on a plaintext connection). Encrypted PEM keys are rejected with
a clear message instead of Node's opaque decoder error.
- Share the ~/ expansion + FailedToReadCertificate wrapping across all
three SSL files.
TOML loader (src/config/toml-loader.ts):
- New sslcert/sslkey fields: PostgreSQL only, both-or-neither, sslmode in
require/verify-ca/verify-full, file must exist and be readable.
- ~/ expansion, backfill from DSN, DSN/field conflict check, and DSN
building all mirror sslrootcert via shared helpers.
Tests cover the parser and loader rules, plus a new Testcontainers suite
that boots Postgres with `hostssl all all all cert` and verifies a cert
connection succeeds (client_dn = CN=user) and a cert-less one is refused.
Docs: docs/config/toml.mdx, docs/config/command-line.mdx,
dbhub.toml.example, CLAUDE.md.
Closes#439
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012UzToxWXzC7oQ9xMnhM192
* Align sslcert/sslkey docs with the require/verify-ca/verify-full restriction
Address review: CLAUDE.md and the postgresSslFileParams comment said
client certificates apply in "any TLS mode", but disable and an unset
sslmode are rejected. Name the three accepted modes explicitly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012UzToxWXzC7oQ9xMnhM192
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CLAUDE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -176,7 +176,7 @@ outside TOML and follow the same order:
176
176
- SQL Server (NTLM): `sqlserver://user:password@localhost:1433/dbname?authentication=ntlm&domain=MYDOMAIN`
177
177
- Oracle: `oracle://user:password@localhost:1521/FREEPDB1` (path is the service name; `?sid=ORCL` for a SID; `sslmode=require`/`verify-full` switch to TCPS)
178
178
- SQLite: `sqlite:///path/to/database.db` or `sqlite:///:memory:`
179
-
- SSL modes: `sslmode=disable` (no SSL), `sslmode=require` (SSL without cert verification), `sslmode=verify-ca` (PostgreSQL only, CA verification), `sslmode=verify-full` (PostgreSQL and Oracle, CA + hostname verification). Use `sslrootcert` to specify CA certificate path for verify modes.
179
+
- SSL modes: `sslmode=disable` (no SSL), `sslmode=require` (SSL without cert verification), `sslmode=verify-ca` (PostgreSQL only, CA verification), `sslmode=verify-full` (PostgreSQL and Oracle, CA + hostname verification). Use `sslrootcert` to specify CA certificate path for verify modes. PostgreSQL client certificate auth: `sslcert` + `sslkey` (PEM, unencrypted, both required; `sslmode` must be `require`, `verify-ca` or `verify-full` — `disable` or unset is rejected) in the DSN or TOML source.
Copy file name to clipboardExpand all lines: docs/config/toml.mdx
+42Lines changed: 42 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -419,6 +419,46 @@ Sources define database connections. Each source represents a database that DBHu
419
419
</Tip>
420
420
</ParamField>
421
421
422
+
### sslcert / sslkey
423
+
424
+
<ParamFieldpath="sslcert"type="string">
425
+
Path to a PEM client certificate for **client certificate authentication**. Use when the server enforces `hostssl ... cert` or `clientcert=verify-ca` / `verify-full` in `pg_hba.conf` and rejects connections with `connection requires a valid client certificate`.
426
+
427
+
Must be set together with `sslkey`, and requires `sslmode` to be `require`, `verify-ca` or `verify-full` (the certificate is only presented over TLS). It is independent of `sslrootcert`: `require` + `sslcert`/`sslkey` authenticates the client without verifying the server.
428
+
429
+
Supports `~/` path expansion.
430
+
431
+
**PostgreSQL only.**
432
+
</ParamField>
433
+
434
+
<ParamFieldpath="sslkey"type="string">
435
+
Path to the PEM private key for `sslcert`. The key must be **unencrypted** (an encrypted key is rejected at startup; `sslpassword` is not supported). DER-encoded keys are not accepted.
436
+
437
+
Keep the key file private (`chmod 0600`); DBHub reads it once at startup and never logs its contents.
438
+
439
+
Supports `~/` path expansion.
440
+
441
+
**PostgreSQL only.**
442
+
443
+
```toml
444
+
[[sources]]
445
+
id = "dev"
446
+
type = "postgres"
447
+
host = "db.example.internal"
448
+
database = "app"
449
+
user = "app"
450
+
password = "${PG_PASSWORD}"
451
+
sslmode = "verify-ca"
452
+
sslrootcert = "~/.certs/ca.crt"
453
+
sslcert = "~/.certs/client.crt"
454
+
sslkey = "~/.certs/client.key"
455
+
```
456
+
457
+
<Tip>
458
+
Can also be set via DSN query parameters: `?sslmode=require&sslcert=/path/to/client.crt&sslkey=/path/to/client.key`
459
+
</Tip>
460
+
</ParamField>
461
+
422
462
### instanceName
423
463
424
464
<ParamFieldpath="instanceName"type="string">
@@ -856,6 +896,8 @@ default = 10
856
896
|`pool_max_connections`| integer | ❌ | PostgreSQL pool size per process and source (default: `10`, range: `1`-`1000`) |
0 commit comments