fix(storage): restore legacy SSE-S3 read compatibility (#3584)

* Update .gitignore

* Fix. fixed SSE-S3 compatibility issues in large-scale testing

* fix

* fix(ecstore): reject whitespace bucket names

* Update replication_extension_test.rs

* style(ecstore): format bucket whitespace test

---------

Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: cxymds <cxymds@gmail.com>
This commit is contained in:
唐小鸭
2026-06-23 21:35:17 +08:00
committed by GitHub
parent 5c60f0cae9
commit eff656e086
13 changed files with 1239 additions and 11 deletions
+68 -2
View File
@@ -1680,10 +1680,22 @@ async fn apply_managed_decryption_material(
// Use factory pattern to get provider (test or production mode)
let provider = get_sse_dek_provider().await?;
#[cfg(feature = "rio-v2")]
let decrypted_data_key = if is_legacy_rustfs_managed_metadata(&normalized_metadata) {
provider
.decrypt_legacy_sse_dek(&encrypted_data_key, &kms_key_id, &object_context)
.await
} else {
provider
.decrypt_sse_dek(&encrypted_data_key, &kms_key_id, &object_context)
.await
};
#[cfg(not(feature = "rio-v2"))]
let decrypted_data_key = provider
.decrypt_sse_dek(&encrypted_data_key, &kms_key_id, &object_context)
.await
.map_err(|e| ApiError::from(StorageError::other(format!("Failed to decrypt data key: {e}"))))?;
.await;
let decrypted_data_key =
decrypted_data_key.map_err(|e| ApiError::from(StorageError::other(format!("Failed to decrypt data key: {e}"))))?;
#[cfg(feature = "rio-v2")]
let (key_bytes, base_nonce, key_kind) = if let Some(sealed_key) = minio_sealed_key {
(
@@ -1761,6 +1773,17 @@ pub trait SseDekProvider: Send + Sync {
kms_key_id: &str,
context: &ObjectEncryptionContext,
) -> Result<[u8; 32], ApiError>;
/// Decrypt a DEK from positively identified legacy managed metadata.
#[cfg(feature = "rio-v2")]
async fn decrypt_legacy_sse_dek(
&self,
encrypted_dek: &[u8],
kms_key_id: &str,
context: &ObjectEncryptionContext,
) -> Result<[u8; 32], ApiError> {
self.decrypt_sse_dek(encrypted_dek, kms_key_id, context).await
}
}
// ============================================================================
@@ -1820,6 +1843,24 @@ impl SseDekProvider for KmsSseDekProvider {
Ok(data_key.plaintext_key)
}
#[cfg(feature = "rio-v2")]
async fn decrypt_legacy_sse_dek(
&self,
encrypted_dek: &[u8],
_kms_key_id: &str,
_context: &ObjectEncryptionContext,
) -> Result<[u8; 32], ApiError> {
let service = Self::current_service()
.await
.ok_or_else(|| ApiError::from(StorageError::other("KMS encryption service is not initialized")))?;
let data_key = service
.decrypt_legacy_data_key(encrypted_dek)
.await
.map_err(|e| ApiError::from(StorageError::other(format!("Failed to decrypt legacy data key: {e}"))))?;
Ok(data_key.plaintext_key)
}
}
// ============================================================================
@@ -2139,6 +2180,14 @@ fn contains_managed_encryption_metadata(metadata: &HashMap<String, String>) -> b
|| metadata.contains_key(MINIO_INTERNAL_ENCRYPTION_KMS_CONTEXT_HEADER)
}
#[cfg(feature = "rio-v2")]
fn is_legacy_rustfs_managed_metadata(metadata: &HashMap<String, String>) -> bool {
metadata.contains_key(INTERNAL_ENCRYPTION_KEY_HEADER)
&& metadata.contains_key(INTERNAL_ENCRYPTION_IV_HEADER)
&& !metadata.contains_key(MINIO_INTERNAL_ENCRYPTION_S3_SEALED_KEY_HEADER)
&& !metadata.contains_key(MINIO_INTERNAL_ENCRYPTION_KMS_SEALED_KEY_HEADER)
}
#[cfg(feature = "rio-v2")]
fn parse_minio_managed_sealed_key(
metadata: &HashMap<String, String>,
@@ -3047,6 +3096,23 @@ mod tests {
assert!(metadata.contains_key("content-type"));
}
#[cfg(feature = "rio-v2")]
#[test]
fn test_legacy_managed_metadata_excludes_sealed_keys() {
let legacy_metadata = HashMap::from([
(INTERNAL_ENCRYPTION_KEY_HEADER.to_string(), "encrypted-dek".to_string()),
(INTERNAL_ENCRYPTION_IV_HEADER.to_string(), "nonce".to_string()),
]);
assert!(is_legacy_rustfs_managed_metadata(&legacy_metadata));
let sealed_metadata = HashMap::from([
(INTERNAL_ENCRYPTION_KEY_HEADER.to_string(), "encrypted-dek".to_string()),
(INTERNAL_ENCRYPTION_IV_HEADER.to_string(), "nonce".to_string()),
(MINIO_INTERNAL_ENCRYPTION_S3_SEALED_KEY_HEADER.to_string(), "sealed-key".to_string()),
]);
assert!(!is_legacy_rustfs_managed_metadata(&sealed_metadata));
}
#[cfg(feature = "rio-v2")]
#[test]
fn test_normalize_managed_metadata_accepts_minio_only_headers() {