Refactor and unify SSE encryption and decryption processes

This commit is contained in:
reatang
2026-01-17 01:48:37 +08:00
parent a26ddf3aaa
commit c24728d044
2 changed files with 200 additions and 209 deletions

View File

@@ -26,9 +26,8 @@ use crate::storage::entity;
use crate::storage::helper::OperationHelper;
use crate::storage::options::{filter_object_metadata, get_content_sha256};
use crate::storage::sse::{
DecryptionRequest, InMemoryAsyncReader, ManagedEncryptionMaterial, SsecParams, apply_decryption, apply_ssec_encryption,
create_managed_encryption_material, decrypt_managed_encryption_key, derive_part_nonce, generate_ssec_nonce, is_managed_sse,
store_ssec_metadata, strip_managed_encryption_metadata, validate_ssec_params,
DecryptionRequest, EncryptionRequest, InMemoryAsyncReader, apply_decryption, apply_encryption,
decrypt_managed_encryption_key, derive_part_nonce, prepare_sse_configuration, strip_managed_encryption_metadata,
};
use crate::storage::{
access::{ReqInfo, authorize_request},
@@ -102,7 +101,7 @@ use rustfs_policy::policy::{
action::{Action, S3Action},
{BucketPolicy, BucketPolicyArgs, Validator},
};
use rustfs_rio::{CompressReader, DecryptReader, EncryptReader, EtagReader, HashReader, Reader, WarpReader};
use rustfs_rio::{CompressReader, EncryptReader, EtagReader, HashReader, Reader, WarpReader};
use rustfs_s3select_api::{
object_store::bytes_stream,
query::{Context, Query},
@@ -138,8 +137,6 @@ use std::{
};
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
use tokio::sync::mpsc;
// AsyncRead and AsyncSeek moved to sse module
use crate::storage::sse::{EncryptionRequest, apply_encryption};
use tokio_stream::wrappers::ReceiverStream;
use tokio_tar::Archive;
use tokio_util::io::{ReaderStream, StreamReader};
@@ -992,11 +989,24 @@ impl S3 for FS {
let mut reader: Box<dyn Reader> = Box::new(WarpReader::new(gr.stream));
if let Some((key_bytes, nonce, original_size_opt)) =
decrypt_managed_encryption_key(&src_bucket, &src_key, &src_info.user_defined).await?
{
reader = Box::new(DecryptReader::new(reader, key_bytes, nonce));
if let Some(original) = original_size_opt {
// Apply unified SSE decryption for source object if encrypted
// Note: SSE-C for copy source is handled via copy_source_sse_customer_* headers
let copy_source_sse_customer_key = req.input.copy_source_sse_customer_key.as_ref();
let copy_source_sse_customer_key_md5 = req.input.copy_source_sse_customer_key_md5.as_ref();
let decryption_request = DecryptionRequest {
bucket: &src_bucket,
key: &src_key,
metadata: &src_info.user_defined,
sse_customer_key: copy_source_sse_customer_key,
sse_customer_key_md5: copy_source_sse_customer_key_md5,
part_number: None,
parts: &src_info.parts,
};
if let Some(material) = apply_decryption(decryption_request).await? {
reader = material.wrap_single_reader(reader);
if let Some(original) = material.original_size {
src_info.actual_size = original;
}
}
@@ -1059,43 +1069,31 @@ impl S3 for FS {
let mut reader = HashReader::new(reader, length, actual_size, None, None, false).map_err(ApiError::from)?;
if let Some(ref sse_alg) = effective_sse
&& is_managed_sse(sse_alg)
{
let material =
create_managed_encryption_material(&bucket, &key, sse_alg, effective_kms_key_id.clone(), actual_size).await?;
let ManagedEncryptionMaterial {
data_key,
headers,
kms_key_id: kms_key_used,
} = material;
let key_bytes = data_key.plaintext_key;
let nonce = data_key.nonce;
src_info.user_defined.extend(headers.into_iter());
effective_kms_key_id = Some(kms_key_used.clone());
let encrypt_reader = EncryptReader::new(reader, key_bytes, nonce);
reader = HashReader::new(Box::new(encrypt_reader), -1, actual_size, None, None, false).map_err(ApiError::from)?;
}
// Apply SSE-C encryption if customer-provided key is specified
if let (Some(sse_alg), Some(sse_key), Some(sse_md5)) = (&sse_customer_algorithm, &sse_customer_key, &sse_customer_key_md5)
{
let params = SsecParams {
algorithm: sse_alg.as_str().to_string(),
key: sse_key.clone(),
key_md5: sse_md5.clone(),
};
let validated = validate_ssec_params(&params)?;
let encrypted_reader = apply_ssec_encryption(reader, &validated, &bucket, &key);
// Apply unified SSE encryption for destination object
let encryption_request = EncryptionRequest {
bucket: &bucket,
key: &key,
server_side_encryption: effective_sse.clone(),
ssekms_key_id: effective_kms_key_id.clone(),
sse_customer_algorithm: sse_customer_algorithm.clone(),
sse_customer_key: sse_customer_key,
sse_customer_key_md5: sse_customer_key_md5.clone(),
content_size: actual_size,
part_number: None,
};
if let Some(material) = apply_encryption(encryption_request).await? {
// Apply encryption wrapper
let encrypted_reader = material.wrap_reader(reader);
reader = HashReader::new(encrypted_reader, -1, actual_size, None, None, false).map_err(ApiError::from)?;
// Store SSE-C metadata for GET responses
store_ssec_metadata(&mut src_info.user_defined, &validated, actual_size);
// Merge encryption metadata
src_info.user_defined.extend(material.metadata);
// Update effective_kms_key_id if managed SSE was used
if let Some(kms_key_id) = material.kms_key_id {
effective_kms_key_id = Some(kms_key_id);
}
}
src_info.put_object_reader = Some(PutObjReader::new(reader));
@@ -3496,42 +3494,15 @@ impl S3 for FS {
metadata.insert(AMZ_OBJECT_TAGGING.to_owned(), tags);
}
// TDD: Get bucket SSE configuration for multipart upload
let bucket_sse_config = metadata_sys::get_sse_config(&bucket).await.ok();
debug!("TDD: Got bucket SSE config for multipart: {:?}", bucket_sse_config);
// Prepare SSE configuration using unified API
let sse_config = prepare_sse_configuration(&bucket, server_side_encryption, ssekms_key_id).await?;
let effective_sse = sse_config.effective_sse.clone();
let mut effective_kms_key_id = sse_config.effective_kms_key_id.clone();
// TDD: Determine effective encryption (request parameters override bucket defaults)
let original_sse = server_side_encryption.clone();
let effective_sse = server_side_encryption.or_else(|| {
bucket_sse_config.as_ref().and_then(|(config, _timestamp)| {
debug!("TDD: Processing bucket SSE config for multipart: {:?}", config);
config.rules.first().and_then(|rule| {
debug!("TDD: Processing SSE rule for multipart: {:?}", rule);
rule.apply_server_side_encryption_by_default.as_ref().map(|sse| {
debug!("TDD: Found SSE default for multipart: {:?}", sse);
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 to AES256
}
})
})
})
});
debug!("TDD: effective_sse for multipart={:?} (original={:?})", effective_sse, original_sse);
let _original_kms_key_id = ssekms_key_id.clone();
let mut effective_kms_key_id = ssekms_key_id.or_else(|| {
bucket_sse_config.as_ref().and_then(|(config, _timestamp)| {
config.rules.first().and_then(|rule| {
rule.apply_server_side_encryption_by_default
.as_ref()
.and_then(|sse| sse.kms_master_key_id.clone())
})
})
});
// Store effective SSE information in metadata for multipart upload
// For multipart upload, generate encryption material if managed SSE is used
// This material will be stored in metadata and used by upload_part and complete_multipart_upload
// Note: SSE-C doesn't need key generation here, just store algorithm and key MD5
if let Some(sse_alg) = &sse_customer_algorithm {
metadata.insert(
"x-amz-server-side-encryption-customer-algorithm".to_string(),
@@ -3542,27 +3513,30 @@ impl S3 for FS {
metadata.insert("x-amz-server-side-encryption-customer-key-md5".to_string(), sse_md5.clone());
}
if let Some(sse) = &effective_sse {
if is_managed_sse(sse) {
let material = create_managed_encryption_material(&bucket, &key, sse, effective_kms_key_id.clone(), 0).await?;
let ManagedEncryptionMaterial {
data_key: _,
headers,
kms_key_id: kms_key_used,
} = material;
metadata.extend(headers.into_iter());
effective_kms_key_id = Some(kms_key_used.clone());
} else {
metadata.insert("x-amz-server-side-encryption".to_string(), sse.as_str().to_string());
// Generate encryption material for managed SSE (SSE-S3/SSE-KMS)
// The encryption material (data key + nonce) will be used by upload_part and complete_multipart_upload
let encryption_request = EncryptionRequest {
bucket: &bucket,
key: &key,
server_side_encryption: effective_sse.clone(),
ssekms_key_id: effective_kms_key_id.clone(),
sse_customer_algorithm: None, // SSE-C is handled separately
sse_customer_key: None,
sse_customer_key_md5: None,
content_size: 0, // Size unknown at multipart creation
part_number: None,
};
if let Some(material) = apply_encryption(encryption_request).await? {
// Store encryption metadata for later use by upload_part and complete_multipart_upload
metadata.extend(material.metadata);
// Update effective_kms_key_id if managed SSE was used
if let Some(kms_key_id) = material.kms_key_id {
effective_kms_key_id = Some(kms_key_id);
}
}
if let Some(kms_key_id) = &effective_kms_key_id {
metadata.insert("x-amz-server-side-encryption-aws-kms-key-id".to_string(), kms_key_id.clone());
}
if is_compressible(&req.headers, &key) {
metadata.insert(
format!("{RESERVED_METADATA_PREFIX_LOWER}compression"),
@@ -3719,31 +3693,30 @@ impl S3 for FS {
let actual_size = size;
// Apply SSE-C encryption for upload_part if customer provided key
if let (Some(sse_alg), Some(sse_key), Some(sse_key_md5)) =
(&sse_customer_algorithm, &sse_customer_key, &sse_customer_key_md5)
{
let params = SsecParams {
algorithm: sse_alg.as_str().to_string(),
key: sse_key.clone(),
key_md5: sse_key_md5.clone(),
};
let validated = validate_ssec_params(&params)?;
// For multipart upload, derive a unique nonce for each part
// This ensures each part has a different nonce while maintaining determinism
let base_nonce = generate_ssec_nonce(&bucket, &key);
let part_nonce = derive_part_nonce(base_nonce, part_id);
// Apply encryption with part-specific nonce
let encrypted_reader = EncryptReader::new(reader, validated.key_bytes, part_nonce);
reader = Box::new(encrypted_reader);
// Apply unified SSE encryption for upload_part
// Note: For SSE-C, the key is provided with each part upload
// For managed SSE, the encryption material was generated in create_multipart_upload
let encryption_request = EncryptionRequest {
bucket: &bucket,
key: &key,
server_side_encryption: None, // Managed SSE handled below
ssekms_key_id: None,
sse_customer_algorithm: sse_customer_algorithm.clone(),
sse_customer_key: sse_customer_key,
sse_customer_key_md5: sse_customer_key_md5.clone(),
content_size: actual_size,
part_number: Some(part_id),
};
if let Some(material) = apply_encryption(encryption_request).await? {
// Apply encryption wrapper
let encrypted_reader = material.wrap_reader(reader);
reader = encrypted_reader;
// When encrypting, size becomes unknown since encryption adds authentication tags
size = -1;
debug!("Applied SSE-C encryption to part {} with derived nonce for {}/{}", part_id, bucket, key);
debug!("Applied {:?} encryption to part {} for {}/{}", material.encryption_type, part_id, bucket, key);
}
let mut md5hex = if let Some(base64_md5) = input.content_md5 {
@@ -3777,9 +3750,23 @@ impl S3 for FS {
return Err(ApiError::from(StorageError::other(format!("add_checksum error={err:?}"))).into());
}
if let Some((key_bytes, base_nonce, _)) = decrypt_managed_encryption_key(&bucket, &key, &fi.user_defined).await? {
let part_nonce = derive_part_nonce(base_nonce, part_id);
let encrypt_reader = EncryptReader::new(reader, key_bytes, part_nonce);
// Apply managed SSE encryption if configured in multipart upload metadata
// The encryption material (data key + nonce) was generated in create_multipart_upload
let decryption_request = DecryptionRequest {
bucket: &bucket,
key: &key,
metadata: &fi.user_defined,
sse_customer_key: None, // SSE-C already handled above
sse_customer_key_md5: None,
part_number: Some(part_id),
parts: &[],
};
if let Some(material) = apply_decryption(decryption_request).await? {
// For upload_part, we use the decryption material to get the key/nonce,
// then apply encryption (since we're encrypting the part data)
let part_nonce = derive_part_nonce(material.nonce, part_id);
let encrypt_reader = EncryptReader::new(reader, material.key_bytes, part_nonce);
reader = HashReader::new(Box::new(encrypt_reader), -1, actual_size, None, None, false).map_err(ApiError::from)?;
}
@@ -3979,11 +3966,24 @@ impl S3 for FS {
let mut reader: Box<dyn Reader> = Box::new(WarpReader::new(src_stream));
if let Some((key_bytes, nonce, original_size_opt)) =
decrypt_managed_encryption_key(&src_bucket, &src_key, &src_info.user_defined).await?
{
reader = Box::new(DecryptReader::new(reader, key_bytes, nonce));
if let Some(original) = original_size_opt {
// Apply unified SSE decryption for source object if encrypted
// Note: SSE-C for copy source is handled via copy_source_sse_customer_* headers
let copy_source_sse_customer_key = req.input.copy_source_sse_customer_key.as_ref();
let copy_source_sse_customer_key_md5 = req.input.copy_source_sse_customer_key_md5.as_ref();
let src_decryption_request = DecryptionRequest {
bucket: &src_bucket,
key: &src_key,
metadata: &src_info.user_defined,
sse_customer_key: copy_source_sse_customer_key,
sse_customer_key_md5: copy_source_sse_customer_key_md5,
part_number: None,
parts: &src_info.parts,
};
if let Some(material) = apply_decryption(src_decryption_request).await? {
reader = material.wrap_single_reader(reader);
if let Some(original) = material.original_size {
src_info.actual_size = original;
}
}
@@ -3999,9 +3999,23 @@ impl S3 for FS {
let mut reader = HashReader::new(reader, size, actual_size, None, None, false).map_err(ApiError::from)?;
if let Some((key_bytes, base_nonce, _)) = decrypt_managed_encryption_key(&bucket, &key, &mp_info.user_defined).await? {
let part_nonce = derive_part_nonce(base_nonce, part_id);
let encrypt_reader = EncryptReader::new(reader, key_bytes, part_nonce);
// Apply managed SSE encryption for destination multipart upload if configured
// The encryption material (data key + nonce) was generated in create_multipart_upload
let dst_decryption_request = DecryptionRequest {
bucket: &bucket,
key: &key,
metadata: &mp_info.user_defined,
sse_customer_key: None, // SSE-C not supported for upload_part_copy destination
sse_customer_key_md5: None,
part_number: Some(part_id),
parts: &[],
};
if let Some(material) = apply_decryption(dst_decryption_request).await? {
// For upload_part_copy, we use the decryption material to get the key/nonce,
// then apply encryption (since we're encrypting the part data)
let part_nonce = derive_part_nonce(material.nonce, part_id);
let encrypt_reader = EncryptReader::new(reader, material.key_bytes, part_nonce);
reader = HashReader::new(Box::new(encrypt_reader), -1, actual_size, None, None, false).map_err(ApiError::from)?;
}
@@ -4247,39 +4261,38 @@ impl S3 for FS {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
// TDD: Get multipart info to extract encryption configuration before completing
info!(
"TDD: Attempting to get multipart info for bucket={}, key={}, upload_id={}",
bucket, key, upload_id
);
// Get multipart info to extract encryption configuration before completing
let multipart_info = store
.get_multipart_info(&bucket, &key, &upload_id, &ObjectOptions::default())
.await
.map_err(ApiError::from)?;
info!("TDD: Got multipart info successfully");
info!("TDD: Multipart info metadata: {:?}", multipart_info.user_defined);
// TDD: Extract encryption information from multipart upload metadata
// Extract encryption information from multipart upload metadata
// For managed SSE (SSE-S3/SSE-KMS), the encryption material was generated in create_multipart_upload
// For SSE-C, the algorithm and key MD5 were stored in metadata
let server_side_encryption = multipart_info
.user_defined
.get("x-amz-server-side-encryption")
.map(|s| ServerSideEncryption::from(s.clone()));
info!(
"TDD: Raw encryption from metadata: {:?} -> parsed: {:?}",
multipart_info.user_defined.get("x-amz-server-side-encryption"),
server_side_encryption
);
let ssekms_key_id = multipart_info
.user_defined
.get("x-amz-server-side-encryption-aws-kms-key-id")
.cloned();
info!(
"TDD: Extracted encryption info - SSE: {:?}, KMS Key: {:?}",
server_side_encryption, ssekms_key_id
let _sse_customer_algorithm = multipart_info
.user_defined
.get("x-amz-server-side-encryption-customer-algorithm")
.map(|s| SSECustomerAlgorithm::from(s.clone()));
let _sse_customer_key_md5 = multipart_info
.user_defined
.get("x-amz-server-side-encryption-customer-key-md5")
.cloned();
debug!(
"Extracted encryption info from multipart - SSE: {:?}, KMS Key: {:?}, SSE-C: {:?}",
server_side_encryption, ssekms_key_id, _sse_customer_algorithm
);
let obj_info = store
@@ -4370,8 +4383,8 @@ impl S3 for FS {
key: Some(key.clone()),
e_tag: obj_info.etag.clone().map(|etag| to_s3s_etag(&etag)),
location: Some("us-east-1".to_string()),
server_side_encryption: server_side_encryption.clone(), // TDD: Return encryption info
ssekms_key_id: ssekms_key_id.clone(), // TDD: Return KMS key ID if present
server_side_encryption: server_side_encryption.clone(),
ssekms_key_id: ssekms_key_id.clone(),
checksum_crc32: checksum_crc32.clone(),
checksum_crc32c: checksum_crc32c.clone(),
checksum_sha1: checksum_sha1.clone(),
@@ -4381,18 +4394,14 @@ impl S3 for FS {
version_id: mpu_version,
..Default::default()
};
info!(
"TDD: Created output: SSE={:?}, KMS={:?}",
output.server_side_encryption, output.ssekms_key_id
);
let helper_output = entity::CompleteMultipartUploadOutput {
bucket: Some(bucket.clone()),
key: Some(key.clone()),
e_tag: obj_info.etag.clone().map(|etag| to_s3s_etag(&etag)),
location: Some("us-east-1".to_string()),
server_side_encryption, // TDD: Return encryption info
ssekms_key_id, // TDD: Return KMS key ID if present
server_side_encryption,
ssekms_key_id,
checksum_crc32,
checksum_crc32c,
checksum_sha1,

View File

@@ -655,13 +655,16 @@ async fn apply_managed_encryption_material(
// Build metadata headers
let mut metadata = HashMap::new();
// Try to use service for metadata formatting if available, otherwise build manually
if let Some(service) = get_global_encryption_service().await {
metadata = service.metadata_to_headers(&encryption_metadata);
} else {
// Manual metadata building for test mode
metadata.insert("x-rustfs-encryption-key".to_string(), BASE64_STANDARD.encode(&encryption_metadata.encrypted_data_key));
metadata.insert(
"x-rustfs-encryption-key".to_string(),
BASE64_STANDARD.encode(&encryption_metadata.encrypted_data_key),
);
metadata.insert("x-rustfs-encryption-iv".to_string(), BASE64_STANDARD.encode(&encryption_metadata.iv));
metadata.insert("x-rustfs-encryption-algorithm".to_string(), encryption_metadata.algorithm.clone());
metadata.insert("x-amz-server-side-encryption".to_string(), algorithm_str.to_string());
@@ -671,7 +674,7 @@ async fn apply_managed_encryption_material(
metadata.insert("x-amz-server-side-encryption-aws-kms-key-id".to_string(), kms_key_to_use.clone());
}
}
metadata.insert(
"x-rustfs-encryption-original-size".to_string(),
encryption_metadata.original_size.to_string(),
@@ -695,8 +698,8 @@ async fn apply_managed_encryption_material(
}
async fn apply_managed_decryption_material(
bucket: &str,
key: &str,
_bucket: &str,
_key: &str,
metadata: &HashMap<String, String>,
part_number: Option<usize>,
) -> Result<Option<DecryptionMaterial>, ApiError> {
@@ -853,51 +856,35 @@ impl KmsSseDekProvider {
pub async fn new() -> Result<Self, ApiError> {
let service = get_global_encryption_service()
.await
.ok_or_else(|| ApiError::from(StorageError::other(
"KMS encryption service is not initialized"
)))?;
.ok_or_else(|| ApiError::from(StorageError::other("KMS encryption service is not initialized")))?;
Ok(Self { service })
}
}
#[async_trait]
impl SseDekProvider for KmsSseDekProvider {
async fn generate_sse_dek(
&self,
bucket: &str,
key: &str,
kms_key_id: &str,
) -> Result<(DataKey, Vec<u8>), ApiError> {
let context = ObjectEncryptionContext::new(
bucket.to_string(),
key.to_string()
);
async fn generate_sse_dek(&self, bucket: &str, key: &str, kms_key_id: &str) -> Result<(DataKey, Vec<u8>), ApiError> {
let context = ObjectEncryptionContext::new(bucket.to_string(), key.to_string());
let kms_key_option = Some(kms_key_id.to_string());
let (data_key, encrypted_data_key) = self.service
let (data_key, encrypted_data_key) = self
.service
.create_data_key(&kms_key_option, &context)
.await
.map_err(|e| ApiError::from(StorageError::other(
format!("Failed to create data key: {}", e)
)))?;
.map_err(|e| ApiError::from(StorageError::other(format!("Failed to create data key: {}", e))))?;
Ok((data_key, encrypted_data_key))
}
async fn decrypt_sse_dek(
&self,
encrypted_dek: &[u8],
_kms_key_id: &str,
) -> Result<[u8; 32], ApiError> {
async fn decrypt_sse_dek(&self, encrypted_dek: &[u8], _kms_key_id: &str) -> Result<[u8; 32], ApiError> {
// Create a minimal context for decryption
let context = ObjectEncryptionContext::new("".to_string(), "".to_string());
let data_key = self.service
let data_key = self
.service
.decrypt_data_key(encrypted_dek, &context)
.await
.map_err(|e| ApiError::from(StorageError::other(
format!("Failed to decrypt data key: {}", e)
)))?;
.map_err(|e| ApiError::from(StorageError::other(format!("Failed to decrypt data key: {}", e))))?;
Ok(data_key.plaintext_key)
}
}
@@ -907,28 +894,28 @@ impl SseDekProvider for KmsSseDekProvider {
// ============================================================================
/// Simple SSE DEK provider for testing purposes
///
///
/// This provider reads a single 32-byte customer master key (CMK) from the
/// `__RUSTFS_SSE_SIMPLE_CMK` environment variable. The key must be base64-encoded.
///
///
/// # Environment Variable Format
///
///
/// ```text
/// __RUSTFS_SSE_SIMPLE_CMK=<base64_encoded_32_byte_key>
/// ```
///
///
/// Example:
/// ```bash
/// export __RUSTFS_SSE_SIMPLE_CMK="AKHul86TBMMJ3+VrGlh9X3dHJsOtSXOXHOODPwmAnOo="
/// ```
///
///
/// # Key Generation
///
///
/// Use the provided script to generate a valid key:
/// ```bash
/// # Windows
/// .\scripts\generate-sse-keys.ps1
///
///
/// # Linux/Unix/macOS
/// ./scripts/generate-sse-keys.sh
/// ```
@@ -956,10 +943,7 @@ impl SimpleSseDekProvider {
arr
}
Err(_) => {
eprintln!(
"✗ Failed to load master key: decoded key is not 32 bytes (got {} bytes)",
decoded_len
);
eprintln!("✗ Failed to load master key: decoded key is not 32 bytes (got {} bytes)", decoded_len);
[0u8; 32]
}
}
@@ -1092,7 +1076,7 @@ pub async fn get_sse_dek_provider() -> Result<Arc<dyn SseDekProvider>, ApiError>
if let Some(provider) = GLOBAL_SSE_DEK_PROVIDER.get() {
return Ok(provider.clone());
}
// Determine provider based on environment variable
let provider: Arc<dyn SseDekProvider> = if std::env::var("__RUSTFS_SSE_SIMPLE_CMK").is_ok() {
debug!("Using SimpleSseDekProvider (test mode) based on __RUSTFS_SSE_SIMPLE_CMK");
@@ -1101,14 +1085,12 @@ pub async fn get_sse_dek_provider() -> Result<Arc<dyn SseDekProvider>, ApiError>
debug!("Using KmsSseDekProvider (production mode)");
Arc::new(KmsSseDekProvider::new().await?)
};
// Store in global cache
GLOBAL_SSE_DEK_PROVIDER
.set(provider.clone())
.map_err(|_| ApiError::from(StorageError::other(
"Failed to initialize global SSE DEK provider (already set)"
)))?;
.map_err(|_| ApiError::from(StorageError::other("Failed to initialize global SSE DEK provider (already set)")))?;
Ok(provider)
}