Separate server and client passwords optionally (#407)

* Separate server and user passwords

* config
This commit is contained in:
Lev Kokotov
2023-04-18 09:57:17 -07:00
committed by GitHub
parent a18eb42df5
commit 3dae3d0777
7 changed files with 77 additions and 75 deletions

View File

@@ -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: <UNSET>
default: "admin_pass"
```
Password to access the virtual administrative database
### auth_query (experimental)
```
path: general.auth_query
default: <UNSET>
```
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: <UNSET>
```
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: <UNSET>
```
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.<pool_name>` 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.<pool_name>.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.<pool_name>.sharding_key_regex
default: <UNSET>
@@ -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.<pool_name>.automatic_sharding_key
default: <UNSET>
@@ -311,30 +281,6 @@ default: 3000
Connect timeout can be overwritten in the pool
### auth_query (experimental)
```
path: general.auth_query
default: <UNSET>
```
Auth query can be overwritten in the pool
### auth_query_user (experimental)
```
path: general.auth_query_user
default: <UNSET>
```
Auth query user can be overwritten in the pool
### auth_query_password (experimental)
```
path: general.auth_query_password
default: <UNSET>
```
Auth query password can be overwritten in the pool
## `pools.<pool_name>.users.<user_index>` Section
### username
@@ -343,7 +289,8 @@ path: pools.<pool_name>.users.<user_index>.username
default: "sharding_user"
```
Postgresql username
PostgreSQL username used to authenticate the user and connect to the server
if `server_username` is not set.
### password
```
@@ -351,7 +298,26 @@ path: pools.<pool_name>.users.<user_index>.password
default: "sharding_user"
```
Postgresql password
PostgreSQL password used to authenticate the user and connect to the server
if `server_password` is not set.
### server_username
```
path: pools.<pool_name>.users.<user_index>.server_username
default: <UNSET>
example: "another_user"
```
PostgreSQL username used to connect to the server.
### server_password
```
path: pools.<pool_name>.users.<user_index>.server_password
default: <UNSET>
example: "another_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.<pool_name>.shards.<shard_index>.mirrors
default: <UNSET>

View File

@@ -125,10 +125,22 @@ connect_timeout = 3000
# User configs are structured as pool.<pool_name>.users.<user_index>
# 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.

View File

@@ -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,

View File

@@ -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' => {

View File

@@ -178,6 +178,8 @@ impl Address {
pub struct User {
pub username: String,
pub password: Option<String>,
pub server_username: Option<String>,
pub server_password: Option<String>,
pub pool_size: u32,
pub pool_mode: Option<PoolMode>,
#[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,

View File

@@ -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<ScramSha256> = None;
if let Some(password) = &user.password.clone() {
scram = Some(ScramSha256::new(password));
}
let mut scram: Option<ScramSha256> = 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

View File

@@ -0,0 +1 @@
tomli