Skip to content

Commit 83fe635

Browse files
authored
Merge pull request #327 from cipherstash/refactor-frontend-context
Refactor frontend context
2 parents 5279c1b + 9c05593 commit 83fe635

File tree

30 files changed

+877
-552
lines changed

30 files changed

+877
-552
lines changed

.tool-versions

Lines changed: 0 additions & 1 deletion
This file was deleted.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/errors.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
- Configuration errors:
3434
- [Missing or invalid TLS configuration](#config-missing-or-invalid-tls)
35+
- [Network configuration change requires restart](#config-network-change-requires-restart)
36+
3537
<!-- ---------------------------------------------------------------------------------------------------- -->
3638

3739
<!-- ---------------------------------------------------------------------------------------------------- -->
@@ -651,3 +653,35 @@ Check that the certificate and private key are valid.
651653

652654

653655
<!-- ---------------------------------------------------------------------------------------------------- -->
656+
657+
658+
## Network configuration change requires restart <a id='config-network-change-requires-restart'></a>
659+
660+
A configuration reload was attempted with network-level changes that require a full restart.
661+
662+
### Error message
663+
664+
```
665+
Network configuration change requires restart
666+
```
667+
668+
### Notes
669+
670+
When receiving a SIGHUP signal, CipherStash Proxy attempts to reload application-level configuration without disrupting active connections. However, certain network-related configuration changes require stopping and restarting the proxy service to take effect.
671+
672+
The following settings require a restart when changed:
673+
- `server.host` - The host address the proxy listens on
674+
- `server.port` - The port the proxy listens on
675+
- `server.require_tls` - TLS requirement setting
676+
- `server.worker_threads` - Number of worker threads
677+
- `tls` - Any TLS certificate or key configuration
678+
679+
### How to fix
680+
681+
1. Stop the CipherStash Proxy service
682+
2. Update the configuration as needed
683+
3. Restart the CipherStash Proxy service
684+
685+
Application-level configuration changes (database, auth, encrypt, log, prometheus, development) can be reloaded without restart using SIGHUP.
686+
687+
<!-- ---------------------------------------------------------------------------------------------------- -->

mise.toml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ echo
311311
mise --env tcp run postgres:setup
312312
mise --env tls run postgres:setup
313313
314+
mise run test:integration:showcase
315+
314316
echo
315317
echo '###############################################'
316318
echo '# Test: Prometheus'
@@ -379,10 +381,8 @@ echo '###############################################'
379381
echo '# Test: Showcase'
380382
echo '###############################################'
381383
echo
382-
mise --env tls run proxy:up proxy-tls --extra-args "--detach --wait"
383-
mise --env tls run test:wait_for_postgres_to_quack --port 6432 --max-retries 20 --tls
384-
RUST_BACKTRACE=full cargo run -p showcase
385-
mise --env tls run proxy:down
384+
385+
mise run test:integration:showcase
386386
387387
echo
388388
echo '###############################################'
@@ -646,6 +646,15 @@ else
646646
fi
647647
"""
648648

649+
[tasks."test:integration:showcase"]
650+
description = "Run Showcase integration test"
651+
run = """
652+
mise --env tls run proxy:up proxy-tls --extra-args "--detach --wait"
653+
mise --env tls run test:wait_for_postgres_to_quack --port 6432 --max-retries 20 --tls
654+
RUST_BACKTRACE=full cargo run -p showcase
655+
mise --env tls run proxy:down
656+
"""
657+
649658
[tasks.release]
650659
description = "Publish release artifacts"
651660
depends = ["release:docker"]

packages/cipherstash-proxy/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version = "2.0.0"
44
edition = "2021"
55

66
[dependencies]
7+
async-trait = "0.1"
78
aws-lc-rs = "1.13.3"
89
bigdecimal = { version = "0.4.6", features = ["serde-json"] }
910
arc-swap = "1.7.1"

packages/cipherstash-proxy/src/config/database.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ impl DatabaseConfig {
8787
})?;
8888
Ok(name)
8989
}
90+
91+
#[cfg(test)]
92+
pub fn for_testing() -> Self {
93+
Self {
94+
host: Self::default_host(),
95+
port: Self::default_port(),
96+
name: "test".to_string(),
97+
username: "test".to_string(),
98+
password: Protected::new("test".to_string()),
99+
connection_timeout: None,
100+
with_tls_verification: false,
101+
config_reload_interval: Self::default_config_reload_interval(),
102+
schema_reload_interval: Self::default_schema_reload_interval(),
103+
}
104+
}
90105
}
91106

92107
///

packages/cipherstash-proxy/src/config/tandem.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,29 @@ impl TandemConfig {
302302

303303
DEFAULT_THREAD_STACK_SIZE
304304
}
305+
306+
#[cfg(test)]
307+
pub fn for_testing() -> Self {
308+
Self {
309+
server: ServerConfig::default(),
310+
database: DatabaseConfig::for_testing(),
311+
auth: AuthConfig {
312+
workspace_crn: "crn:ap-southeast-2.aws:IJGECSCWKREECNBS".parse().unwrap(),
313+
client_access_key: "test".to_string(),
314+
},
315+
encrypt: EncryptConfig {
316+
client_id: "test".to_string(),
317+
client_key: "test".to_string(),
318+
default_keyset_id: Some(
319+
Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
320+
),
321+
},
322+
tls: None,
323+
log: LogConfig::default(),
324+
prometheus: PrometheusConfig::default(),
325+
development: None,
326+
}
327+
}
305328
}
306329

307330
impl PrometheusConfig {

packages/cipherstash-proxy/src/config/tls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{error::TlsConfigError, log::CONFIG};
1010
/// Server TLS Configuration
1111
/// This is listener/inbound connection config
1212
///
13-
#[derive(Clone, Debug, Deserialize)]
13+
#[derive(Clone, Debug, Deserialize, PartialEq)]
1414
#[serde(untagged)]
1515
pub enum TlsConfig {
1616
Pem {

packages/cipherstash-proxy/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ pub enum ConfigError {
176176
#[error("Expected an Encrypt configuration table")]
177177
MissingEncryptConfigTable,
178178

179+
#[error("Network configuration change requires restart For help visit {}#config-network-change-requires-restart", ERROR_DOC_BASE_URL)]
180+
NetworkConfigurationChangeRequiresRestart,
181+
179182
#[error(transparent)]
180183
Parse(#[from] serde_json::Error),
181184

packages/cipherstash-proxy/src/main.rs

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use cipherstash_proxy::config::TandemConfig;
22
use cipherstash_proxy::connect::{self, AsyncStream};
3-
use cipherstash_proxy::error::Error;
3+
use cipherstash_proxy::error::{ConfigError, Error};
44
use cipherstash_proxy::prometheus::CLIENTS_ACTIVE_CONNECTIONS;
55
use cipherstash_proxy::proxy::Proxy;
66
use cipherstash_proxy::{cli, log, postgresql as pg, prometheus, tls, Args};
77
use clap::Parser;
88
use metrics::gauge;
9-
use tokio::net::TcpListener;
109
use tokio::signal::unix::{signal, SignalKind};
1110
use tokio_util::task::TaskTracker;
1211
use tracing::{error, info, warn};
@@ -55,7 +54,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
5554

5655
let mut proxy = init(config).await;
5756

58-
let mut listener = connect::bind_with_retry(&proxy.config.server).await;
57+
let listener = connect::bind_with_retry(&proxy.config.server).await;
5958
let tracker = TaskTracker::new();
6059

6160
let mut client_id = 0;
@@ -81,26 +80,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
8180
break;
8281
},
8382
_ = sighup() => {
84-
info!(msg = "Received SIGHUP. Reloading configuration");
85-
(listener, proxy) = reload_config(listener, &args, proxy).await;
86-
info!(msg = "Reloaded configuration");
83+
info!(msg = "Received SIGHUP. Reloading application configuration");
84+
proxy = reload_application_config(&proxy.config, &args).await.unwrap_or(proxy);
8785
},
8886
_ = sigterm() => {
8987
info!(msg = "Received SIGTERM");
9088
break;
9189
},
9290
Ok(client_stream) = AsyncStream::accept(&listener) => {
9391

94-
let proxy = proxy.clone();
95-
9692
client_id += 1;
9793

94+
let context = proxy.context(client_id);
95+
9896
tracker.spawn(async move {
99-
let proxy = proxy.clone();
10097

10198
gauge!(CLIENTS_ACTIVE_CONNECTIONS).increment(1);
10299

103-
match pg::handler(client_stream, proxy, client_id).await {
100+
match pg::handler(client_stream,context).await {
104101
Ok(_) => (),
105102
Err(err) => {
106103

@@ -261,25 +258,35 @@ async fn sighup() -> std::io::Result<()> {
261258
Ok(())
262259
}
263260

264-
async fn reload_config(listener: TcpListener, args: &Args, proxy: Proxy) -> (TcpListener, Proxy) {
261+
fn has_network_config_changed(current: &TandemConfig, new: &TandemConfig) -> bool {
262+
current.server.host != new.server.host
263+
|| current.server.port != new.server.port
264+
|| current.server.require_tls != new.server.require_tls
265+
|| current.server.worker_threads != new.server.worker_threads
266+
|| current.tls != new.tls
267+
}
268+
269+
async fn reload_application_config(config: &TandemConfig, args: &Args) -> Result<Proxy, Error> {
265270
let new_config = match TandemConfig::load(args) {
266271
Ok(config) => config,
267272
Err(err) => {
268273
warn!(
269274
msg = "Configuration could not be reloaded: {}",
270275
error = err.to_string()
271276
);
272-
return (listener, proxy);
277+
return Err(err);
273278
}
274279
};
275280

276-
let new_proxy = init(new_config).await;
281+
// Check for network config changes that require restart
282+
if has_network_config_changed(config, &new_config) {
283+
let err = ConfigError::NetworkConfigurationChangeRequiresRestart;
284+
warn!(msg = err.to_string());
277285

278-
// Explicit drop needed here to free the network resources before binding if using the same address & port
279-
std::mem::drop(listener);
286+
return Err(err.into());
287+
}
280288

281-
(
282-
connect::bind_with_retry(&new_proxy.config.server).await,
283-
new_proxy,
284-
)
289+
info!(msg = "Configuration reloaded");
290+
let proxy = init(new_config).await;
291+
Ok(proxy)
285292
}

0 commit comments

Comments
 (0)