diff --git a/fluxer_docs/src/content/docs/operator/configuration.mdx b/fluxer_docs/src/content/docs/operator/configuration.mdx index a7208860b..389c3ace3 100644 --- a/fluxer_docs/src/content/docs/operator/configuration.mdx +++ b/fluxer_docs/src/content/docs/operator/configuration.mdx @@ -388,7 +388,7 @@ Default `fluxer`. The password. The literal `fluxer` is rejected in production. #### `FLUXER_POSTGRES_SSL` -Default `false`. TLS to the database. Must be `true` or `false`. In production it must be `true` unless `FLUXER_SELF_HOSTED=true`. Compose forwards it from `.env`. +Default `false`. TLS to the database. Must be `true` or `false`. When `false`, an `sslmode` other than `prefer` in `FLUXER_POSTGRES_URL` still applies. In production it must be `true` unless `FLUXER_SELF_HOSTED=true`. Compose forwards it from `.env`. #### `FLUXER_POSTGRES_SSL_CA` diff --git a/fluxer_svc/src/postgres.rs b/fluxer_svc/src/postgres.rs index 197ea829d..df77970a6 100644 --- a/fluxer_svc/src/postgres.rs +++ b/fluxer_svc/src/postgres.rs @@ -62,7 +62,6 @@ impl PostgresConfig { } pub async fn connect(config: &PostgresConfig) -> anyhow::Result { - let has_url = config.url.is_some(); let mut pg = if let Some(url) = &config.url { PgConfig::from_str(url).context("failed to parse FLUXER_POSTGRES_URL")? } else { @@ -77,11 +76,7 @@ pub async fn connect(config: &PostgresConfig) -> anyhow::Result { pg }; - if config.ssl { - pg.ssl_mode(SslMode::Require); - } else if !has_url { - pg.ssl_mode(SslMode::Disable); - } + apply_ssl_mode(&mut pg, config.ssl); let tls = if pg.get_ssl_mode() == SslMode::Disable { build_disabled_tls_connector() @@ -111,6 +106,14 @@ pub async fn connect(config: &PostgresConfig) -> anyhow::Result { Ok(pool) } +fn apply_ssl_mode(pg: &mut PgConfig, ssl: bool) { + if ssl { + pg.ssl_mode(SslMode::Require); + } else if pg.get_ssl_mode() == SslMode::Prefer { + pg.ssl_mode(SslMode::Disable); + } +} + fn build_tls_connector(ca_pem: Option<&str>) -> anyhow::Result { let _ = rustls::crypto::ring::default_provider().install_default(); if let Some(ca_pem) = ca_pem.filter(|value| !value.trim().is_empty()) { @@ -780,6 +783,27 @@ mod tests { use super::*; use serde_json::json; + fn ssl_mode_for(url: &str, ssl: bool) -> SslMode { + let mut pg = PgConfig::from_str(url).unwrap(); + apply_ssl_mode(&mut pg, ssl); + pg.get_ssl_mode() + } + + #[test] + fn ssl_flag_decides_tls_unless_url_names_a_mode() { + let socket = "postgres://fluxer@/fluxer?host=/run/postgresql"; + assert_eq!(SslMode::Disable, ssl_mode_for(socket, false)); + assert_eq!(SslMode::Require, ssl_mode_for(socket, true)); + assert_eq!( + SslMode::Require, + ssl_mode_for("postgres://db.example.com/fluxer?sslmode=require", false) + ); + assert_eq!( + SslMode::Require, + ssl_mode_for("postgres://db.example.com/fluxer?sslmode=disable", true) + ); + } + #[test] fn encodes_row_keys_like_postgres_kv_executor() { assert_eq!(