From c95cb4046c0522c14edd1a56860d3ee9f8762058 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Tue, 18 Apr 2023 09:43:47 -0700 Subject: [PATCH 1/2] Separate server and user passwords --- pgcat.toml | 16 ++++++++++++++-- src/auth_passthrough.rs | 2 ++ src/client.rs | 5 +++++ src/config.rs | 4 ++++ src/server.rs | 30 +++++++++++++++++++++--------- 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/pgcat.toml b/pgcat.toml index 7db6abe3..c9faef8f 100644 --- a/pgcat.toml +++ b/pgcat.toml @@ -125,10 +125,22 @@ connect_timeout = 3000 # User configs are structured as pool..users. # This section holds the credentials for users that may connect to this cluster [pools.sharded_db.users.0] -# Postgresql username +# PostgreSQL username used to authenticate the user and connect to the server +# if `server_username` is not set. username = "sharding_user" -# Postgresql password + +# PostgreSQL password used to authenticate the user and connect to the server +# if `server_password` is not set. password = "sharding_user" + +pool_mode = "session" + +# PostgreSQL username used to connect to the server. +# server_username = "another_user" + +# PostgreSQL password used to connect to the server. +# server_password = "another_password" + # Maximum number of server connections that can be established for this user # The maximum number of connection from a single Pgcat process to any database in the cluster # is the sum of pool_size across all users. diff --git a/src/auth_passthrough.rs b/src/auth_passthrough.rs index f313dead..4e936262 100644 --- a/src/auth_passthrough.rs +++ b/src/auth_passthrough.rs @@ -72,6 +72,8 @@ impl AuthPassthrough { let auth_user = crate::config::User { username: self.user.clone(), password: Some(self.password.clone()), + server_username: None, + server_password: None, pool_size: 1, statement_timeout: 0, pool_mode: None, diff --git a/src/client.rs b/src/client.rs index 4114e4bb..5098ec6f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1128,6 +1128,11 @@ where self.buffer.put(&message[..]); } + // Close the prepared statement. + 'C' => { + self.buffer.put(&message[..]); + } + // Execute // Execute a prepared statement prepared in `P` and bound in `B`. 'E' => { diff --git a/src/config.rs b/src/config.rs index 4e0ff8ae..00c0f068 100644 --- a/src/config.rs +++ b/src/config.rs @@ -178,6 +178,8 @@ impl Address { pub struct User { pub username: String, pub password: Option, + pub server_username: Option, + pub server_password: Option, pub pool_size: u32, pub pool_mode: Option, #[serde(default)] // 0 @@ -189,6 +191,8 @@ impl Default for User { User { username: String::from("postgres"), password: None, + server_username: None, + server_password: None, pool_size: 15, statement_timeout: 0, pool_mode: None, diff --git a/src/server.rs b/src/server.rs index 14862bd0..84bed6cc 100644 --- a/src/server.rs +++ b/src/server.rs @@ -103,19 +103,32 @@ impl Server { trace!("Sending StartupMessage"); // StartupMessage - startup(&mut stream, &user.username, database).await?; + let username = match user.server_username { + Some(ref server_username) => server_username, + None => &user.username, + }; + + let password = match user.server_password { + Some(ref server_password) => Some(server_password), + None => match user.password { + Some(ref password) => Some(password), + None => None, + }, + }; + + startup(&mut stream, username, database).await?; let mut server_info = BytesMut::new(); let mut process_id: i32 = 0; let mut secret_key: i32 = 0; - let server_identifier = ServerIdentifier::new(&user.username, &database); + let server_identifier = ServerIdentifier::new(username, &database); // We'll be handling multiple packets, but they will all be structured the same. // We'll loop here until this exchange is complete. - let mut scram: Option = None; - if let Some(password) = &user.password.clone() { - scram = Some(ScramSha256::new(password)); - } + let mut scram: Option = match password { + Some(password) => Some(ScramSha256::new(password)), + None => None, + }; loop { let code = match stream.read_u8().await { @@ -172,11 +185,10 @@ impl Server { } }; - match &user.password { + match password { // Using plaintext password Some(password) => { - md5_password(&mut stream, &user.username, password, &salt[..]) - .await? + md5_password(&mut stream, username, password, &salt[..]).await? } // Using auth passthrough, in this case we should already have a From 10f8d5a5ef2a71e3ea4bdba0d3ee69a6930d0462 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Tue, 18 Apr 2023 09:45:32 -0700 Subject: [PATCH 2/2] config --- CONFIG.md | 92 ++++++++++++-------------------------- utilities/requirements.txt | 1 + 2 files changed, 30 insertions(+), 63 deletions(-) create mode 100644 utilities/requirements.txt diff --git a/CONFIG.md b/CONFIG.md index 613da752..fbee178f 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -1,4 +1,4 @@ -# PgCat Configurations +# PgCat Configurations ## `general` Section ### host @@ -108,7 +108,7 @@ If we should log client disconnections ### autoreload ``` path: general.autoreload -default: false +default: 15000 ``` When set to true, PgCat reloads configs if it detects a change in the config file. @@ -127,7 +127,7 @@ path: general.tcp_keepalives_idle default: 5 ``` -Number of seconds of connection idleness to wait before sending a keepalive packet to the server and client. +Number of seconds of connection idleness to wait before sending a keepalive packet to the server. ### tcp_keepalives_count ``` @@ -175,41 +175,11 @@ Connecting to that database allows running commands like `SHOW POOLS`, `SHOW DAT ### admin_password ``` path: general.admin_password -default: +default: "admin_pass" ``` Password to access the virtual administrative database -### auth_query (experimental) -``` -path: general.auth_query -default: -``` - -Query to be sent to servers to obtain the hash used for md5 authentication. The connection will be -established using the database configured in the pool. This parameter is inherited by every pool -and can be redefined in pool configuration. - -### auth_query_user (experimental) -``` -path: general.auth_query_user -default: -``` - -User to be used for connecting to servers to obtain the hash used for md5 authentication by sending the query -specified in `auth_query_user`. The connection will be established using the database configured in the pool. -This parameter is inherited by every pool and can be redefined in pool configuration. - -### auth_query_password (experimental) -``` -path: general.auth_query_password -default: -``` - -Password to be used for connecting to servers to obtain the hash used for md5 authentication by sending the query -specified in `auth_query_user`. The connection will be established using the database configured in the pool. -This parameter is inherited by every pool and can be redefined in pool configuration. - ## `pools.` Section ### pool_mode @@ -243,7 +213,7 @@ If the client doesn't specify, PgCat routes traffic to this role by default. `replica` round-robin between replicas only without touching the primary, `primary` all queries go to the primary unless otherwise specified. -### query_parser_enabled (experimental) +### query_parser_enabled ``` path: pools..query_parser_enabled default: true @@ -264,7 +234,7 @@ If the query parser is enabled and this setting is enabled, the primary will be load balancing of read queries. Otherwise, the primary will only be used for write queries. The primary can always be explicitly selected with our custom protocol. -### sharding_key_regex (experimental) +### sharding_key_regex ``` path: pools..sharding_key_regex default: @@ -286,7 +256,7 @@ Current options: `pg_bigint_hash`: PARTITION BY HASH (Postgres hashing function) `sha1`: A hashing function based on SHA1 -### automatic_sharding_key (experimental) +### automatic_sharding_key ``` path: pools..automatic_sharding_key default: @@ -311,47 +281,43 @@ default: 3000 Connect timeout can be overwritten in the pool -### auth_query (experimental) -``` -path: general.auth_query -default: -``` - -Auth query can be overwritten in the pool +## `pools..users.` Section -### auth_query_user (experimental) +### username ``` -path: general.auth_query_user -default: +path: pools..users..username +default: "sharding_user" ``` -Auth query user can be overwritten in the pool +PostgreSQL username used to authenticate the user and connect to the server +if `server_username` is not set. -### auth_query_password (experimental) +### password ``` -path: general.auth_query_password -default: +path: pools..users..password +default: "sharding_user" ``` -Auth query password can be overwritten in the pool +PostgreSQL password used to authenticate the user and connect to the server +if `server_password` is not set. -## `pools..users.` Section - -### username +### server_username ``` -path: pools..users..username -default: "sharding_user" +path: pools..users..server_username +default: +example: "another_user" ``` -Postgresql username +PostgreSQL username used to connect to the server. -### password +### server_password ``` -path: pools..users..password -default: "sharding_user" +path: pools..users..server_password +default: +example: "another_password" ``` -Postgresql password +PostgreSQL password used to connect to the server. ### pool_size ``` @@ -382,7 +348,7 @@ default: [["127.0.0.1", 5432, "primary"], ["localhost", 5432, "replica"]] Array of servers in the shard, each server entry is an array of `[host, port, role]` -### mirrors (experimental) +### mirrors ``` path: pools..shards..mirrors default: diff --git a/utilities/requirements.txt b/utilities/requirements.txt new file mode 100644 index 00000000..aab392a3 --- /dev/null +++ b/utilities/requirements.txt @@ -0,0 +1 @@ +tomli