mirror of
https://github.com/rustfs/rustfs.git
synced 2026-01-16 17:20:33 +00:00
Resolving the issue of encryption parameters not being stored.
This commit is contained in:
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
@@ -114,6 +114,7 @@
|
|||||||
// "RUSTFS_OBS_METRIC_ENDPOINT": "http://127.0.0.1:4318/v1/metrics", // default otlp http endpoint
|
// "RUSTFS_OBS_METRIC_ENDPOINT": "http://127.0.0.1:4318/v1/metrics", // default otlp http endpoint
|
||||||
// "RUSTFS_OBS_LOG_ENDPOINT": "http://127.0.0.1:4318/v1/logs", // default otlp http endpoint
|
// "RUSTFS_OBS_LOG_ENDPOINT": "http://127.0.0.1:4318/v1/logs", // default otlp http endpoint
|
||||||
// "RUSTFS_COMPRESS_ENABLE": "true",
|
// "RUSTFS_COMPRESS_ENABLE": "true",
|
||||||
|
"__RUSTFS_SSE_SIMPLE_CMK": "2dfNXGHlsEflGVCxb+5DIdGEl1sIvtwX+QfmYasi5QM=",
|
||||||
"RUSTFS_CONSOLE_ADDRESS": "127.0.0.1:9001",
|
"RUSTFS_CONSOLE_ADDRESS": "127.0.0.1:9001",
|
||||||
"RUSTFS_OBS_LOG_DIRECTORY": "./target/logs",
|
"RUSTFS_OBS_LOG_DIRECTORY": "./target/logs",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3350,6 +3350,7 @@ impl S3 for FS {
|
|||||||
let mut reader = PutObjReader::new(reader);
|
let mut reader = PutObjReader::new(reader);
|
||||||
|
|
||||||
let mt2 = metadata.clone();
|
let mt2 = metadata.clone();
|
||||||
|
opts.user_defined.extend(metadata);
|
||||||
|
|
||||||
let repoptions =
|
let repoptions =
|
||||||
get_must_replicate_options(&mt2, "".to_string(), ReplicationStatusType::Empty, ReplicationType::Object, opts.clone());
|
get_must_replicate_options(&mt2, "".to_string(), ReplicationStatusType::Empty, ReplicationType::Object, opts.clone());
|
||||||
|
|||||||
@@ -664,18 +664,18 @@ async fn apply_managed_encryption_material(
|
|||||||
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-iv".to_string(), BASE64_STANDARD.encode(&encryption_metadata.iv));
|
||||||
metadata.insert("x-rustfs-encryption-algorithm".to_string(), encryption_metadata.algorithm.clone());
|
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());
|
||||||
|
|
||||||
|
// if kms_key is changed, we need to update the metadata
|
||||||
|
if kms_key_id.is_none() {
|
||||||
|
metadata.insert("x-amz-server-side-encryption-aws-kms-key-id".to_string(), kms_key_to_use.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.insert(
|
metadata.insert(
|
||||||
"x-rustfs-encryption-original-size".to_string(),
|
"x-rustfs-encryption-original-size".to_string(),
|
||||||
encryption_metadata.original_size.to_string(),
|
encryption_metadata.original_size.to_string(),
|
||||||
);
|
);
|
||||||
metadata.insert("x-amz-server-side-encryption".to_string(), algorithm_str.to_string());
|
|
||||||
|
|
||||||
// if kms_key is changed, we need to update the metadata
|
|
||||||
if kms_key_id.is_none() {
|
|
||||||
metadata.insert("x-amz-server-side-encryption-aws-kms-key-id".to_string(), kms_key_to_use.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle part-specific nonce if needed
|
// Handle part-specific nonce if needed
|
||||||
let nonce = if let Some(part_num) = part_number {
|
let nonce = if let Some(part_num) = part_number {
|
||||||
@@ -906,63 +906,80 @@ impl SseDekProvider for KmsSseDekProvider {
|
|||||||
// Test/Simple DEK Provider
|
// Test/Simple DEK Provider
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Implement a simple SSE DEK provider for testing purposes
|
/// 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
|
||||||
|
/// ```
|
||||||
struct SimpleSseDekProvider {
|
struct SimpleSseDekProvider {
|
||||||
cmk_ids: HashMap<String, [u8; 32]>,
|
master_key: [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
// __RUSTFS_SSE_SIMPLE_CMK_ID format: key-id1:base64_key1,key-id2:base64_key2,...
|
|
||||||
|
|
||||||
impl SimpleSseDekProvider {
|
impl SimpleSseDekProvider {
|
||||||
/// Create a SimpleSseDekProvider with predefined keys (for testing)
|
/// Create a SimpleSseDekProvider with a predefined key (for testing)
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn new_with_keys(cmk_ids: HashMap<String, [u8; 32]>) -> Self {
|
pub fn new_with_key(master_key: [u8; 32]) -> Self {
|
||||||
Self { cmk_ids }
|
Self { master_key }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let cmk_id = std::env::var("__RUSTFS_SSE_SIMPLE_CMK_ID").unwrap_or_else(|_| "".to_string());
|
let cmk_value = std::env::var("__RUSTFS_SSE_SIMPLE_CMK").unwrap_or_else(|_| "".to_string());
|
||||||
|
|
||||||
let cmk_ids: HashMap<String, [u8; 32]> = cmk_id
|
let master_key = if !cmk_value.is_empty() {
|
||||||
.split(',')
|
match BASE64_STANDARD.decode(cmk_value.trim()) {
|
||||||
.filter_map(|pair| {
|
Ok(v) => {
|
||||||
let parts: Vec<&str> = pair.split(':').collect();
|
let decoded_len = v.len();
|
||||||
if parts.len() == 2 {
|
match v.try_into() {
|
||||||
let key_name = parts[0];
|
Ok(arr) => {
|
||||||
match BASE64_STANDARD.decode(parts[1]) {
|
println!("✓ Successfully loaded master key (32 bytes)");
|
||||||
Ok(v) => {
|
arr
|
||||||
let decoded_len = v.len();
|
|
||||||
match v.try_into() {
|
|
||||||
Ok(arr) => {
|
|
||||||
println!("✓ Successfully loaded CMK: {}", key_name);
|
|
||||||
Some((key_name.to_string(), arr))
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
eprintln!(
|
|
||||||
"✗ Failed to load CMK '{}': decoded key is not 32 bytes (got {} bytes)",
|
|
||||||
key_name, decoded_len
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(_) => {
|
||||||
eprintln!("✗ Failed to load CMK '{}': invalid base64 encoding: {}", key_name, e);
|
eprintln!(
|
||||||
None
|
"✗ Failed to load master key: decoded key is not 32 bytes (got {} bytes)",
|
||||||
|
decoded_len
|
||||||
|
);
|
||||||
|
[0u8; 32]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
eprintln!("✗ Invalid CMK format in '{}': expected 'name:base64_key'", pair);
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
Err(e) => {
|
||||||
.collect();
|
eprintln!("✗ Failed to load master key: invalid base64 encoding: {}", e);
|
||||||
|
[0u8; 32]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[0u8; 32]
|
||||||
|
};
|
||||||
|
|
||||||
if cmk_ids.is_empty() {
|
if master_key == [0u8; 32] {
|
||||||
eprintln!("⚠️ WARNING: No valid CMK keys loaded! All encryption operations will fail.");
|
eprintln!("✗ Failed to load master key: no valid master key loaded! All encryption operations will fail.");
|
||||||
|
eprintln!(" Set __RUSTFS_SSE_SIMPLE_CMK environment variable to a base64-encoded 32-byte key.");
|
||||||
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { cmk_ids }
|
Self { master_key: master_key }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple encryption of DEK
|
// Simple encryption of DEK
|
||||||
@@ -1016,13 +1033,7 @@ impl SimpleSseDekProvider {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl SseDekProvider for SimpleSseDekProvider {
|
impl SseDekProvider for SimpleSseDekProvider {
|
||||||
async fn generate_sse_dek(&self, _bucket: &str, _key: &str, kms_key_id: &str) -> Result<(DataKey, Vec<u8>), ApiError> {
|
async fn generate_sse_dek(&self, _bucket: &str, _key: &str, _kms_key_id: &str) -> Result<(DataKey, Vec<u8>), ApiError> {
|
||||||
let cmk_value = self
|
|
||||||
.cmk_ids
|
|
||||||
.get(kms_key_id)
|
|
||||||
.ok_or_else(|| ApiError::from(StorageError::other(format!("CMK ID not found: {}", kms_key_id))))?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
// Generate a 32-byte array as data key
|
// Generate a 32-byte array as data key
|
||||||
let mut dek = [0u8; 32];
|
let mut dek = [0u8; 32];
|
||||||
rand::rng().fill_bytes(&mut dek);
|
rand::rng().fill_bytes(&mut dek);
|
||||||
@@ -1031,8 +1042,8 @@ impl SseDekProvider for SimpleSseDekProvider {
|
|||||||
let mut nonce = [0u8; 12];
|
let mut nonce = [0u8; 12];
|
||||||
rand::rng().fill_bytes(&mut nonce);
|
rand::rng().fill_bytes(&mut nonce);
|
||||||
|
|
||||||
// Encrypt data key
|
// Encrypt data key with master key
|
||||||
let encrypted_dek = Self::encrypt_dek(dek, cmk_value)?;
|
let encrypted_dek = Self::encrypt_dek(dek, self.master_key)?;
|
||||||
|
|
||||||
// Return data key and IV
|
// Return data key and IV
|
||||||
Ok((
|
Ok((
|
||||||
@@ -1044,18 +1055,11 @@ impl SseDekProvider for SimpleSseDekProvider {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
// Verify CMK ID exists (for testing purposes)
|
// Decrypt data key with master key
|
||||||
let cmk_value = self
|
|
||||||
.cmk_ids
|
|
||||||
.get(kms_key_id)
|
|
||||||
.ok_or_else(|| ApiError::from(StorageError::other(format!("CMK ID not found: {}", kms_key_id))))?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
// Decrypt data key
|
|
||||||
let encrypted_dek_str = std::str::from_utf8(encrypted_dek)
|
let encrypted_dek_str = std::str::from_utf8(encrypted_dek)
|
||||||
.map_err(|_| ApiError::from(StorageError::other("Invalid UTF-8 in encrypted DEK")))?;
|
.map_err(|_| ApiError::from(StorageError::other("Invalid UTF-8 in encrypted DEK")))?;
|
||||||
let dek = Self::decrypt_dek(encrypted_dek_str, cmk_value)?;
|
let dek = Self::decrypt_dek(encrypted_dek_str, self.master_key)?;
|
||||||
Ok(dek)
|
Ok(dek)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1070,7 +1074,7 @@ static GLOBAL_SSE_DEK_PROVIDER: OnceLock<Arc<dyn SseDekProvider>> = OnceLock::ne
|
|||||||
/// Get or initialize the global SSE DEK provider
|
/// Get or initialize the global SSE DEK provider
|
||||||
///
|
///
|
||||||
/// Factory function that automatically selects the appropriate provider:
|
/// Factory function that automatically selects the appropriate provider:
|
||||||
/// - If `__RUSTFS_SSE_SIMPLE_CMK_ID` environment variable exists: use SimpleSseDekProvider (test mode)
|
/// - If `__RUSTFS_SSE_SIMPLE_CMK` environment variable exists: use SimpleSseDekProvider (test mode)
|
||||||
/// - Otherwise: use KmsSseDekProvider (production mode with real KMS)
|
/// - Otherwise: use KmsSseDekProvider (production mode with real KMS)
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
@@ -1090,8 +1094,8 @@ pub async fn get_sse_dek_provider() -> Result<Arc<dyn SseDekProvider>, ApiError>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine provider based on environment variable
|
// Determine provider based on environment variable
|
||||||
let provider: Arc<dyn SseDekProvider> = if std::env::var("__RUSTFS_SSE_SIMPLE_CMK_ID").is_ok() {
|
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_ID");
|
debug!("Using SimpleSseDekProvider (test mode) based on __RUSTFS_SSE_SIMPLE_CMK");
|
||||||
Arc::new(SimpleSseDekProvider::new())
|
Arc::new(SimpleSseDekProvider::new())
|
||||||
} else {
|
} else {
|
||||||
debug!("Using KmsSseDekProvider (production mode)");
|
debug!("Using KmsSseDekProvider (production mode)");
|
||||||
@@ -1613,15 +1617,13 @@ mod tests {
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
// 1. Setup: Create SimpleSseDekProvider with test CMK
|
// 1. Setup: Create SimpleSseDekProvider with test master key
|
||||||
let mut test_keys = HashMap::new();
|
let provider = SimpleSseDekProvider::new_with_key([42u8; 32]);
|
||||||
test_keys.insert("test-key".to_string(), [42u8; 32]);
|
|
||||||
let provider = SimpleSseDekProvider::new_with_keys(test_keys);
|
|
||||||
|
|
||||||
// 2. Generate a data encryption key
|
// 2. Generate a data encryption key
|
||||||
let bucket = "test-bucket";
|
let bucket = "test-bucket";
|
||||||
let key = "test-key";
|
let key = "test-key";
|
||||||
let kms_key_id = "test-key"; // Must match the key in SimpleSseDekProvider::new()
|
let kms_key_id = "default"; // Key ID is ignored in simple provider
|
||||||
|
|
||||||
let (data_key, _encrypted_dek) = provider
|
let (data_key, _encrypted_dek) = provider
|
||||||
.generate_sse_dek(bucket, key, kms_key_id)
|
.generate_sse_dek(bucket, key, kms_key_id)
|
||||||
@@ -1682,14 +1684,12 @@ mod tests {
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
// 1. Setup: Create SimpleSseDekProvider with test CMK
|
// 1. Setup: Create SimpleSseDekProvider with test master key
|
||||||
let mut test_keys = HashMap::new();
|
let provider = SimpleSseDekProvider::new_with_key([42u8; 32]);
|
||||||
test_keys.insert("test-key".to_string(), [42u8; 32]);
|
|
||||||
let provider = SimpleSseDekProvider::new_with_keys(test_keys);
|
|
||||||
|
|
||||||
let bucket = "test-bucket";
|
let bucket = "test-bucket";
|
||||||
let key = "test-key-large";
|
let key = "test-key-large";
|
||||||
let kms_key_id = "test-key";
|
let kms_key_id = "default";
|
||||||
|
|
||||||
let (data_key, _encrypted_dek) = provider
|
let (data_key, _encrypted_dek) = provider
|
||||||
.generate_sse_dek(bucket, key, kms_key_id)
|
.generate_sse_dek(bucket, key, kms_key_id)
|
||||||
@@ -1735,14 +1735,12 @@ mod tests {
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
// 1. Setup: Create SimpleSseDekProvider with test CMK
|
// 1. Setup: Create SimpleSseDekProvider with test master key
|
||||||
let mut test_keys = HashMap::new();
|
let provider = SimpleSseDekProvider::new_with_key([42u8; 32]);
|
||||||
test_keys.insert("test-key".to_string(), [42u8; 32]);
|
|
||||||
let provider = SimpleSseDekProvider::new_with_keys(test_keys);
|
|
||||||
|
|
||||||
let bucket = "test-bucket";
|
let bucket = "test-bucket";
|
||||||
let key = "test-key";
|
let key = "test-key";
|
||||||
let kms_key_id = "test-key";
|
let kms_key_id = "default";
|
||||||
|
|
||||||
// Generate two different keys (with different nonces)
|
// Generate two different keys (with different nonces)
|
||||||
let (data_key1, _) = provider
|
let (data_key1, _) = provider
|
||||||
@@ -1787,14 +1785,12 @@ mod tests {
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
// 1. Setup: Create SimpleSseDekProvider with test CMK
|
// 1. Setup: Create SimpleSseDekProvider with test master key
|
||||||
let mut test_keys = HashMap::new();
|
let provider = SimpleSseDekProvider::new_with_key([42u8; 32]);
|
||||||
test_keys.insert("test-key".to_string(), [42u8; 32]);
|
|
||||||
let provider = SimpleSseDekProvider::new_with_keys(test_keys);
|
|
||||||
|
|
||||||
let bucket = "test-bucket";
|
let bucket = "test-bucket";
|
||||||
let key = "test-key";
|
let key = "test-key";
|
||||||
let kms_key_id = "test-key";
|
let kms_key_id = "default";
|
||||||
|
|
||||||
// 1. Generate DEK and get encrypted DEK
|
// 1. Generate DEK and get encrypted DEK
|
||||||
let (data_key, encrypted_dek) = provider
|
let (data_key, encrypted_dek) = provider
|
||||||
|
|||||||
28
scripts/generate-sse-keys.ps1
Normal file
28
scripts/generate-sse-keys.ps1
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Generate SSE encryption key (32 bytes base64 encoded)
|
||||||
|
# For testing with __RUSTFS_SSE_SIMPLE_CMK environment variable
|
||||||
|
# Usage: .\generate-sse-keys.ps1
|
||||||
|
|
||||||
|
# Function to generate a random 256-bit key and encode it in base64
|
||||||
|
function Generate-Base64Key {
|
||||||
|
# Generate 32 bytes (256 bits) of random data
|
||||||
|
$bytes = New-Object byte[] 32
|
||||||
|
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
|
||||||
|
$rng.GetBytes($bytes)
|
||||||
|
$rng.Dispose()
|
||||||
|
|
||||||
|
# Convert to base64
|
||||||
|
return [Convert]::ToBase64String($bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate key
|
||||||
|
$base64Key = Generate-Base64Key
|
||||||
|
|
||||||
|
# Output result
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Generated SSE encryption key (32 bytes, base64 encoded):" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host $base64Key -ForegroundColor Yellow
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "You can use this in your environment variable:" -ForegroundColor Cyan
|
||||||
|
Write-Host "`$env:__RUSTFS_SSE_SIMPLE_CMK=`"$base64Key`"" -ForegroundColor White
|
||||||
|
Write-Host ""
|
||||||
24
scripts/generate-sse-keys.sh
Normal file
24
scripts/generate-sse-keys.sh
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Generate SSE encryption key (32 bytes base64 encoded)
|
||||||
|
# For testing with __RUSTFS_SSE_SIMPLE_CMK environment variable
|
||||||
|
# Usage: ./generate-sse-keys.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Function to generate a random 256-bit key and encode it in base64
|
||||||
|
generate_base64_key() {
|
||||||
|
# Generate 32 bytes (256 bits) of random data and base64 encode it
|
||||||
|
openssl rand -base64 32 | tr -d '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate key
|
||||||
|
base64_key=$(generate_base64_key)
|
||||||
|
|
||||||
|
# Output result
|
||||||
|
echo "Generated SSE encryption key (32 bytes, base64 encoded):"
|
||||||
|
echo ""
|
||||||
|
echo "$base64_key"
|
||||||
|
echo ""
|
||||||
|
echo "You can use this in your environment variable:"
|
||||||
|
echo "export __RUSTFS_SSE_SIMPLE_CMK=\"$base64_key\""
|
||||||
|
|
||||||
Reference in New Issue
Block a user