From d82ffd664d1e269f24384883f4acd55f0dee697b Mon Sep 17 00:00:00 2001 From: Stephan Fitzpatrick Date: Fri, 14 Nov 2025 05:38:47 +0000 Subject: [PATCH] fix: use proper TLS connector for DuckLake instance catalog setup The setup_ducklake_catalog_db_inner function was using NoTls even when sslmode=require was set in the connection string, causing TLS handshake failures with AWS RDS PostgreSQL. This fix adds conditional TLS connector logic similar to pg_executor.rs: - Uses native_tls::TlsConnector with MakeTlsConnector when sslmode requires SSL - Accepts invalid certs/hostnames for compatibility with managed DB services - Falls back to NoTls for non-SSL connections Fixes the 'error performing TLS handshake: no TLS implementation configured' error when setting up DuckLake instance catalogs with RDS PostgreSQL. --- backend/windmill-api/src/settings.rs | 34 ++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/backend/windmill-api/src/settings.rs b/backend/windmill-api/src/settings.rs index 4851130286..9c5da2e20b 100644 --- a/backend/windmill-api/src/settings.rs +++ b/backend/windmill-api/src/settings.rs @@ -701,13 +701,33 @@ async fn setup_ducklake_catalog_db_inner( sslmode = ssl_mode ); - let (client, connection) = tokio::time::timeout( - std::time::Duration::from_secs(20), - tokio_postgres::connect(&conn_str, tokio_postgres::NoTls), - ) - .await - .map_err(|e| error::Error::ExecutionErr(format!("timeout: {}", e.to_string())))? - .map_err(|e| error::Error::ExecutionErr(format!("error: {}", e.to_string())))?; + let (client, connection) = if ssl_mode == "require" || ssl_mode == "verify-ca" || ssl_mode == "verify-full" { + use native_tls::TlsConnector; + use postgres_native_tls::MakeTlsConnector; + + let mut connector = TlsConnector::builder(); + connector.danger_accept_invalid_certs(true); + connector.danger_accept_invalid_hostnames(true); + + tokio::time::timeout( + std::time::Duration::from_secs(20), + tokio_postgres::connect( + &conn_str, + MakeTlsConnector::new(connector.build().map_err(to_anyhow)?), + ), + ) + .await + .map_err(|e| error::Error::ExecutionErr(format!("timeout: {}", e.to_string())))? + .map_err(|e| error::Error::ExecutionErr(format!("error: {}", e.to_string())))? + } else { + tokio::time::timeout( + std::time::Duration::from_secs(20), + tokio_postgres::connect(&conn_str, tokio_postgres::NoTls), + ) + .await + .map_err(|e| error::Error::ExecutionErr(format!("timeout: {}", e.to_string())))? + .map_err(|e| error::Error::ExecutionErr(format!("error: {}", e.to_string())))? + }; let join_handle = tokio::spawn(async move { connection.await }); logs.db_connect = "OK".to_string();