From 17eff5a97b2d1b1aeeb0272a38c9205fde5b1983 Mon Sep 17 00:00:00 2001 From: Henry Guo Date: Wed, 13 May 2026 11:45:42 +0800 Subject: [PATCH] fix(tls): ignore Kubernetes secret projection dirs (#2938) --- Cargo.lock | 1 + crates/utils/Cargo.toml | 1 + crates/utils/src/certs.rs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 31f383e7e..9dd068f03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10244,6 +10244,7 @@ dependencies = [ "lz4", "md-5 0.11.0", "netif", + "rcgen", "regex", "rustix 1.1.4", "rustls", diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index b3eec08f4..60f2cea83 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -63,6 +63,7 @@ url = { workspace = true, optional = true } zstd = { workspace = true, optional = true } [dev-dependencies] +rcgen = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } temp-env = { workspace = true } diff --git a/crates/utils/src/certs.rs b/crates/utils/src/certs.rs index 1366064ee..50e4d2a52 100644 --- a/crates/utils/src/certs.rs +++ b/crates/utils/src/certs.rs @@ -288,6 +288,10 @@ pub fn certs_error(err: String) -> Error { Error::other(err) } +fn is_discoverable_cert_domain_dir(domain_name: &str) -> bool { + !domain_name.starts_with('.') +} + /// Load all certificates and private keys in the directory /// This function loads all certificate and private key pairs from the specified directory. /// It looks for files named `options.cert_filename` and `options.key_filename` in each subdirectory. @@ -347,6 +351,10 @@ pub fn load_all_certs_from_directory( .file_name() .and_then(|name| name.to_str()) .ok_or_else(|| certs_error(format!("invalid domain name directory:{path:?}")))?; + if !is_discoverable_cert_domain_dir(domain_name) { + debug!("skip internal certificate directory: {:?}", path); + continue; + } // find certificate and private key files let cert_path = path.join(&options.cert_filename); // e.g., rustfs_cert.pem @@ -477,6 +485,13 @@ mod tests { CertDirectoryLoadOptions::builder(path, "rustfs_cert.pem", "rustfs_key.pem").build() } + fn write_test_cert_pair(dir: &std::path::Path) { + let rcgen::CertifiedKey { cert, signing_key } = + rcgen::generate_simple_self_signed(vec!["example.com".to_string()]).unwrap(); + fs::write(dir.join("rustfs_cert.pem"), cert.pem()).unwrap(); + fs::write(dir.join("rustfs_key.pem"), signing_key.serialize_pem()).unwrap(); + } + #[test] fn test_certs_error_function() { let error_msg = "Test error message"; @@ -675,6 +690,30 @@ mod tests { ); } + #[test] + fn test_load_all_certs_skips_kubernetes_secret_projection_dirs() { + let temp_dir = TempDir::new().unwrap(); + write_test_cert_pair(temp_dir.path()); + + let domain_dir = temp_dir.path().join("example.com"); + fs::create_dir(&domain_dir).unwrap(); + write_test_cert_pair(&domain_dir); + + for internal_dir_name in ["..data", "..2026_04_28_18_33_53.4209048473"] { + let internal_dir = temp_dir.path().join(internal_dir_name); + fs::create_dir(&internal_dir).unwrap(); + write_test_cert_pair(&internal_dir); + } + + let certs = load_all_certs_from_directory(default_load_options(temp_dir.path())).unwrap(); + + assert!(certs.contains_key("default")); + assert!(certs.contains_key("example.com")); + assert!(!certs.contains_key("..data")); + assert!(!certs.contains_key("..2026_04_28_18_33_53.4209048473")); + assert_eq!(certs.len(), 2); + } + #[test] fn test_unicode_path_handling() { let temp_dir = TempDir::new().unwrap();