diff --git a/crates/credentials/src/credentials.rs b/crates/credentials/src/credentials.rs index e918e9265..dc8c2b503 100644 --- a/crates/credentials/src/credentials.rs +++ b/crates/credentials/src/credentials.rs @@ -259,7 +259,18 @@ fn resolve_rpc_secret(env_secret: Option<&str>, global_access: Option<&str>, glo } match (global_access, global_secret) { - (Some(access_key), Some(secret_key)) => derive_rpc_secret(access_key, secret_key), + (Some(access_key), Some(secret_key)) => { + // Fail closed: never derive the RPC secret while the default secret + // key is in effect. The derivation uses `secret_key` as the HMAC key, + // so a public default secret yields a publicly computable RPC secret + // that any network peer can use to forge internode RPC signatures. + // Operators running with default credentials must configure + // RUSTFS_RPC_SECRET (or set a non-default RUSTFS_SECRET_KEY) instead. + if secret_key.trim() == DEFAULT_SECRET_KEY { + return None; + } + derive_rpc_secret(access_key, secret_key) + } _ => None, } } @@ -575,12 +586,19 @@ mod tests { } #[test] - fn test_resolve_rpc_secret_allows_default_credentials_for_derivation() { + fn test_resolve_rpc_secret_rejects_default_credentials_for_derivation() { assert!(resolve_rpc_secret(None, None, None).is_none()); - let expected = derive_rpc_secret(DEFAULT_ACCESS_KEY, DEFAULT_SECRET_KEY).expect("secret should derive"); + // Fail closed: the default secret key must not yield a derivable RPC + // secret, otherwise the derived value is publicly computable and any + // network peer can forge internode RPC signatures. + assert!(resolve_rpc_secret(None, Some(DEFAULT_ACCESS_KEY), Some(DEFAULT_SECRET_KEY)).is_none()); + + // A default access key paired with a non-default secret key is still + // safe to derive: the HMAC key (the secret key) is not public. + let expected = derive_rpc_secret(DEFAULT_ACCESS_KEY, "custom-global-secret").expect("secret should derive"); assert_eq!( - resolve_rpc_secret(None, Some(DEFAULT_ACCESS_KEY), Some(DEFAULT_SECRET_KEY)).as_deref(), + resolve_rpc_secret(None, Some(DEFAULT_ACCESS_KEY), Some("custom-global-secret")).as_deref(), Some(expected.as_str()) );