Skip to content

Separate server and client passwords optionally #407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 29 additions & 63 deletions CONFIG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PgCat Configurations
# PgCat Configurations
## `general` Section

### host
Expand Down Expand Up @@ -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.
Expand All @@ -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
```
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -311,47 +281,43 @@ 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
## `pools.<pool_name>.users.<user_index>` Section

### auth_query_user (experimental)
### username
```
path: general.auth_query_user
default: <UNSET>
path: pools.<pool_name>.users.<user_index>.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: <UNSET>
path: pools.<pool_name>.users.<user_index>.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.<pool_name>.users.<user_index>` Section

### username
### server_username
```
path: pools.<pool_name>.users.<user_index>.username
default: "sharding_user"
path: pools.<pool_name>.users.<user_index>.server_username
default: <UNSET>
example: "another_user"
```

Postgresql username
PostgreSQL username used to connect to the server.

### password
### server_password
```
path: pools.<pool_name>.users.<user_index>.password
default: "sharding_user"
path: pools.<pool_name>.users.<user_index>.server_password
default: <UNSET>
example: "another_password"
```

Postgresql password
PostgreSQL password used to connect to the server.

### pool_size
```
Expand Down Expand Up @@ -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>
Expand Down
16 changes: 14 additions & 2 deletions pgcat.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions src/auth_passthrough.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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' => {
Expand Down
4 changes: 4 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
30 changes: 21 additions & 9 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions utilities/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tomli