mirror of
https://github.com/rustfs/rustfs.git
synced 2026-10-04 04:21:35 +00:00
fix(sse): guard copy-source SSE-C keys over TLS and reject bucket-keyed KMS context (#8296)
* fix(sse): count copy-source SSE-C headers in the TLS transport guard
The SSE-C transport guard only looked at the object's own customer-key
headers. A CopyObject or UploadPartCopy that read an SSE-C source into a
non-SSE-C destination carried the source key only in the
x-amz-copy-source-server-side-encryption-customer-* headers, so it was
accepted on a plaintext transport with RUSTFS_SSE_C_REQUIRE_TLS=true and
was missing from rustfs_ssec_plaintext_requests_total.
Treat the copy-source triple as SSE-C headers too.
* fix(sse): reject a KMS context key that replaces the location entry
Managed SSE wraps each data key under an encryption context that carries
{bucket: bucket/key}, added with or_insert, while only the client context
is persisted and the entry is rebuilt on read. A client context entry
keyed by the bucket name therefore replaced the location entry on write
and on every read, so the data key was no longer tied to the object's
location.
Reject such a context with 400 InvalidArgument at the single managed-SSE
write entry, before the KMS is called. The read side is unchanged, so
objects stored with such an entry stay readable, and other keys,
including other bucket names, are still accepted.
---------
Co-authored-by: Hauser <housemecn@gmail.com>
This commit is contained in:
@@ -137,6 +137,8 @@ This release reports rather than refuses, because flipping straight to a rejecti
|
||||
- `RUSTFS_SSE_C_REQUIRE_TLS=true` (default `false`) refuses those requests now, with the same `400 InvalidRequest` wording AWS uses. Confirm the counter reads zero before enabling it.
|
||||
- The default is expected to flip in a later release.
|
||||
|
||||
The guard covers both the object's own SSE-C headers and the `x-amz-copy-source-server-side-encryption-customer-*` headers that `CopyObject` and `UploadPartCopy` use to read an SSE-C source: either set carries a customer key.
|
||||
|
||||
The verdict is per connection: a listener that terminates TLS satisfies it, and so does an `https` protocol forwarded by a proxy the trusted-proxy configuration accepts. A direct plaintext client asserts nothing, and a forwarded protocol from an untrusted peer is not consulted.
|
||||
|
||||
## Object ciphertext format: what the v1 frame layout does and does not authenticate
|
||||
@@ -179,6 +181,12 @@ Historically the KV2 and Local backends sealed only the DEK plaintext; the `encr
|
||||
|
||||
Rollout constraint: reading bound envelopes needs no switch, but **a node that predates the field cannot open them** — its unwrap runs without the additional data and fails authentication. The switch defaults off (`ENV_KMS_ENVELOPE_AAD` in `crates/kms/src/config.rs`); enable it only after every node runs a release that understands `context_binding`, mirroring the `RUSTFS_ENCRYPTION_FRAME_V2` rollout. With the switch on, a rewrap sweep upgrades unbound envelopes to the bound format (converging to zero writes on re-run); a bound envelope never regresses to the unbound shape, and an envelope carrying an unrecognized `context_binding` value is refused rather than decrypted without its binding.
|
||||
|
||||
### Location entry in the encryption context
|
||||
|
||||
Every SSE-S3 and SSE-KMS data key is wrapped under an encryption context that includes the entry `{"<bucket>": "<bucket>/<object>"}`. Only the client-supplied part of the context (`x-amz-server-side-encryption-context`) is stored with the object; the location entry is rebuilt from the object's current location on every read, so a data key does not open at another location. How strongly that is enforced depends on the backend, as described above.
|
||||
|
||||
A client context entry whose key equals the bucket name would replace the location entry, so SSE-KMS writes refuse it with `400 InvalidArgument`. Other keys, including the names of other buckets, are accepted. Objects that an earlier release stored with such an entry remain readable. Builds with the `rio-v2` feature additionally bind each object key to its location when sealing it.
|
||||
|
||||
### Guarantees that hold only once every node is upgraded
|
||||
|
||||
These are properties of builds from `1.0.0-rc.1` onward; a single older node removes them for the whole cluster.
|
||||
|
||||
Reference in New Issue
Block a user