mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-27 23:47:28 +00:00
feat(kms): report the configuration references that block a key deletion (#5598)
* feat(kms): report configuration references that block a key deletion Adds a KeyImpactReport that states which configuration still points at a key, how exhaustively the sources were read, and which sources were not consulted at all. The report deliberately carries no in-use or safe-to-delete claim: it covers the configuration layer only, so an empty reference list means nothing was found in the scanned sources, never that the key is unreferenced. Immediate deletion destroys key material without ever reaching the deletion worker, so it never passed the worker's reference gate. The manager now consults the same checker on that path and refuses with a typed KeyStillReferenced error. This only ever adds a refusal; the scheduled deletion path and the worker's blocking behaviour are unchanged. * test(kms): cover the immediate-deletion reference refusal * feat(kms): surface configuration references on the admin key endpoints DeleteKey and DescribeKey now return an impact section listing the configuration that points at the key, so an operator scheduling a deletion sees what will refuse to destroy the material instead of learning it from a server-side log once the window has run out. The section is reported, never acted on: scheduling still succeeds while references exist, and the deletion worker's gate remains the only thing that decides whether material is destroyed. An immediate deletion that the manager refuses for an outstanding reference now answers 409. * test(kms): pin the impact wire shape and the unreferenced force-delete path * fix(kms): make the DescribeKey impact section opt-in Collecting the section lists every bucket, and DescribeKey is polled, so carrying that fan-out on the default read path trades a hot path's cost for a diagnostic. It is now collected only for impact=true; without the parameter the endpoint does exactly the work it did before and returns no impact field. A value that is neither true nor false is refused rather than read as off, so a typo cannot answer a request for the section with a response that merely lacks one. DeleteKey still reports unconditionally: that is the request whose consequences the caller cannot otherwise see, and it is not polled. * fix(kms): box the query-parse refusal now that responses carry impact The delete response grew an impact section, which pushed it past the size clippy accepts inline in a Result. It is a full response body rather than an error code, so it is boxed at the one place that returns it as an error; the wire shape and the public field type are unchanged.
This commit is contained in:
@@ -144,6 +144,16 @@ pub enum KmsError {
|
||||
"Baseline version lost for key {key_id}: master key version records exist (oldest {oldest_version}) but the key record carries no baseline version, so data keys written before versioned rotation can no longer be resolved to the master key version that wrapped them. A node older than versioned rotation rewrote the key record and dropped the field. Finish upgrading every node, restore baseline_version to {oldest_version} on the key record, then retry"
|
||||
)]
|
||||
BaselineVersionLost { key_id: String, oldest_version: u32 },
|
||||
|
||||
/// Configuration still points at the key, so its material must not be
|
||||
/// destroyed. Distinct from the generic invalid-operation errors so that
|
||||
/// callers can tell "this key is still wired into the deployment" apart
|
||||
/// from a malformed request and act on the listed references.
|
||||
#[error(
|
||||
"Key {key_id} is still referenced by configuration and its material must not be destroyed: {}. Remove or repoint the listed configuration, then retry",
|
||||
.references.join(", ")
|
||||
)]
|
||||
KeyStillReferenced { key_id: String, references: Vec<String> },
|
||||
}
|
||||
|
||||
impl KmsError {
|
||||
@@ -252,6 +262,14 @@ impl KmsError {
|
||||
Self::OperationCancelled { message: message.into() }
|
||||
}
|
||||
|
||||
/// Create a still-referenced error
|
||||
pub fn key_still_referenced<S: Into<String>>(key_id: S, references: Vec<String>) -> Self {
|
||||
Self::KeyStillReferenced {
|
||||
key_id: key_id.into(),
|
||||
references,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a material missing error
|
||||
pub fn material_missing<S: Into<String>>(key_id: S) -> Self {
|
||||
Self::MaterialMissing { key_id: key_id.into() }
|
||||
|
||||
Reference in New Issue
Block a user