diff --git a/libs/pageserver_api/src/config.rs b/libs/pageserver_api/src/config.rs index 8f56d60a4a..bd9f7efb7f 100644 --- a/libs/pageserver_api/src/config.rs +++ b/libs/pageserver_api/src/config.rs @@ -180,6 +180,7 @@ pub struct ConfigToml { #[serde(skip_serializing_if = "Option::is_none")] pub generate_unarchival_heatmap: Option, pub tracing: Option, + pub enable_tls_page_service_api: bool, } #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] @@ -631,6 +632,7 @@ impl Default for ConfigToml { load_previous_heatmap: None, generate_unarchival_heatmap: None, tracing: None, + enable_tls_page_service_api: false, } } } diff --git a/pageserver/src/bin/pageserver.rs b/pageserver/src/bin/pageserver.rs index 54fecee588..2740f81758 100644 --- a/pageserver/src/bin/pageserver.rs +++ b/pageserver/src/bin/pageserver.rs @@ -452,6 +452,23 @@ fn start_pageserver( info!("Using auth for http API: {:#?}", conf.http_auth_type); info!("Using auth for pg connections: {:#?}", conf.pg_auth_type); + let tls_server_config = if conf.listen_https_addr.is_some() || conf.enable_tls_page_service_api + { + let resolver = BACKGROUND_RUNTIME.block_on(ReloadingCertificateResolver::new( + &conf.ssl_key_file, + &conf.ssl_cert_file, + conf.ssl_cert_reload_period, + ))?; + + let server_config = rustls::ServerConfig::builder() + .with_no_client_auth() + .with_cert_resolver(resolver); + + Some(Arc::new(server_config)) + } else { + None + }; + match var("NEON_AUTH_TOKEN") { Ok(v) => { info!("Loaded JWT token for authentication with Safekeeper"); @@ -670,17 +687,11 @@ fn start_pageserver( let https_task = match https_listener { Some(https_listener) => { - let resolver = MGMT_REQUEST_RUNTIME.block_on(ReloadingCertificateResolver::new( - &conf.ssl_key_file, - &conf.ssl_cert_file, - conf.ssl_cert_reload_period, - ))?; + let tls_server_config = tls_server_config + .clone() + .expect("tls_server_config is set earlier if https is enabled"); - let server_config = rustls::ServerConfig::builder() - .with_no_client_auth() - .with_cert_resolver(resolver); - - let tls_acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config)); + let tls_acceptor = tokio_rustls::TlsAcceptor::from(tls_server_config); let server = http_utils::server::Server::new(service, https_listener, Some(tls_acceptor))?; @@ -736,6 +747,11 @@ fn start_pageserver( tokio::net::TcpListener::from_std(pageserver_listener) .context("create tokio listener")? }, + if conf.enable_tls_page_service_api { + tls_server_config + } else { + None + }, ); // All started up! Now just sit and wait for shutdown signal. diff --git a/pageserver/src/config.rs b/pageserver/src/config.rs index ccc29e59d4..26ae6af70e 100644 --- a/pageserver/src/config.rs +++ b/pageserver/src/config.rs @@ -219,6 +219,11 @@ pub struct PageServerConf { pub generate_unarchival_heatmap: bool, pub tracing: Option, + + /// Enable TLS in page service API. + /// Does not force TLS: the client negotiates TLS usage during the handshake. + /// Uses key and certificate from ssl_key_file/ssl_cert_file. + pub enable_tls_page_service_api: bool, } /// Token for authentication to safekeepers @@ -391,6 +396,7 @@ impl PageServerConf { load_previous_heatmap, generate_unarchival_heatmap, tracing, + enable_tls_page_service_api, } = config_toml; let mut conf = PageServerConf { @@ -441,6 +447,7 @@ impl PageServerConf { page_service_pipelining, get_vectored_concurrent_io, tracing, + enable_tls_page_service_api, // ------------------------------------------------------------ // fields that require additional validation or custom handling diff --git a/pageserver/src/page_service.rs b/pageserver/src/page_service.rs index 7e3991dbdc..61f524fc29 100644 --- a/pageserver/src/page_service.rs +++ b/pageserver/src/page_service.rs @@ -105,6 +105,7 @@ pub fn spawn( pg_auth: Option>, perf_trace_dispatch: Option, tcp_listener: tokio::net::TcpListener, + tls_config: Option>, ) -> Listener { let cancel = CancellationToken::new(); let libpq_ctx = RequestContext::todo_child( @@ -124,6 +125,7 @@ pub fn spawn( perf_trace_dispatch, tcp_listener, conf.pg_auth_type, + tls_config, conf.page_service_pipelining.clone(), libpq_ctx, cancel.clone(), @@ -181,6 +183,7 @@ pub async fn libpq_listener_main( perf_trace_dispatch: Option, listener: tokio::net::TcpListener, auth_type: AuthType, + tls_config: Option>, pipelining_config: PageServicePipeliningConfig, listener_ctx: RequestContext, listener_cancel: CancellationToken, @@ -223,6 +226,7 @@ pub async fn libpq_listener_main( local_auth, socket, auth_type, + tls_config.clone(), pipelining_config.clone(), connection_ctx, connections_cancel.child_token(), @@ -264,6 +268,7 @@ async fn page_service_conn_main( auth: Option>, socket: tokio::net::TcpStream, auth_type: AuthType, + tls_config: Option>, pipelining_config: PageServicePipeliningConfig, connection_ctx: RequestContext, cancel: CancellationToken, @@ -334,7 +339,8 @@ async fn page_service_conn_main( cancel.clone(), gate_guard, ); - let pgbackend = PostgresBackend::new_from_io(socket_fd, socket, peer_addr, auth_type, None)?; + let pgbackend = + PostgresBackend::new_from_io(socket_fd, socket, peer_addr, auth_type, tls_config)?; match pgbackend.run(&mut conn_handler, &cancel).await { Ok(()) => {