refactor(sse): keep one bucket-default algorithm mapping for every writer (#6251)

This commit is contained in:
Zhengchao An
2026-08-19 14:30:04 +08:00
committed by GitHub
parent bce0c05f3c
commit 5cb12300bc
4 changed files with 31 additions and 35 deletions
+5 -24
View File
@@ -97,7 +97,7 @@ use super::storage_api::object_usecase::set_disk::{
};
use super::storage_api::object_usecase::sse::{
DecryptionRequest, EncryptionRequest, SSEType, SseKmsPrincipal, apply_bucket_default_lock_retention,
authorize_sse_kms_object_read, build_ssec_read_headers, encryption_material_to_metadata,
authorize_sse_kms_object_read, bucket_default_write_sse, build_ssec_read_headers, encryption_material_to_metadata,
extract_server_side_encryption_from_headers, extract_ssec_params_from_headers, extract_ssekms_context_from_headers,
get_buffer_size_opt_in, load_bucket_object_lock_config_state, map_get_object_reader_error, sse_decryption, sse_encryption,
validate_bucket_object_lock_enabled_state,
@@ -169,8 +169,8 @@ use s3s::dto::{
ObjectLockLegalHoldStatus, ObjectLockMode, ObjectLockRetention, ObjectLockRetentionMode, ObjectPart, PutObjectInput,
PutObjectOutput, Range, RequestCharged, RestoreObjectInput, RestoreObjectOutput, RestoreStatus, SSECustomerAlgorithm,
SSECustomerKeyMD5, SSEKMSKeyId, SelectObjectContentInput, SelectObjectContentOutput, ServerSideEncryption,
ServerSideEncryptionByDefault, ServerSideEncryptionConfiguration, StorageClass, StreamingBlob, TaggingDirective,
TaggingHeader, Timestamp, TimestampFormat, WebsiteRedirectLocation,
ServerSideEncryptionConfiguration, StorageClass, StreamingBlob, TaggingDirective, TaggingHeader, Timestamp, TimestampFormat,
WebsiteRedirectLocation,
};
use s3s::header::{X_AMZ_RESTORE, X_AMZ_RESTORE_OUTPUT_PATH};
use s3s::stream::{ByteStream, DynByteStream, RemainingLength};
@@ -2676,25 +2676,6 @@ fn has_put_sse_request_headers(headers: &HeaderMap) -> bool {
|| headers.get(AMZ_SERVER_SIDE_ENCRYPTION_KMS_ID).is_some()
}
/// Managed SSE resolved from a bucket default encryption rule on the copy path.
///
/// Unknown algorithms fall back to AES256, the same total mapping as the PUT and
/// extract paths and the storage-layer resolver (`prepare_sse_configuration`), which
/// `sse_encryption` re-runs when it mints the destination DEK. Resolving `None` here
/// instead lets a same-name copy under a malformed bucket default pass the
/// `copy_changes_encryption` guard and take the metadata-only shortcut while the
/// storage layer still encrypts: fresh DEK metadata is committed beside the untouched
/// plaintext blocks and the object becomes unreadable. Reachable only via corrupt or
/// hand-edited bucket metadata — PutBucketEncryption rejects unknown algorithms
/// (backlog#1826).
fn bucket_default_write_sse(sse: &ServerSideEncryptionByDefault) -> ServerSideEncryption {
match sse.sse_algorithm.as_str() {
"AES256" => ServerSideEncryption::from_static(ServerSideEncryption::AES256),
"aws:kms" => ServerSideEncryption::from_static(ServerSideEncryption::AWS_KMS),
_ => ServerSideEncryption::from_static(ServerSideEncryption::AES256),
}
}
/// Resolve the effective server-side encryption for a write against the bucket's
/// default encryption configuration.
///
@@ -10115,8 +10096,8 @@ mod tests {
DefaultRetention, Delete, DeleteMarkerReplication, DeleteMarkerReplicationStatus, DeleteReplication,
DeleteReplicationStatus, Destination, ExistingObjectReplication, ExistingObjectReplicationStatus, ObjectIdentifier,
ObjectLockConfiguration, ObjectLockEnabled, ObjectLockRule, ReplicaModifications, ReplicaModificationsStatus,
ReplicationConfiguration, ReplicationRule, ReplicationRuleStatus, RestoreRequest, ServerSideEncryptionConfiguration,
ServerSideEncryptionRule, SourceSelectionCriteria,
ReplicationConfiguration, ReplicationRule, ReplicationRuleStatus, RestoreRequest, ServerSideEncryptionByDefault,
ServerSideEncryptionConfiguration, ServerSideEncryptionRule, SourceSelectionCriteria,
};
use std::pin::Pin;
use std::sync::Arc;
+3 -2
View File
@@ -1032,8 +1032,9 @@ pub(crate) mod sse {
validate_bucket_object_lock_enabled_state,
};
pub(crate) use crate::storage::storage_api::sse_consumer::{
EncryptionKeyKind, SSEType, build_ssec_read_headers, encryption_material_to_metadata, extract_ssec_params_from_headers,
extract_ssekms_context_from_headers, map_get_object_reader_error, mark_encrypted_multipart_metadata,
EncryptionKeyKind, SSEType, bucket_default_write_sse, build_ssec_read_headers, encryption_material_to_metadata,
extract_ssec_params_from_headers, extract_ssekms_context_from_headers, map_get_object_reader_error,
mark_encrypted_multipart_metadata,
};
}
+20 -6
View File
@@ -164,7 +164,7 @@ use rustfs_utils::http::headers::{
AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5, AMZ_SERVER_SIDE_ENCRYPTION_KMS_CONTEXT,
};
use rustfs_utils::path::path_join_buf;
use s3s::dto::{SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5, SSEKMSKeyId};
use s3s::dto::{SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5, SSEKMSKeyId, ServerSideEncryptionByDefault};
use std::borrow::Cow;
// ============================================================================
@@ -203,6 +203,24 @@ pub struct SseConfiguration {
/// Effective KMS key ID (after considering bucket defaults)
pub effective_kms_key_id: Option<SSEKMSKeyId>,
}
/// Managed SSE resolved from a bucket default encryption rule on a write path.
///
/// The single mapping shared by every writer: this resolver, and the PUT, COPY
/// and extract paths in `app::object_usecase`, which reach it through
/// `resolve_bucket_default_sse`. Unknown algorithms fall back to AES256 rather
/// than to `None`. Resolving `None` instead lets a same-name copy under a
/// malformed bucket default pass the `copy_changes_encryption` guard and take
/// the metadata-only shortcut while this layer still encrypts: fresh DEK
/// metadata is committed beside the untouched plaintext blocks and the object
/// becomes unreadable. Reachable only via corrupt or hand-edited bucket
/// metadata — PutBucketEncryption rejects unknown algorithms (backlog#1826).
pub(crate) fn bucket_default_write_sse(sse: &ServerSideEncryptionByDefault) -> ServerSideEncryption {
match sse.sse_algorithm.as_str() {
"AES256" => ServerSideEncryption::from_static(ServerSideEncryption::AES256),
"aws:kms" => ServerSideEncryption::from_static(ServerSideEncryption::AWS_KMS),
_ => ServerSideEncryption::from_static(ServerSideEncryption::AES256),
}
}
/// Prepare SSE configuration by resolving request parameters with bucket defaults
///
@@ -266,11 +284,7 @@ async fn prepare_sse_configuration(
has_kms_key_id = sse.kms_master_key_id.is_some(),
"Bucket SSE default resolved"
);
match sse.sse_algorithm.as_str() {
"AES256" => ServerSideEncryption::from_static(ServerSideEncryption::AES256),
"aws:kms" => ServerSideEncryption::from_static(ServerSideEncryption::AWS_KMS),
_ => ServerSideEncryption::from_static(ServerSideEncryption::AES256), // fallback
}
bucket_default_write_sse(sse)
})
})
});
+3 -3
View File
@@ -344,9 +344,9 @@ pub(crate) mod s3_api_consumer {
pub(crate) mod sse_consumer {
pub(crate) use super::super::sse::{
EncryptionKeyKind, SSEType, build_ssec_read_headers, encryption_material_to_metadata, extract_ssec_params_from_headers,
extract_ssekms_context_from_headers, log_sse_kms_key_policy_mode, map_get_object_reader_error,
mark_encrypted_multipart_metadata,
EncryptionKeyKind, SSEType, bucket_default_write_sse, build_ssec_read_headers, encryption_material_to_metadata,
extract_ssec_params_from_headers, extract_ssekms_context_from_headers, log_sse_kms_key_policy_mode,
map_get_object_reader_error, mark_encrypted_multipart_metadata,
};
pub(crate) use super::{
DecryptionRequest, EncryptionRequest, PrepareEncryptionRequest, SseKmsPrincipal, apply_bucket_default_lock_retention,