From 2a85f2ba6fae1a2a0229f9964e096f103581ac72 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 16 Mar 2026 12:32:16 -0700 Subject: [PATCH] Require grpc.ca for gRPC server TLS --- seaweed-volume/src/main.rs | 101 ++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/seaweed-volume/src/main.rs b/seaweed-volume/src/main.rs index 8d3240ed2..405f9872d 100644 --- a/seaweed-volume/src/main.rs +++ b/seaweed-volume/src/main.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, RwLock}; -use tracing::{error, info}; +use tracing::{error, info, warn}; use seaweed_volume::config::{self, VolumeServerConfig}; use seaweed_volume::metrics; @@ -164,6 +164,45 @@ fn build_outgoing_http_client( Ok((builder.build()?, scheme.to_string())) } +fn build_grpc_server_tls_config( + cert_path: &str, + key_path: &str, + ca_path: &str, +) -> Option { + if cert_path.is_empty() || key_path.is_empty() || ca_path.is_empty() { + return None; + } + + let cert = match std::fs::read_to_string(cert_path) { + Ok(cert) => cert, + Err(e) => { + warn!("Failed to read gRPC cert '{}': {}", cert_path, e); + return None; + } + }; + let key = match std::fs::read_to_string(key_path) { + Ok(key) => key, + Err(e) => { + warn!("Failed to read gRPC key '{}': {}", key_path, e); + return None; + } + }; + let ca_cert = match std::fs::read_to_string(ca_path) { + Ok(ca_cert) => ca_cert, + Err(e) => { + warn!("Failed to read gRPC CA cert '{}': {}", ca_path, e); + return None; + } + }; + + let identity = tonic::transport::Identity::from_pem(cert, key); + Some( + tonic::transport::ServerTlsConfig::new() + .identity(identity) + .client_ca_root(tonic::transport::Certificate::from_pem(ca_cert)), + ) +} + async fn run(config: VolumeServerConfig) -> Result<(), Box> { // Initialize the store let mut store = Store::new(config.index_type); @@ -446,28 +485,14 @@ async fn run(config: VolumeServerConfig) -> Result<(), Box( } } } + +#[cfg(test)] +mod tests { + use super::build_grpc_server_tls_config; + + fn write_pem(dir: &tempfile::TempDir, name: &str, body: &str) -> String { + let path = dir.path().join(name); + std::fs::write(&path, body).unwrap(); + path.to_string_lossy().into_owned() + } + + #[test] + fn test_grpc_server_tls_requires_ca() { + let dir = tempfile::tempdir().unwrap(); + let cert = write_pem( + &dir, + "server.crt", + "-----BEGIN CERTIFICATE-----\nZmFrZQ==\n-----END CERTIFICATE-----\n", + ); + let key = write_pem( + &dir, + "server.key", + "-----BEGIN PRIVATE KEY-----\nZmFrZQ==\n-----END PRIVATE KEY-----\n", + ); + + assert!(build_grpc_server_tls_config(&cert, &key, "").is_none()); + } + + #[test] + fn test_grpc_server_tls_returns_none_when_files_are_missing() { + assert!(build_grpc_server_tls_config( + "/missing/server.crt", + "/missing/server.key", + "/missing/ca.crt", + ) + .is_none()); + } +}