Refactor trusted-proxies: modernize utils, improve safety, and fix clippy lints (#1693)

Co-authored-by: majinghe <42570491+majinghe@users.noreply.github.com>
Co-authored-by: GatewayJ <835269233@qq.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>
Co-authored-by: heihutu <30542132+heihutu@users.noreply.github.com>
This commit is contained in:
houseme
2026-02-03 01:06:22 +08:00
committed by GitHub
parent d1a70176a2
commit cb468fb32f
55 changed files with 5145 additions and 93 deletions
+2 -2
View File
@@ -59,6 +59,7 @@ rustfs-rio.workspace = true
rustfs-s3select-api = { workspace = true }
rustfs-s3select-query = { workspace = true }
rustfs-targets = { workspace = true }
rustfs-trusted-proxies = { workspace = true }
rustfs-utils = { workspace = true, features = ["full"] }
rustfs-zip = { workspace = true }
rustfs-scanner = { workspace = true }
@@ -141,8 +142,7 @@ libsystemd.workspace = true
[target.'cfg(not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64")))'.dependencies]
mimalloc = { workspace = true }
# Note: If you want to *explicitly* exclude Windows from a target dependency set,
# you can use a cfg like the following instead:
# Only enable pprof-based profiling on non-Windows targets.
[target.'cfg(all(not(target_os = "windows"), not(all(target_os = "linux", target_env = "gnu", target_arch = "x86_64"))))'.dependencies]
starshard = { workspace = true }
backtrace = { workspace = true }
+3
View File
@@ -126,6 +126,9 @@ async fn async_main() -> Result<()> {
// Initialize performance profiling if enabled
profiling::init_from_env().await;
// Initialize trusted proxies system
rustfs_trusted_proxies::init();
// Initialize TLS if a certificate path is provided
if let Some(tls_path) = &opt.tls_path {
match init_cert(tls_path).await {
+27 -5
View File
@@ -37,6 +37,7 @@ use rustfs_common::GlobalReadiness;
use rustfs_config::{RUSTFS_TLS_CERT, RUSTFS_TLS_KEY};
use rustfs_ecstore::rpc::{TONIC_RPC_PREFIX, verify_rpc_signature};
use rustfs_protos::proto_gen::node_service::node_service_server::NodeServiceServer;
use rustfs_trusted_proxies::ClientInfo;
use rustfs_utils::net::parse_and_resolve_address;
use rustls::ServerConfig;
use s3s::{host::MultiDomain, service::S3Service, service::S3ServiceBuilder};
@@ -216,7 +217,7 @@ pub async fn start_http_server(
b.set_access(store.clone());
b.set_route(admin::make_admin_route(opt.console_enable)?);
// console server does not need to setup virtual-hosted-style requests
// Virtual-hosted-style requests are only set up for S3 API when server domains are configured and console is disabled
if !opt.server_domains.is_empty() && !opt.console_enable {
MultiDomain::new(&opt.server_domains).map_err(Error::other)?; // validate domains
@@ -525,7 +526,7 @@ struct ConnectionContext {
/// Process a single incoming TCP connection.
///
/// This function is executed in a new Tokio task and it will:
/// This function is executed in a new Tokio task, and it will:
/// 1. If TLS is configured, perform TLS handshake.
/// 2. Build a complete service stack for this connection, including S3, RPC services, and all middleware.
/// 3. Use Hyper to handle HTTP requests on this connection.
@@ -562,11 +563,24 @@ fn process_connection(
None
}
};
let hybrid_service = ServiceBuilder::new()
// NOTE: Both extension types are intentionally inserted to maintain compatibility:
// 1. `Option<RemoteAddr>` - Used by existing admin/storage handlers throughout the codebase
// 2. `std::net::SocketAddr` - Required by TrustedProxyMiddleware for proxy validation
// This dual insertion is necessary because the middleware expects the raw SocketAddr type
// while our application code uses the RemoteAddr wrapper. Consolidating these would
// require either modifying the third-party middleware or refactoring all existing handlers.
.layer(AddExtensionLayer::new(remote_addr))
.option_layer(remote_addr.map(|ra| AddExtensionLayer::new(ra.0)))
// Add TrustedProxyLayer to handle X-Forwarded-For and other proxy headers
// This should be placed before TraceLayer so that logs reflect the real client IP
.option_layer(if rustfs_trusted_proxies::is_enabled() {
Some(rustfs_trusted_proxies::layer().clone())
} else {
None
})
.layer(SetRequestIdLayer::x_request_id(MakeRequestUuid))
.layer(CatchPanicLayer::new())
.layer(AddExtensionLayer::new(remote_addr))
// CRITICAL: Insert ReadinessGateLayer before business logic
// This stops requests from hitting IAMAuth or Storage if they are not ready.
.layer(ReadinessGateLayer::new(readiness))
@@ -578,10 +592,18 @@ fn process_connection(
.get(http::header::HeaderName::from_static("x-request-id"))
.and_then(|v| v.to_str().ok())
.unwrap_or("unknown");
// Extract real client IP from trusted proxy middleware if available
let client_info = request.extensions().get::<ClientInfo>();
let real_ip = client_info
.map(|info| info.real_ip.to_string())
.unwrap_or_else(|| "unknown".to_string());
let span = tracing::info_span!("http-request",
trace_id = %trace_id,
status_code = tracing::field::Empty,
method = %request.method(),
real_ip = %real_ip,
uri = %request.uri(),
version = ?request.version(),
);
@@ -773,7 +795,7 @@ fn get_listen_backlog() -> i32 {
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
let mut name = [libc::CTL_KERN, libc::KERN_IPC, libc::KIPC_SOMAXCONN];
let mut buf = [0; 1];
let mut buf_len = std::mem::size_of_val(&buf);
let mut buf_len = size_of_val(&buf);
if unsafe {
libc::sysctl(