refactor(kms): consolidate encryption metadata key constants into their shared home (#5995)

The shared module rustfs_utils::http::object_encryption_keys is the single source of truth for encryption metadata key names, but three call sites still carried their own copies or bare literals: crates/kms/src/service.rs (two private constants plus four bare x-rustfs-encryption-* literals on both the write and read path), rustfs/src/app/select_object.rs (six SELECT_* copies), and rustfs/src/storage/options.rs (two private prefix copies now imported from header_compat). All values are unchanged, so the change is a compiler-verified rename.

The reader-only x-rustfs-internal-server-side-encryption- family gets a named constant with the verified judgment recorded on it: no writer emits these keys anywhere in the repo (the SSE writer persists the MinIO-branded keys verbatim for interop), the two comments claiming the dual-key invariant writes this twin were wrong and are corrected, and the defensive redaction/strip readers are kept because removing them is risk-asymmetric.

rustfs-kms's rustfs-utils dependency now declares the http feature it uses instead of relying on feature unification from sibling crates.

Refs rustfs/backlog#1775, rustfs/backlog#1562.
This commit is contained in:
Zhengchao An
2026-08-13 00:37:38 +08:00
committed by GitHub
parent 24ca61eb6e
commit 60d8e8a20b
6 changed files with 46 additions and 34 deletions
+12 -17
View File
@@ -27,6 +27,10 @@ use base64::Engine;
use jiff::Zoned;
use md5::{Digest as Md5Digest, Md5};
use rand::random;
use rustfs_utils::http::object_encryption_keys::{
INTERNAL_ENCRYPTION_ALGORITHM_HEADER, INTERNAL_ENCRYPTION_CONTEXT_HEADER, INTERNAL_ENCRYPTION_IV_HEADER,
INTERNAL_ENCRYPTION_KEY_HEADER, INTERNAL_ENCRYPTION_KEY_ID_HEADER, INTERNAL_ENCRYPTION_TAG_HEADER,
};
use std::collections::HashMap;
use std::io::Cursor;
use tokio::io::{AsyncRead, AsyncReadExt};
@@ -81,15 +85,6 @@ fn request_encryption_context(context: &ObjectEncryptionContext) -> HashMap<Stri
enc_context
}
// Canonical owners of the internal encryption header names. Note on
// INTERNAL_ENCRYPTION_ALGORITHM_HEADER: it carries the AEAD algorithm the
// object was sealed with. The S3 `x-amz-server-side-encryption` header records
// the *SSE mode* (`AES256` / `aws:kms`), not the cipher, so it cannot
// round-trip `ChaCha20Poly1305`. Without this header a ChaCha-sealed object
// comes back from the projection claiming `aws:kms` and is then opened with
// the wrong cipher.
use rustfs_utils::http::object_encryption_keys::{INTERNAL_ENCRYPTION_ALGORITHM_HEADER, INTERNAL_ENCRYPTION_KEY_ID_HEADER};
/// Result of object encryption
#[derive(Debug, Clone)]
pub struct EncryptionResult {
@@ -805,19 +800,19 @@ impl ObjectEncryptionService {
// Internal headers for decryption
headers.insert(
"x-rustfs-encryption-iv".to_string(),
INTERNAL_ENCRYPTION_IV_HEADER.to_string(),
base64::engine::general_purpose::STANDARD.encode(&metadata.iv),
);
if let Some(ref tag) = metadata.tag {
headers.insert(
"x-rustfs-encryption-tag".to_string(),
INTERNAL_ENCRYPTION_TAG_HEADER.to_string(),
base64::engine::general_purpose::STANDARD.encode(tag),
);
}
headers.insert(
"x-rustfs-encryption-key".to_string(),
INTERNAL_ENCRYPTION_KEY_HEADER.to_string(),
base64::engine::general_purpose::STANDARD.encode(&metadata.encrypted_data_key),
);
@@ -829,7 +824,7 @@ impl ObjectEncryptionService {
None => context_aad(&metadata.encryption_context).unwrap_or_default(),
};
headers.insert(
"x-rustfs-encryption-context".to_string(),
INTERNAL_ENCRYPTION_CONTEXT_HEADER.to_string(),
String::from_utf8_lossy(&context_bytes).into_owned(),
);
@@ -874,13 +869,13 @@ impl ObjectEncryptionService {
};
let iv = headers
.get("x-rustfs-encryption-iv")
.get(INTERNAL_ENCRYPTION_IV_HEADER)
.ok_or_else(|| KmsError::validation_error("Missing IV header"))?;
let iv = base64::engine::general_purpose::STANDARD
.decode(iv)
.map_err(|e| KmsError::validation_error(format!("Invalid IV: {e}")))?;
let tag = if let Some(tag_str) = headers.get("x-rustfs-encryption-tag") {
let tag = if let Some(tag_str) = headers.get(INTERNAL_ENCRYPTION_TAG_HEADER) {
Some(
base64::engine::general_purpose::STANDARD
.decode(tag_str)
@@ -890,7 +885,7 @@ impl ObjectEncryptionService {
None
};
let encrypted_data_key = if let Some(key_str) = headers.get("x-rustfs-encryption-key") {
let encrypted_data_key = if let Some(key_str) = headers.get(INTERNAL_ENCRYPTION_KEY_HEADER) {
base64::engine::general_purpose::STANDARD
.decode(key_str)
.map_err(|e| KmsError::validation_error(format!("Invalid encrypted key: {e}")))?
@@ -902,7 +897,7 @@ impl ObjectEncryptionService {
// callers that inspect the context, but the bytes are carried through
// untouched: re-serializing the parsed map is exactly how the original
// ordering — and with it the ability to open the object — was lost.
let (encryption_context, context_aad) = match headers.get("x-rustfs-encryption-context") {
let (encryption_context, context_aad) = match headers.get(INTERNAL_ENCRYPTION_CONTEXT_HEADER) {
Some(context_str) => (
serde_json::from_str(context_str)
.map_err(|e| KmsError::validation_error(format!("Invalid encryption context: {e}")))?,