mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-01 19:12:14 +00:00
739efaaea1
* feat(kms): add link_durably primitive and restore-marker startup guard The local backend gains the two pieces the bundle restore path builds on: a no-clobber hard-link publish primitive whose AlreadyExists case is idempotent only for byte-identical content, and a fail-closed startup guard that refuses to open a key directory holding a restore cutover marker. The durable commit protocol and the key-id containment check become pub(crate) so the restore module reuses them instead of copies. * feat(kms): record a master-key verifier and pre-seal decrypt probe in export Fill the manifest's master_key_verifier slot with an opaque one-way value (scheme-prefixed, bound to the backup id and the KDF salt) so a restore can detect a wrong operator-supplied master key before touching any target state, and probe-decrypt every artifact as stored under the backup KEK before the manifest may seal — digest equality alone only proves the ciphertext landed intact. The payload decryption tail is factored out and shared with the restore side so producer and consumer cannot drift on the framing. Also drops the stale KmsClient test import orphaned by the backend refactor (#5501); the test suite did not compile without this. * feat(kms): restore local backend key material from sealed backup bundles The consumer side of the Local bundle export, as a four-phase protocol: - Dry-run: full in-memory bundle decode (digest and AEAD verification of every artifact), KDF-drift detection against the compiled-in derivation, deployment and injected-generation checks (strictly lower is rejected, equal stays allowed for repeated drills), master-key verifier check, and target conflict enumeration - with zero writes. - Staging: artifacts are committed durably into the .restore-staging/ subdirectory (invisible to the backend's key scan and orphan-temp matcher) and every record is decryption-probed with the derived master key both in memory before staging and again from the staged bytes. - Commit marker + cutover: the durably published .restore-commit.json marker is the single commit point; cutover publishes staged files via link_durably (salt first, keys after), then durably removes the marker and drops staging. - Crash re-entry: before the marker the target top level is untouched and a re-run starts over; with the marker published, backend startup fails closed and a re-run with the same bundle rolls forward while abort_local_restore rolls back. Every interruption converges to the complete old or complete new state. Restore never goes through LocalKmsClient::new (which would mint a fresh salt); the only write mode is the explicit restore-into-empty-target policy, where an orphan salt or a foreign marker already counts as non-empty. The bundle source stays strictly read-only. Refs rustfs/backlog#1572