From 952164e5909e5aee12750e735ca3532eb6c45a0b Mon Sep 17 00:00:00 2001 From: Wes Medford Date: Fri, 20 Dec 2024 20:17:33 -0700 Subject: [PATCH 1/4] (feat) add audit logging plugin. Signed-off-by: Wes Medford --- src/config.rs | 10 +++++- src/plugins/audit_logger.rs | 71 +++++++++++++++++++++++++++++++++++++ src/plugins/mod.rs | 2 ++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/plugins/audit_logger.rs diff --git a/src/config.rs b/src/config.rs index b0d98fb5..0268b30e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -883,6 +883,7 @@ pub struct Plugins { pub intercept: Option, pub table_access: Option, pub query_logger: Option, + pub audit_logger: Option, pub prewarmer: Option, } @@ -901,10 +902,11 @@ impl std::fmt::Display for Plugins { } write!( f, - "interceptor: {}, table_access: {}, query_logger: {}, prewarmer: {}", + "interceptor: {}, table_access: {}, query_logger: {}, audit_logger: {}, prewarmer: {}", is_enabled(self.intercept.as_ref()), is_enabled(self.table_access.as_ref()), is_enabled(self.query_logger.as_ref()), + is_enabled(self.audit_logger.as_ref()), is_enabled(self.prewarmer.as_ref()), ) } @@ -939,6 +941,12 @@ pub struct QueryLogger { pub enabled: bool, } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Hash, Eq)] +pub struct AuditLogger { + pub enabled: bool, + pub patterns: Vec, +} + impl Plugin for QueryLogger { fn is_enabled(&self) -> bool { self.enabled diff --git a/src/plugins/audit_logger.rs b/src/plugins/audit_logger.rs new file mode 100644 index 00000000..f02bfb9b --- /dev/null +++ b/src/plugins/audit_logger.rs @@ -0,0 +1,71 @@ +//! Plugin for sanitizing and logging queries and their results +//! Replaces sensitive data matching configured regex patterns with + +use async_trait::async_trait; +use log::info; +use regex::Regex; +use sqlparser::ast::Statement; + +use crate::{ + errors::Error, + plugins::{Plugin, PluginOutput}, + query_router::QueryRouter, +}; + +#[derive(Clone)] +pub struct AuditLogger<'a> { + pub enabled: bool, + pub patterns: &'a Vec, + compiled_patterns: Vec, +} + +impl<'a> AuditLogger<'a> { + pub fn new(enabled: bool, patterns: &'a Vec) -> Result { + let compiled_patterns = patterns + .iter() + .map(|p| Regex::new(p)) + .collect::, regex::Error>>() + .map_err(|e| Error::BadConfig)?; + + Ok(AuditLogger { + enabled, + patterns, + compiled_patterns, + }) + } + + fn sanitize(&self, text: &str) -> String { + let mut sanitized = text.to_string(); + for pattern in &self.compiled_patterns { + sanitized = pattern.replace_all(&sanitized, "").to_string(); + } + sanitized + } +} + +#[async_trait] +impl<'a> Plugin for AuditLogger<'a> { + async fn run( + &mut self, + query_router: &QueryRouter, + ast: &Vec, + ) -> Result { + if !self.enabled { + return Ok(PluginOutput::Allow); + } + + // Log sanitized queries + for stmt in ast { + let query = stmt.to_string(); + let sanitized = self.sanitize(&query); + info!( + "[pool: {}][user: {}] Query: {}", + query_router.pool_settings().db, + query_router.pool_settings().user.username, + sanitized + ); + } + + Ok(PluginOutput::Allow) + } +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index f1076d06..ef769c37 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -11,6 +11,7 @@ pub mod intercept; pub mod prewarmer; pub mod query_logger; +pub mod audit_logger; pub mod table_access; use crate::{errors::Error, query_router::QueryRouter}; @@ -20,6 +21,7 @@ use sqlparser::ast::Statement; pub use intercept::Intercept; pub use query_logger::QueryLogger; +pub use audit_logger::AuditLogger; pub use table_access::TableAccess; #[derive(Clone, Debug, PartialEq)] From 0bfc74db2a561696a916bddb4519f1eb6689c4f6 Mon Sep 17 00:00:00 2001 From: Wes Medford Date: Fri, 20 Dec 2024 20:41:01 -0700 Subject: [PATCH 2/4] (lint) fix lint Signed-off-by: Wes Medford --- src/plugins/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index ef769c37..43fff602 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -8,10 +8,10 @@ //! - etc //! +pub mod audit_logger; pub mod intercept; pub mod prewarmer; pub mod query_logger; -pub mod audit_logger; pub mod table_access; use crate::{errors::Error, query_router::QueryRouter}; @@ -19,9 +19,9 @@ use async_trait::async_trait; use bytes::BytesMut; use sqlparser::ast::Statement; +pub use audit_logger::AuditLogger; pub use intercept::Intercept; pub use query_logger::QueryLogger; -pub use audit_logger::AuditLogger; pub use table_access::TableAccess; #[derive(Clone, Debug, PartialEq)] From 2774035e2206be84d91cad10d133b3222b7af267 Mon Sep 17 00:00:00 2001 From: Wes Medford Date: Fri, 20 Dec 2024 20:52:28 -0700 Subject: [PATCH 3/4] (fix) create default implementation for plugins Signed-off-by: Wes Medford --- src/config.rs | 20 +++++++++++++++++++- src/plugins/audit_logger.rs | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index 0268b30e..c20ed23b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -878,7 +878,7 @@ impl Default for Shard { } } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Hash, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash, Eq)] pub struct Plugins { pub intercept: Option, pub table_access: Option, @@ -887,6 +887,18 @@ pub struct Plugins { pub prewarmer: Option, } +impl Default for Plugins { + fn default() -> Self { + Self { + intercept: None, + table_access: None, + query_logger: None, + audit_logger: None, + prewarmer: None, + } + } +} + pub trait Plugin { fn is_enabled(&self) -> bool; } @@ -953,6 +965,12 @@ impl Plugin for QueryLogger { } } +impl Plugin for AuditLogger { + fn is_enabled(&self) -> bool { + self.enabled + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Hash, Eq)] pub struct Prewarmer { pub enabled: bool, diff --git a/src/plugins/audit_logger.rs b/src/plugins/audit_logger.rs index f02bfb9b..4324faa8 100644 --- a/src/plugins/audit_logger.rs +++ b/src/plugins/audit_logger.rs @@ -25,7 +25,7 @@ impl<'a> AuditLogger<'a> { .iter() .map(|p| Regex::new(p)) .collect::, regex::Error>>() - .map_err(|e| Error::BadConfig)?; + .map_err(|_e| Error::BadConfig)?; Ok(AuditLogger { enabled, From 1d724599491ab50931e85aab8d13863e7e076c20 Mon Sep 17 00:00:00 2001 From: Wes Medford Date: Fri, 20 Dec 2024 20:56:15 -0700 Subject: [PATCH 4/4] (fix) remove default implementation and fix previous issue --- src/config.rs | 14 +------------- src/query_router.rs | 1 + 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/config.rs b/src/config.rs index c20ed23b..9c1c571c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -878,7 +878,7 @@ impl Default for Shard { } } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Hash, Eq)] pub struct Plugins { pub intercept: Option, pub table_access: Option, @@ -887,18 +887,6 @@ pub struct Plugins { pub prewarmer: Option, } -impl Default for Plugins { - fn default() -> Self { - Self { - intercept: None, - table_access: None, - query_logger: None, - audit_logger: None, - prewarmer: None, - } - } -} - pub trait Plugin { fn is_enabled(&self) -> bool; } diff --git a/src/query_router.rs b/src/query_router.rs index 3e485a0d..9e627f7f 100644 --- a/src/query_router.rs +++ b/src/query_router.rs @@ -1916,6 +1916,7 @@ mod test { let plugins = Plugins { table_access: Some(table_access), intercept: None, + audit_logger: None, query_logger: None, prewarmer: None, };