From 1e40a4252408f4a8b120d50f334f1f7526800e73 Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Wed, 26 Apr 2023 10:38:25 +0200 Subject: [PATCH] Support database connection via SSL This is required to use managed Postgres databases. It is necessary to use SSL connection to the remote host as the connection goes through the open internet. --- .gitignore | 4 ++ build/.gitkeep | 0 fedimovies-cli/src/main.rs | 2 +- fedimovies-config/src/config.rs | 2 + fedimovies-models/Cargo.toml | 3 +- fedimovies-models/src/database/mod.rs | 57 +++++++++++++++++++++------ src/main.rs | 6 ++- 7 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 build/.gitkeep diff --git a/.gitignore b/.gitignore index e63cca3..89e5bab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ .env.local config.yaml +/secret/* /files/* !/files/.gitkeep +/build/* +!/build/.gitkeep /target +fly.toml diff --git a/build/.gitkeep b/build/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fedimovies-cli/src/main.rs b/fedimovies-cli/src/main.rs index f8e601e..ff351fd 100644 --- a/fedimovies-cli/src/main.rs +++ b/fedimovies-cli/src/main.rs @@ -25,7 +25,7 @@ async fn main() { } let db_config = config.database_url.parse().unwrap(); - let db_client = &mut create_database_client(&db_config).await; + let db_client = &mut create_database_client(&db_config, config.tls_ca_file.as_ref().map(|p| p.as_path())).await; apply_migrations(db_client).await; match subcmd { diff --git a/fedimovies-config/src/config.rs b/fedimovies-config/src/config.rs index b994f60..0db6280 100644 --- a/fedimovies-config/src/config.rs +++ b/fedimovies-config/src/config.rs @@ -33,6 +33,8 @@ pub struct Config { // Core settings pub database_url: String, + #[serde(default)] + pub tls_ca_file: Option, pub storage_dir: PathBuf, pub web_client_dir: Option, diff --git a/fedimovies-models/Cargo.toml b/fedimovies-models/Cargo.toml index fda98a7..69aae0a 100644 --- a/fedimovies-models/Cargo.toml +++ b/fedimovies-models/Cargo.toml @@ -27,6 +27,8 @@ thiserror = "1.0.37" # Async runtime tokio = { version = "1.20.4", features = [] } # Used for working with Postgresql database +openssl = { version = "0.10", features = ["vendored"] } +postgres-openssl = "0.5.0" tokio-postgres = { version = "0.7.6", features = ["with-chrono-0_4", "with-uuid-1", "with-serde_json-1"] } postgres-types = { version = "0.2.3", features = ["derive", "with-chrono-0_4", "with-uuid-1", "with-serde_json-1"] } postgres-protocol = "0.6.4" @@ -38,7 +40,6 @@ uuid = { version = "1.1.2", features = ["serde", "v4"] } [dev-dependencies] fedimovies-utils = { path = "../fedimovies-utils", features = ["test-utils"] } - serial_test = "0.7.0" [features] diff --git a/fedimovies-models/src/database/mod.rs b/fedimovies-models/src/database/mod.rs index 71caf00..a8b707f 100644 --- a/fedimovies-models/src/database/mod.rs +++ b/fedimovies-models/src/database/mod.rs @@ -1,3 +1,7 @@ +use deadpool_postgres::SslMode; +use openssl::ssl::{SslConnector, SslMethod}; +use postgres_openssl::MakeTlsConnector; +use std::path::Path; use tokio_postgres::config::Config as DatabaseConfig; use tokio_postgres::error::{Error as PgError, SqlState}; @@ -11,6 +15,7 @@ pub mod test_utils; pub type DbPool = deadpool_postgres::Pool; pub use tokio_postgres::GenericClient as DatabaseClient; +use tokio_postgres::NoTls; #[derive(thiserror::Error, Debug)] #[error("database type error")] @@ -37,21 +42,49 @@ pub enum DatabaseError { AlreadyExists(&'static str), // object type } -pub async fn create_database_client(db_config: &DatabaseConfig) -> tokio_postgres::Client { - let (client, connection) = db_config.connect(tokio_postgres::NoTls).await.unwrap(); - tokio::spawn(async move { - if let Err(err) = connection.await { - log::error!("connection error: {}", err); - }; - }); +pub async fn create_database_client( + db_config: &DatabaseConfig, + ca_file_path: Option<&Path>, +) -> tokio_postgres::Client { + let client = if let Some(ca_file_path) = ca_file_path { + let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); + log::debug!("Using TLS CA file: {}", ca_file_path.display()); + builder.set_ca_file(ca_file_path).unwrap(); + let connector = MakeTlsConnector::new(builder.build()); + let (client, connection) = db_config.connect(connector).await.unwrap(); + tokio::spawn(async move { + if let Err(err) = connection.await { + log::error!("connection with tls error: {}", err); + }; + }); + client + } else { + let (client, connection) = db_config.connect(tokio_postgres::NoTls).await.unwrap(); + tokio::spawn(async move { + if let Err(err) = connection.await { + log::error!("connection error: {}", err); + }; + }); + client + }; + client } -pub fn create_pool(database_url: &str, pool_size: usize) -> DbPool { - let manager = deadpool_postgres::Manager::new( - database_url.parse().expect("invalid database URL"), - tokio_postgres::NoTls, - ); +pub fn create_pool(database_url: &str, ca_file_path: Option<&Path>, pool_size: usize) -> DbPool { + let manager = if let Some(ca_file_path) = ca_file_path { + let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); + log::info!("Using TLS CA file: {}", ca_file_path.display()); + builder.set_ca_file(ca_file_path).unwrap(); + let connector = MakeTlsConnector::new(builder.build()); + deadpool_postgres::Manager::new( + database_url.parse().expect("invalid database URL"), + connector, + ) + } else { + deadpool_postgres::Manager::new(database_url.parse().expect("invalid database URL"), NoTls) + }; + DbPool::builder(manager) .max_size(pool_size) .build() diff --git a/src/main.rs b/src/main.rs index 6e05b6d..689374e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,11 @@ async fn main() -> std::io::Result<()> { // https://wiki.postgresql.org/wiki/Number_Of_Database_Connections let db_pool_size = num_cpus::get() * 2; - let db_pool = create_pool(&config.database_url, db_pool_size); + let db_pool = create_pool( + &config.database_url, + config.tls_ca_file.as_ref().map(|s| s.as_path()), + db_pool_size, + ); let mut db_client = get_database_client(&db_pool).await.unwrap(); apply_migrations(&mut db_client).await;