fix(admin): preserve Heal target identity in SigV4 signing - #374
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related work
No dedicated rc issue. Companion server fix: rustfs/rustfs#7644. Validation harness: https://github.com/rustfs/rustfs-release-validation/pull/14.
Problem and root cause
Heal prefixes are encoded as one URL component, so the object
dir/keyis sent asdir%2Fkey, while the distinct objectdir%2Fkeyis sent asdir%252Fkey. The Admin signer used the generic AWS SigV4 defaults: double percent encoding and path normalization. Its canonical URI therefore disagreed with MinIO-compatible Admin verification, causingSignatureDoesNotMatcheven after the server's object-route fix.MinIO canonicalizes the decoded URL path with S3 path encoding, retaining slashes (upstream signer). Changing only the encoding setting is insufficient: an encoded slash must become a slash in the signing URI, without rewriting the transport URL or decoding a literal
%2Ftwice.Solution
.or..segment, to avoid selecting a different target.Regression coverage
Four new tests cover 15 canonical path vectors, encoded/literal slashes, mixed-case escapes, Unicode, spaces, plus/percent characters, repeated separators, encoded dot segments, byte preservation, query signing, payload hashes, and IPv6 authority. The canonical-request oracle is constructed independently; only the HMAC primitives are shared with the SDK.
A real HTTP capture test checks start/status/stop for three distinct prefixes (nine requests), including the exact transport target and signature. Another regression verifies rejection of five transport-normalized paths. All new regressions failed against the original signer before the fix.
Validation
Based on freshly fetched
mainatfbf5e9f447d9d0eca7c850c3898343a59a74ff0e. The submitted source passed these checks before committing (local builds used six jobs, disabled debug info/incremental compilation, and localhost proxy bypass):cargo fmt --all --checkcargo clippy --locked --workspace --all-targets -- -D warningscargo test --locked --workspace: 2,673 passed, zero failed, two existing ignored tests (the opt-in real RustFS ILM probe and a retry doctest).cargo test --locked -p rc-s3 admin::tests -- --nocapture: 174 passed.cargo build --locked -p rustfs-cli --bin rc./scripts/check-protected-files.sh origin/mainandgit diff --check.The actual built rc executable also passed a local, isolated-process API check against the server patch in rustfs/rustfs#7644:
objects/0000.bin, the distinctobjects%2F0000.bin, and中文/space +percent%/object.binusing--dry-run --scan-mode deep.dry_run_observed, zero repaired/failed/unknown items, and no counter overflow.SignatureDoesNotMatch; a standalone dot target was rejected before transport.Tested rc binary SHA-256:
fd08e9e0636ecffd7af8e1bfaf257101fa7592007189ad769b980735f55d7885. The current main workspace reportsrc 0.1.24; this is a source build, not a newly published release package. Server binary SHA-256:e9c15073f20804d833808089a3750c541ec7341df482de00d71f9fd96ce1e11b(release ancestor97c7b451dplus patch8346a3d35).Boundaries and observations
This is not a jump-host/four-disk run, a fault-repair proof, active-task cancellation, or an 84-case matrix PASS. Stop was checked against completed tasks. rc does not send pool/set selectors, and the observed topology/incarnation fields were null; no scoped repair claim is made. Existing scoped physical-validation assertions were not changed.
The local probe also observed the server's legacy status metadata echoing default settings (
scanMode=1,dryRun=false) after a deep dry-run, while the canonical disposition correctly reporteddry_run_observed. That server status-reporting discrepancy is outside this signing-only change. rustfs/rustfs#7644's separate s3s-footprint CI failure is also not changed here.