From e3d8c967f593e0ceb1012521a68d4d606acb270a Mon Sep 17 00:00:00 2001 From: Sandro Eiler Date: Sun, 4 Feb 2024 14:03:52 +0100 Subject: [PATCH] feat: protect secrets --- Cargo.lock | 11 +++++++++++ Cargo.toml | 5 +++-- src/configuration.rs | 27 ++++++++++++++++++--------- src/main.rs | 8 +++++--- tests/health_check.rs | 10 ++++++---- 5 files changed, 43 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80ce350..e48156c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1044,6 +1044,7 @@ dependencies = [ "hyper 1.1.0", "once_cell", "reqwest", + "secrecy", "serde", "serde_json", "sqlx", @@ -1804,6 +1805,16 @@ dependencies = [ "untrusted", ] +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "security-framework" version = "2.9.1" diff --git a/Cargo.toml b/Cargo.toml index bcc7bbd..4c5773e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,15 +25,16 @@ axum = { version = "0.7" } # tower-cookies = "0.10" # Others config = "0.14" +uuid = { version = "1", features = ["v4", "fast-rng"] } +chrono = { version = "0.4", default-features = false, features = ["clock"] } tracing = { version = "0.1", features = ["log"] } tracing-subscriber = { version = "0.3", features = ["registry", "env-filter"] } tracing-bunyan-formatter = "0.3" tracing-log = "0.2" +secrecy = { version = "0.8", features = ["serde"] } # lazy-regex = "3" # async-trait = "0.1" # strum_macros = "0.25" -uuid = { version = "1", features = ["v4", "fast-rng"] } -chrono = { version = "0.4", default-features = false, features = ["clock"] } [dependencies.sqlx] version = "0.7" diff --git a/src/configuration.rs b/src/configuration.rs index 5966698..9c4d6b6 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,3 +1,5 @@ +use secrecy::{ExposeSecret, Secret}; + #[derive(serde::Deserialize)] /// The application's settings /// @@ -18,7 +20,7 @@ pub struct Settings { /// * `name`: the DB name pub struct DatabaseSettings { pub username: String, - pub password: String, + pub password: Secret, pub port: u16, pub host: String, pub name: String, @@ -38,17 +40,24 @@ pub fn get_configuration() -> Result { } impl DatabaseSettings { - pub fn connection_string(&self) -> String { - format!( + pub fn connection_string(&self) -> Secret { + Secret::new(format!( "postgres://{}:{}@{}:{}/{}", - self.username, self.password, self.host, self.port, self.name - ) + self.username, + self.password.expose_secret(), + self.host, + self.port, + self.name + )) } - pub fn connection_string_without_db(&self) -> String { - format!( + pub fn connection_string_without_db(&self) -> Secret { + Secret::new(format!( "postgres://{}:{}@{}:{}", - self.username, self.password, self.host, self.port - ) + self.username, + self.password.expose_secret(), + self.host, + self.port + )) } } diff --git a/src/main.rs b/src/main.rs index 0252aad..2ad4ada 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use learn_axum::configuration::get_configuration; use learn_axum::startup; use learn_axum::telemetry::{get_subscriber, init_subscriber}; +use secrecy::ExposeSecret; use sqlx::PgPool; use tokio::net::TcpListener; @@ -14,8 +15,9 @@ async fn main() { let configuration = get_configuration().expect("Failed to read configuration."); let addr = format!("127.0.0.1:{}", configuration.application_port); let listener = TcpListener::bind(addr).await.unwrap(); //.expect("Unable to bind to port"); - let connection_pool = PgPool::connect(&configuration.database.connection_string()) - .await - .expect("Failed to connect to Postgres."); + let connection_pool = + PgPool::connect(configuration.database.connection_string().expose_secret()) + .await + .expect("Failed to connect to Postgres."); startup::run(listener, connection_pool).await.unwrap(); } diff --git a/tests/health_check.rs b/tests/health_check.rs index ced8497..c23b603 100644 --- a/tests/health_check.rs +++ b/tests/health_check.rs @@ -1,6 +1,7 @@ use learn_axum::configuration::{get_configuration, DatabaseSettings}; use learn_axum::telemetry::{get_subscriber, init_subscriber}; use once_cell::sync::Lazy; +use secrecy::ExposeSecret; use sqlx::{Connection, Executor, PgConnection, PgPool}; use tokio::net::TcpListener; use uuid::Uuid; @@ -128,16 +129,17 @@ async fn spawn_app() -> TestApp { pub async fn configure_database(config: &DatabaseSettings) -> PgPool { // Create database - let mut connection = PgConnection::connect(&config.connection_string_without_db()) - .await - .expect("Failed to connect to Postgres"); + let mut connection = + PgConnection::connect(&config.connection_string_without_db().expose_secret()) + .await + .expect("Failed to connect to Postgres"); connection .execute(format!(r#"CREATE DATABASE "{}";"#, config.name).as_str()) .await .expect("Failed to create database."); // Migrate database - let connection_pool = PgPool::connect(&config.connection_string()) + let connection_pool = PgPool::connect(&config.connection_string().expose_secret()) .await .expect("Failed to connect to Postgres."); sqlx::migrate!("./migrations")