mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-08 22:33:22 +00:00
300 lines
12 KiB
Rust
300 lines
12 KiB
Rust
// Copyright 2024 RustFS Team
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Comprehensive KMS integration tests
|
|
//!
|
|
//! This module contains comprehensive end-to-end tests that combine multiple KMS features
|
|
//! and test real-world scenarios with mixed encryption types, large datasets, and
|
|
//! complex workflows.
|
|
|
|
use super::common::{
|
|
EncryptionType, LocalKMSTestEnvironment, MultipartTestConfig, create_sse_c_config, sse_customer_key_md5_base64,
|
|
test_all_multipart_encryption_types, test_kms_key_management, test_multipart_upload_with_config, test_sse_c_encryption,
|
|
test_sse_kms_encryption, test_sse_s3_encryption,
|
|
};
|
|
use crate::common::{TEST_BUCKET, init_logging};
|
|
use serial_test::serial;
|
|
use tokio::time::{Duration, sleep};
|
|
use tracing::info;
|
|
|
|
/// Comprehensive test: Full KMS workflow with all encryption types
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_comprehensive_kms_full_workflow() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
init_logging();
|
|
info!("🏁 Start the KMS full-featured synthesis test");
|
|
|
|
let mut kms_env = LocalKMSTestEnvironment::new().await?;
|
|
let _default_key_id = kms_env.start_rustfs_for_local_kms().await?;
|
|
sleep(Duration::from_secs(3)).await;
|
|
|
|
let s3_client = kms_env.base_env.create_s3_client();
|
|
kms_env.base_env.create_test_bucket(TEST_BUCKET).await?;
|
|
|
|
// Phase 1: Test all single encryption types
|
|
info!("📋 Phase 1: Test all single-file encryption types");
|
|
test_sse_s3_encryption(&s3_client, TEST_BUCKET).await?;
|
|
test_sse_kms_encryption(&s3_client, TEST_BUCKET).await?;
|
|
test_sse_c_encryption(&s3_client, TEST_BUCKET).await?;
|
|
|
|
// Phase 2: Test KMS key management APIs
|
|
info!("📋 Phase 2: Test the KMS Key Management API");
|
|
test_kms_key_management(&kms_env.base_env.url, &kms_env.base_env.access_key, &kms_env.base_env.secret_key).await?;
|
|
|
|
// Phase 3: Test all multipart encryption types
|
|
info!("📋 Phase 3: Test all shard upload encryption types");
|
|
test_all_multipart_encryption_types(&s3_client, TEST_BUCKET, "comprehensive-multipart-test").await?;
|
|
|
|
// Phase 4: Mixed workload test
|
|
info!("📋 Phase 4: Mixed workload testing");
|
|
test_mixed_encryption_workload(&s3_client, TEST_BUCKET).await?;
|
|
|
|
kms_env.base_env.delete_test_bucket(TEST_BUCKET).await?;
|
|
info!("✅ KMS fully functional comprehensive test passed");
|
|
Ok(())
|
|
}
|
|
|
|
/// Test mixed encryption workload with different file sizes and encryption types
|
|
async fn test_mixed_encryption_workload(
|
|
s3_client: &aws_sdk_s3::Client,
|
|
bucket: &str,
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
info!("🔄 Test hybrid crypto workloads");
|
|
|
|
// Test configuration: different sizes and encryption types
|
|
let test_configs = vec![
|
|
// Small single-part uploads (S3 allows <5MB for the final part)
|
|
MultipartTestConfig::new("mixed-small-none", 1024 * 1024, 1, EncryptionType::None),
|
|
MultipartTestConfig::new("mixed-small-sse-s3", 1024 * 1024, 1, EncryptionType::SSES3),
|
|
MultipartTestConfig::new("mixed-small-sse-kms", 1024 * 1024, 1, EncryptionType::SSEKMS),
|
|
// SSE-C multipart uploads must respect the 5MB minimum part-size to avoid inline storage paths
|
|
MultipartTestConfig::new("mixed-medium-sse-s3", 5 * 1024 * 1024, 3, EncryptionType::SSES3),
|
|
MultipartTestConfig::new("mixed-medium-sse-kms", 5 * 1024 * 1024, 3, EncryptionType::SSEKMS),
|
|
MultipartTestConfig::new("mixed-medium-sse-c", 5 * 1024 * 1024, 3, create_sse_c_config()),
|
|
// Large multipart files
|
|
MultipartTestConfig::new("mixed-large-sse-s3", 10 * 1024 * 1024, 2, EncryptionType::SSES3),
|
|
MultipartTestConfig::new("mixed-large-sse-kms", 10 * 1024 * 1024, 2, EncryptionType::SSEKMS),
|
|
MultipartTestConfig::new("mixed-large-sse-c", 10 * 1024 * 1024, 2, create_sse_c_config()),
|
|
];
|
|
|
|
for (i, config) in test_configs.iter().enumerate() {
|
|
info!("🔄 Perform hybrid testing {}/{}: {:?}", i + 1, test_configs.len(), config.encryption_type);
|
|
test_multipart_upload_with_config(s3_client, bucket, config).await?;
|
|
}
|
|
|
|
info!("✅ Hybrid cryptographic workload tests pass");
|
|
Ok(())
|
|
}
|
|
|
|
/// Comprehensive stress test: Large dataset with multiple encryption types
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_comprehensive_stress_test() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
init_logging();
|
|
info!("💪 Start the KMS stress test");
|
|
|
|
let mut kms_env = LocalKMSTestEnvironment::new().await?;
|
|
let _default_key_id = kms_env.start_rustfs_for_local_kms().await?;
|
|
sleep(Duration::from_secs(3)).await;
|
|
|
|
let s3_client = kms_env.base_env.create_s3_client();
|
|
kms_env.base_env.create_test_bucket(TEST_BUCKET).await?;
|
|
|
|
// Large multipart uploads with different encryption types
|
|
let stress_configs = vec![
|
|
MultipartTestConfig::new("stress-sse-s3-large", 15 * 1024 * 1024, 4, EncryptionType::SSES3),
|
|
MultipartTestConfig::new("stress-sse-kms-large", 15 * 1024 * 1024, 4, EncryptionType::SSEKMS),
|
|
MultipartTestConfig::new("stress-sse-c-large", 15 * 1024 * 1024, 4, create_sse_c_config()),
|
|
];
|
|
|
|
for config in stress_configs {
|
|
info!(
|
|
"💪 Perform stress test: {:?}, Total size: {}MB",
|
|
config.encryption_type,
|
|
config.total_size() / (1024 * 1024)
|
|
);
|
|
test_multipart_upload_with_config(&s3_client, TEST_BUCKET, &config).await?;
|
|
}
|
|
|
|
kms_env.base_env.delete_test_bucket(TEST_BUCKET).await?;
|
|
info!("✅ KMS stress test passed");
|
|
Ok(())
|
|
}
|
|
|
|
/// Test encryption key isolation and security
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_comprehensive_key_isolation() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
init_logging();
|
|
info!("🔐 Begin the comprehensive test of encryption key isolation");
|
|
|
|
let mut kms_env = LocalKMSTestEnvironment::new().await?;
|
|
let _default_key_id = kms_env.start_rustfs_for_local_kms().await?;
|
|
sleep(Duration::from_secs(3)).await;
|
|
|
|
let s3_client = kms_env.base_env.create_s3_client();
|
|
kms_env.base_env.create_test_bucket(TEST_BUCKET).await?;
|
|
|
|
// Test different SSE-C keys to ensure isolation
|
|
let key1 = "01234567890123456789012345678901";
|
|
let key2 = "98765432109876543210987654321098";
|
|
let key1_md5 = sse_customer_key_md5_base64(key1);
|
|
let key2_md5 = sse_customer_key_md5_base64(key2);
|
|
|
|
let config1 = MultipartTestConfig::new(
|
|
"isolation-test-key1",
|
|
5 * 1024 * 1024,
|
|
2,
|
|
EncryptionType::SSEC {
|
|
key: key1.to_string(),
|
|
key_md5: key1_md5,
|
|
},
|
|
);
|
|
|
|
let config2 = MultipartTestConfig::new(
|
|
"isolation-test-key2",
|
|
5 * 1024 * 1024,
|
|
2,
|
|
EncryptionType::SSEC {
|
|
key: key2.to_string(),
|
|
key_md5: key2_md5,
|
|
},
|
|
);
|
|
|
|
// Upload with different keys
|
|
info!("🔐 Key 1 for uploading files");
|
|
test_multipart_upload_with_config(&s3_client, TEST_BUCKET, &config1).await?;
|
|
|
|
info!("🔐 Key 2 for uploading files");
|
|
test_multipart_upload_with_config(&s3_client, TEST_BUCKET, &config2).await?;
|
|
|
|
// Verify that files cannot be read with wrong keys
|
|
info!("🔒 Verify key isolation");
|
|
let wrong_key = "11111111111111111111111111111111";
|
|
let wrong_key_b64 = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, wrong_key);
|
|
let wrong_key_md5 = sse_customer_key_md5_base64(wrong_key);
|
|
|
|
// Try to read file encrypted with key1 using wrong key
|
|
let wrong_read_result = s3_client
|
|
.get_object()
|
|
.bucket(TEST_BUCKET)
|
|
.key(&config1.object_key)
|
|
.sse_customer_algorithm("AES256")
|
|
.sse_customer_key(&wrong_key_b64)
|
|
.sse_customer_key_md5(&wrong_key_md5)
|
|
.send()
|
|
.await;
|
|
|
|
assert!(wrong_read_result.is_err(), "The encrypted file should not be readable with the wrong key");
|
|
info!("✅ Confirm that key isolation is working correctly");
|
|
|
|
kms_env.base_env.delete_test_bucket(TEST_BUCKET).await?;
|
|
info!("✅ Encryption key isolation comprehensive test passed");
|
|
Ok(())
|
|
}
|
|
|
|
/// Test concurrent encryption operations
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_comprehensive_concurrent_operations() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
init_logging();
|
|
info!("⚡ Started comprehensive testing of concurrent encryption operations");
|
|
|
|
let mut kms_env = LocalKMSTestEnvironment::new().await?;
|
|
let _default_key_id = kms_env.start_rustfs_for_local_kms().await?;
|
|
sleep(Duration::from_secs(3)).await;
|
|
|
|
let s3_client = kms_env.base_env.create_s3_client();
|
|
kms_env.base_env.create_test_bucket(TEST_BUCKET).await?;
|
|
|
|
// Create multiple concurrent upload tasks
|
|
let multipart_part_size = 5 * 1024 * 1024; // honour S3 minimum part size for multipart uploads
|
|
let concurrent_configs = vec![
|
|
MultipartTestConfig::new("concurrent-1-sse-s3", multipart_part_size, 2, EncryptionType::SSES3),
|
|
MultipartTestConfig::new("concurrent-2-sse-kms", multipart_part_size, 2, EncryptionType::SSEKMS),
|
|
MultipartTestConfig::new("concurrent-3-sse-c", multipart_part_size, 2, create_sse_c_config()),
|
|
MultipartTestConfig::new("concurrent-4-none", multipart_part_size, 2, EncryptionType::None),
|
|
];
|
|
|
|
// Execute uploads concurrently
|
|
info!("⚡ Start concurrent uploads");
|
|
let mut tasks = Vec::new();
|
|
for config in concurrent_configs {
|
|
let client = s3_client.clone();
|
|
let bucket = TEST_BUCKET.to_string();
|
|
tasks.push(tokio::spawn(
|
|
async move { test_multipart_upload_with_config(&client, &bucket, &config).await },
|
|
));
|
|
}
|
|
|
|
// Wait for all tasks to complete
|
|
for task in tasks {
|
|
task.await??;
|
|
}
|
|
|
|
info!("✅ All concurrent operations are completed");
|
|
|
|
kms_env.base_env.delete_test_bucket(TEST_BUCKET).await?;
|
|
info!("✅ The comprehensive test of concurrent encryption operation has passed");
|
|
Ok(())
|
|
}
|
|
|
|
/// Test encryption/decryption performance with different file sizes
|
|
#[tokio::test]
|
|
#[serial]
|
|
async fn test_comprehensive_performance_benchmark() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
init_logging();
|
|
info!("📊 Start KMS performance benchmarking");
|
|
|
|
let mut kms_env = LocalKMSTestEnvironment::new().await?;
|
|
let _default_key_id = kms_env.start_rustfs_for_local_kms().await?;
|
|
sleep(Duration::from_secs(3)).await;
|
|
|
|
let s3_client = kms_env.base_env.create_s3_client();
|
|
kms_env.base_env.create_test_bucket(TEST_BUCKET).await?;
|
|
|
|
// Performance test configurations with increasing file sizes
|
|
let perf_configs = vec![
|
|
("small", MultipartTestConfig::new("perf-small", 1024 * 1024, 1, EncryptionType::SSES3)),
|
|
(
|
|
"medium",
|
|
MultipartTestConfig::new("perf-medium", 5 * 1024 * 1024, 2, EncryptionType::SSES3),
|
|
),
|
|
(
|
|
"large",
|
|
MultipartTestConfig::new("perf-large", 10 * 1024 * 1024, 3, EncryptionType::SSES3),
|
|
),
|
|
];
|
|
|
|
for (size_name, config) in perf_configs {
|
|
info!("📊 Test {} file performance ({}MB)", size_name, config.total_size() / (1024 * 1024));
|
|
|
|
let start_time = std::time::Instant::now();
|
|
test_multipart_upload_with_config(&s3_client, TEST_BUCKET, &config).await?;
|
|
let duration = start_time.elapsed();
|
|
|
|
let throughput_mbps = (config.total_size() as f64 / (1024.0 * 1024.0)) / duration.as_secs_f64();
|
|
info!(
|
|
"📊 {} file test completed: {:.2} seconds, throughput: {:.2} MB/s",
|
|
size_name,
|
|
duration.as_secs_f64(),
|
|
throughput_mbps
|
|
);
|
|
}
|
|
|
|
kms_env.base_env.delete_test_bucket(TEST_BUCKET).await?;
|
|
info!("✅ KMS performance benchmark passed");
|
|
Ok(())
|
|
}
|