mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-21 11:56:38 +00:00
fix(replication): rebuild SSE metadata boundary for encrypted objects (#5872)
Groundwork for encrypted-object replication (backlog#1783, PR-A of 3): - classify_replication_source_encryption: accept the AES256 marker that every stored SSE-C object carries; the SseC arm was unreachable. - Fail closed on sealed material without an SSE marker (MinIO-written objects) instead of replicating ciphertext as plaintext. - Replace the dead VALID_SSE_REPLICATION_HEADERS table with a transport map keyed by the metadata keys the SSE writer actually persists, shared via the new rustfs_utils::http::object_encryption_keys module. - Structurally strip all encryption metadata from outbound replication (x-rustfs-encryption-* envelopes previously passed the filters). - Skip decrypt_checksums for encrypted objects at the boundary so its is_multipart=false (a response-path contract) cannot misroute encrypted multipart objects once managed replication opens. - Redact X-Rustfs-Replication-* SSE transport values in FileInfo Debug. A reconciliation test pins that every key encryption_material_to_metadata produces is either transport-mapped or stripped. All four SSE replication e2e contracts still assert FAILED unchanged.
This commit is contained in:
@@ -278,7 +278,11 @@ pub struct FileInfo {
|
||||
fn is_sensitive_metadata_key(key: &str) -> bool {
|
||||
// `is_encryption_metadata_key` covers the x-minio-internal- SSE prefix but not
|
||||
// its x-rustfs-internal- twin, which the dual-key invariant writes alongside it.
|
||||
is_encryption_metadata_key(key) || starts_with_ignore_ascii_case(key, "x-rustfs-internal-server-side-encryption-")
|
||||
is_encryption_metadata_key(key)
|
||||
|| starts_with_ignore_ascii_case(key, "x-rustfs-internal-server-side-encryption-")
|
||||
|| rustfs_utils::http::REPLICATION_SSE_TRANSPORT_PREFIXES
|
||||
.iter()
|
||||
.any(|prefix| starts_with_ignore_ascii_case(key, prefix))
|
||||
}
|
||||
|
||||
struct RedactedMetadata<'a>(&'a HashMap<String, String>);
|
||||
@@ -2559,6 +2563,30 @@ mod tests {
|
||||
assert!(dump.contains("text/plain"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug_redacts_replication_sse_transport_metadata_values() {
|
||||
let sealed_key = "IAAfANqt7wIJfVSgFAG3f5S6HuC2eyM5DdJlx7RSJKw2ZakSb3d5";
|
||||
let mut fi = FileInfo::default();
|
||||
for key in [
|
||||
"X-Rustfs-Replication-Server-Side-Encryption-Sealed-Key",
|
||||
"X-Rustfs-Replication-Server-Side-Encryption-Iv",
|
||||
"X-Rustfs-Replication-Encryption-Iv",
|
||||
"X-Rustfs-Replication-Ssec-Key-Md5",
|
||||
] {
|
||||
fi.metadata.insert(key.to_string(), sealed_key.to_string());
|
||||
}
|
||||
fi.metadata.insert("content-type".to_string(), "text/plain".to_string());
|
||||
|
||||
let dump = format!("{fi:?}");
|
||||
assert!(
|
||||
!dump.contains(sealed_key),
|
||||
"replication SSE transport value leaked into Debug output: {dump}"
|
||||
);
|
||||
assert!(dump.contains("X-Rustfs-Replication-Server-Side-Encryption-Sealed-Key"));
|
||||
assert!(dump.contains(&format!("<redacted {} bytes>", sealed_key.len())));
|
||||
assert!(dump.contains("text/plain"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug_elides_inline_data_bytes() {
|
||||
let fi = FileInfo {
|
||||
|
||||
Reference in New Issue
Block a user