diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd655c..b38bbdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,18 @@ * Add support for reporting peer client information +### aquatic_http + +#### Added + +* Reload TLS certificate (and key) on SIGUSR1 + ### aquatic_ws #### Added * Add support for reporting peer client information -* Reload TLS certificate and key on SIGUSR1 +* Reload TLS certificate (and key) on SIGUSR1 #### Changed diff --git a/Cargo.lock b/Cargo.lock index a85f803..7a09a85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,6 +118,7 @@ dependencies = [ "aquatic_common", "aquatic_http_protocol", "aquatic_toml_config", + "arc-swap", "cfg-if", "either", "futures", diff --git a/crates/http/Cargo.toml b/crates/http/Cargo.toml index 616f1e6..8f52edd 100644 --- a/crates/http/Cargo.toml +++ b/crates/http/Cargo.toml @@ -28,6 +28,7 @@ aquatic_http_protocol.workspace = true aquatic_toml_config.workspace = true anyhow = "1" +arc-swap = "1" cfg-if = "1" either = "1" futures = "0.3" diff --git a/crates/http/src/config.rs b/crates/http/src/config.rs index c3cbd32..7696bf0 100644 --- a/crates/http/src/config.rs +++ b/crates/http/src/config.rs @@ -77,6 +77,12 @@ pub struct NetworkConfig { /// Maximum number of pending TCP connections pub tcp_backlog: i32, /// Path to TLS certificate (DER-encoded X.509) + /// + /// The TLS files are read on start and when the program receives `SIGUSR1`. + /// If initial parsing fails, the program exits. Later failures result in + /// in emitting of an error-level log message, while successful updates + /// result in emitting of an info-level log message. Updates only affect + /// new connections. pub tls_certificate_path: PathBuf, /// Path to TLS private key (DER-encoded ASN.1 in PKCS#8 or PKCS#1 format) pub tls_private_key_path: PathBuf, diff --git a/crates/http/src/lib.rs b/crates/http/src/lib.rs index 7f9fc65..d4e1864 100644 --- a/crates/http/src/lib.rs +++ b/crates/http/src/lib.rs @@ -9,6 +9,7 @@ use aquatic_common::{ rustls_config::create_rustls_config, PanicSentinelWatcher, ServerStartInstant, }; +use arc_swap::ArcSwap; use common::State; use glommio::{channels::channel_mesh::MeshBuilder, prelude::*}; use signal_hook::{ @@ -57,10 +58,10 @@ pub fn run(config: Config) -> ::anyhow::Result<()> { let (sentinel_watcher, sentinel) = PanicSentinelWatcher::create_with_sentinel(); let priv_dropper = PrivilegeDropper::new(config.privileges.clone(), config.socket_workers); - let tls_config = Arc::new(create_rustls_config( + let tls_config = Arc::new(ArcSwap::from_pointee(create_rustls_config( &config.network.tls_certificate_path, &config.network.tls_private_key_path, - )?); + )?)); let server_start_instant = ServerStartInstant::new(); @@ -144,6 +145,18 @@ pub fn run(config: Config) -> ::anyhow::Result<()> { match signal { SIGUSR1 => { let _ = update_access_list(&config.access_list, &state.access_list); + + match create_rustls_config( + &config.network.tls_certificate_path, + &config.network.tls_private_key_path, + ) { + Ok(config) => { + tls_config.store(Arc::new(config)); + + ::log::info!("successfully updated tls config"); + } + Err(err) => ::log::error!("could not update tls config: {:#}", err), + } } SIGTERM => { if sentinel_watcher.panic_was_triggered() { diff --git a/crates/http/src/workers/socket.rs b/crates/http/src/workers/socket.rs index 3c1ac49..a3751ec 100644 --- a/crates/http/src/workers/socket.rs +++ b/crates/http/src/workers/socket.rs @@ -15,6 +15,7 @@ use aquatic_http_protocol::request::{Request, RequestParseError, ScrapeRequest}; use aquatic_http_protocol::response::{ FailureResponse, Response, ScrapeResponse, ScrapeStatistics, }; +use arc_swap::ArcSwap; use either::Either; use futures::stream::FuturesUnordered; use futures_lite::{AsyncReadExt, AsyncWriteExt, StreamExt}; @@ -59,7 +60,7 @@ pub async fn run_socket_worker( _sentinel: PanicSentinel, config: Config, state: State, - tls_config: Arc, + tls_config: Arc>, request_mesh_builder: MeshBuilder, priv_dropper: PrivilegeDropper, server_start_instant: ServerStartInstant, @@ -208,12 +209,12 @@ impl Connection { request_senders: Rc>, server_start_instant: ServerStartInstant, connection_id: ConnectionId, - tls_config: Arc, + tls_config: Arc>, connection_slab: Rc>>, stream: TcpStream, peer_addr: CanonicalSocketAddr, ) -> anyhow::Result<()> { - let tls_acceptor: TlsAcceptor = tls_config.into(); + let tls_acceptor: TlsAcceptor = tls_config.load_full().into(); let stream = tls_acceptor.accept(stream).await?; let mut response_buffer = [0; RESPONSE_BUFFER_SIZE]; diff --git a/crates/ws/src/config.rs b/crates/ws/src/config.rs index 8e935ee..2ad37bc 100644 --- a/crates/ws/src/config.rs +++ b/crates/ws/src/config.rs @@ -88,8 +88,9 @@ pub struct NetworkConfig { /// /// The TLS files are read on start and when the program receives `SIGUSR1`. /// If initial parsing fails, the program exits. Later failures result in - /// in emitting of an error-level log message, while a successful update - /// results in emitting of an info-level log message. + /// in emitting of an error-level log message, while successful updates + /// result in emitting of an info-level log message. Updates only affect + /// new connections. pub enable_tls: bool, /// Path to TLS certificate (DER-encoded X.509) pub tls_certificate_path: PathBuf,