mirror of
https://github.com/postgresml/pgcat.git
synced 2026-03-23 01:16:30 +00:00
Separate server and client passwords optionally (#407)
* Separate server and user passwords * config
This commit is contained in:
92
CONFIG.md
92
CONFIG.md
@@ -108,7 +108,7 @@ If we should log client disconnections
|
|||||||
### autoreload
|
### autoreload
|
||||||
```
|
```
|
||||||
path: general.autoreload
|
path: general.autoreload
|
||||||
default: false
|
default: 15000
|
||||||
```
|
```
|
||||||
|
|
||||||
When set to true, PgCat reloads configs if it detects a change in the config file.
|
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
|
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
|
### tcp_keepalives_count
|
||||||
```
|
```
|
||||||
@@ -175,41 +175,11 @@ Connecting to that database allows running commands like `SHOW POOLS`, `SHOW DAT
|
|||||||
### admin_password
|
### admin_password
|
||||||
```
|
```
|
||||||
path: general.admin_password
|
path: general.admin_password
|
||||||
default: <UNSET>
|
default: "admin_pass"
|
||||||
```
|
```
|
||||||
|
|
||||||
Password to access the virtual administrative database
|
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
|
## `pools.<pool_name>` Section
|
||||||
|
|
||||||
### pool_mode
|
### 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,
|
`replica` round-robin between replicas only without touching the primary,
|
||||||
`primary` all queries go to the primary unless otherwise specified.
|
`primary` all queries go to the primary unless otherwise specified.
|
||||||
|
|
||||||
### query_parser_enabled (experimental)
|
### query_parser_enabled
|
||||||
```
|
```
|
||||||
path: pools.<pool_name>.query_parser_enabled
|
path: pools.<pool_name>.query_parser_enabled
|
||||||
default: true
|
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
|
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.
|
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
|
path: pools.<pool_name>.sharding_key_regex
|
||||||
default: <UNSET>
|
default: <UNSET>
|
||||||
@@ -286,7 +256,7 @@ Current options:
|
|||||||
`pg_bigint_hash`: PARTITION BY HASH (Postgres hashing function)
|
`pg_bigint_hash`: PARTITION BY HASH (Postgres hashing function)
|
||||||
`sha1`: A hashing function based on SHA1
|
`sha1`: A hashing function based on SHA1
|
||||||
|
|
||||||
### automatic_sharding_key (experimental)
|
### automatic_sharding_key
|
||||||
```
|
```
|
||||||
path: pools.<pool_name>.automatic_sharding_key
|
path: pools.<pool_name>.automatic_sharding_key
|
||||||
default: <UNSET>
|
default: <UNSET>
|
||||||
@@ -311,30 +281,6 @@ default: 3000
|
|||||||
|
|
||||||
Connect timeout can be overwritten in the pool
|
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
|
## `pools.<pool_name>.users.<user_index>` Section
|
||||||
|
|
||||||
### username
|
### username
|
||||||
@@ -343,7 +289,8 @@ path: pools.<pool_name>.users.<user_index>.username
|
|||||||
default: "sharding_user"
|
default: "sharding_user"
|
||||||
```
|
```
|
||||||
|
|
||||||
Postgresql username
|
PostgreSQL username used to authenticate the user and connect to the server
|
||||||
|
if `server_username` is not set.
|
||||||
|
|
||||||
### password
|
### password
|
||||||
```
|
```
|
||||||
@@ -351,7 +298,26 @@ path: pools.<pool_name>.users.<user_index>.password
|
|||||||
default: "sharding_user"
|
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
|
### 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]`
|
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
|
path: pools.<pool_name>.shards.<shard_index>.mirrors
|
||||||
default: <UNSET>
|
default: <UNSET>
|
||||||
|
|||||||
16
pgcat.toml
16
pgcat.toml
@@ -125,10 +125,22 @@ connect_timeout = 3000
|
|||||||
# User configs are structured as pool.<pool_name>.users.<user_index>
|
# User configs are structured as pool.<pool_name>.users.<user_index>
|
||||||
# This section holds the credentials for users that may connect to this cluster
|
# This section holds the credentials for users that may connect to this cluster
|
||||||
[pools.sharded_db.users.0]
|
[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"
|
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"
|
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
|
# 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
|
# 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.
|
# is the sum of pool_size across all users.
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ impl AuthPassthrough {
|
|||||||
let auth_user = crate::config::User {
|
let auth_user = crate::config::User {
|
||||||
username: self.user.clone(),
|
username: self.user.clone(),
|
||||||
password: Some(self.password.clone()),
|
password: Some(self.password.clone()),
|
||||||
|
server_username: None,
|
||||||
|
server_password: None,
|
||||||
pool_size: 1,
|
pool_size: 1,
|
||||||
statement_timeout: 0,
|
statement_timeout: 0,
|
||||||
pool_mode: None,
|
pool_mode: None,
|
||||||
|
|||||||
@@ -1128,6 +1128,11 @@ where
|
|||||||
self.buffer.put(&message[..]);
|
self.buffer.put(&message[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close the prepared statement.
|
||||||
|
'C' => {
|
||||||
|
self.buffer.put(&message[..]);
|
||||||
|
}
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
// Execute a prepared statement prepared in `P` and bound in `B`.
|
// Execute a prepared statement prepared in `P` and bound in `B`.
|
||||||
'E' => {
|
'E' => {
|
||||||
|
|||||||
@@ -178,6 +178,8 @@ impl Address {
|
|||||||
pub struct User {
|
pub struct User {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
|
pub server_username: Option<String>,
|
||||||
|
pub server_password: Option<String>,
|
||||||
pub pool_size: u32,
|
pub pool_size: u32,
|
||||||
pub pool_mode: Option<PoolMode>,
|
pub pool_mode: Option<PoolMode>,
|
||||||
#[serde(default)] // 0
|
#[serde(default)] // 0
|
||||||
@@ -189,6 +191,8 @@ impl Default for User {
|
|||||||
User {
|
User {
|
||||||
username: String::from("postgres"),
|
username: String::from("postgres"),
|
||||||
password: None,
|
password: None,
|
||||||
|
server_username: None,
|
||||||
|
server_password: None,
|
||||||
pool_size: 15,
|
pool_size: 15,
|
||||||
statement_timeout: 0,
|
statement_timeout: 0,
|
||||||
pool_mode: None,
|
pool_mode: None,
|
||||||
|
|||||||
@@ -103,19 +103,32 @@ impl Server {
|
|||||||
trace!("Sending StartupMessage");
|
trace!("Sending StartupMessage");
|
||||||
|
|
||||||
// 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 server_info = BytesMut::new();
|
||||||
let mut process_id: i32 = 0;
|
let mut process_id: i32 = 0;
|
||||||
let mut secret_key: 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 be handling multiple packets, but they will all be structured the same.
|
||||||
// We'll loop here until this exchange is complete.
|
// We'll loop here until this exchange is complete.
|
||||||
let mut scram: Option<ScramSha256> = None;
|
let mut scram: Option<ScramSha256> = match password {
|
||||||
if let Some(password) = &user.password.clone() {
|
Some(password) => Some(ScramSha256::new(password)),
|
||||||
scram = Some(ScramSha256::new(password));
|
None => None,
|
||||||
}
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let code = match stream.read_u8().await {
|
let code = match stream.read_u8().await {
|
||||||
@@ -172,11 +185,10 @@ impl Server {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match &user.password {
|
match password {
|
||||||
// Using plaintext password
|
// Using plaintext password
|
||||||
Some(password) => {
|
Some(password) => {
|
||||||
md5_password(&mut stream, &user.username, password, &salt[..])
|
md5_password(&mut stream, username, password, &salt[..]).await?
|
||||||
.await?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using auth passthrough, in this case we should already have a
|
// Using auth passthrough, in this case we should already have a
|
||||||
|
|||||||
1
utilities/requirements.txt
Normal file
1
utilities/requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
tomli
|
||||||
Reference in New Issue
Block a user