Skip to content

fix(postgres): support client certificate authentication (mTLS) - #666

Open
adisusilayasa wants to merge 2 commits into
TabularisDB:mainfrom
adisusilayasa:fix/postgres-client-cert-auth
Open

fix(postgres): support client certificate authentication (mTLS)#666
adisusilayasa wants to merge 2 commits into
TabularisDB:mainfrom
adisusilayasa:fix/postgres-client-cert-auth

Conversation

@adisusilayasa

Copy link
Copy Markdown

Description

Fixes PostgreSQL TLS connections when client certificates (ssl_cert) and private keys (ssl_key) are provided.

Previously, build_postgres_tls_connector in src-tauri/src/pool_manager.rs hardcoded .with_no_client_auth() across all SSL modes, causing PostgreSQL servers requiring client-side certificate authentication (e.g. Google Cloud SQL with mTLS enabled) to reject connections with connection requires a valid client certificate.

Changes

  • Added load_client_auth_from_pem to parse client certificates and private keys from PEM files using rustls_pemfile.
  • Updated build_postgres_tls_connector to attach client credentials via .with_client_auth_cert(...) when ssl_cert and ssl_key are supplied.
  • Included ssl_cert and ssl_key in build_connection_key for PostgreSQL connection pool keying.
  • Added unit tests covering client certificate loading, connector configuration, and pool key changes.

@kilo-code-bot

kilo-code-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • src-tauri/Cargo.lock
  • src-tauri/src/pool_manager.rs
  • src-tauri/src/pool_manager_tests.rs

Reviewed by glm-5.2 · Input: 53.9K · Output: 12.7K · Cached: 311.6K

@debba

debba commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Hi @adisusilayasa

Tested this locally against a Postgres 16 container with clientcert=verify-full in pg_hba.conf, which reproduces the Cloud SQL failure mode from the description. The fix works: without a client cert the server rejects with "connection requires a valid client certificate", with cert and key it connects and queries fine, and a cert signed by a different CA gets rejected as expected. All 66 pool_manager tests pass on the branch, including the new ones.

One edge case worth addressing before merge: build_postgres_tls_connector runs unconditionally, so with ssl_mode=disable the new code still reads and validates the cert/key files even though TLS is never negotiated (the pg config maps disable to PgSslMode::Disable). The connection modal hides the cert fields when SSL is disabled but doesn't clear them, so a connection that once had a client cert configured and was later switched to disable will now fail to connect if the PEM files were moved or deleted, or if only one of the two fields is set. Before this change those fields were simply ignored for postgres, so this is a small behavior regression. Skipping client auth loading when the mode is disable would restore the old behavior there:

let client_auth = if ssl_mode == "disable" {
    None
} else {
    match (user_cert, user_key) {
        // ...
    }
};

Small nit on test_load_client_auth_from_pem_valid: it writes fixed filenames into env::temp_dir(), so two test runs on the same machine can collide, and the cleanup lines never run if an assertion fails earlier. Using the tempfile crate would handle both.

Nothing else blocking from my side, the rest looks good.

aesslinger added a commit to TabularisDB/tabularis-postgresql-plugin that referenced this pull request Aug 19, 2026
ConnectionParams already carried ssl_cert and ssl_key, but
build_tls_connector never read them -- every TLS branch called
.with_no_client_auth() unconditionally, so servers requiring
client-certificate auth (e.g. Google Cloud SQL with mTLS enabled)
rejected connections with "connection requires a valid client
certificate," the same bug fixed upstream in the builtin driver
(TabularisDB/tabularis#666).

Added load_client_cert_from_pem, reusing the same
rustls::pki_types::pem::PemObject machinery as the existing
load_roots_from_pem rather than reintroducing rustls-pemfile (removed
in #21 for being unmaintained, RUSTSEC-2025-0134) -- PrivateKeyDer
supports PKCS1/SEC1/PKCS8 via the same trait, so no new dependency is
needed. Both TLS branches now present the client cert via
.with_client_auth_cert(...) when ssl_cert/ssl_key are set, and
build_tls_connector errors clearly if only one of the pair is
provided.

Left connection_key unchanged -- it doesn't currently key on
ssl_mode/ssl_ca either, so folding in just ssl_cert/ssl_key would be
inconsistent scope creep beyond "client certs don't work at all."

Fixes #34.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants