Repository navigation
s3client: sign storage requests with the configured default region - #277
Conversation
da7ed6c to
ec02a59
Compare
arttor
left a comment
There was a problem hiding this comment.
please also rebase onto main to make tests pass on CI
| * limitations under the License. | ||
| */ | ||
|
|
||
| package s3client |
There was a problem hiding this comment.
Thanks for adding tests. In this repo storage behaviour is tested with e2e tests under test/ against real storages running in containers, not with a hand-written fake S3 server. test/env/components.go already provides Garage, SeaweedFS, MinIO, gofakes3 and Ceph RGW. test/minio/presign_test.go is an example of such a test.
Can you replace region_test.go with an e2e test against one of them configured with a region? You'll probably need to add an option in test/env to set the region on the container (e.g. via an env var). The test should cover both cases from the issue - replication to that storage and requests through the proxy - and fail on main.
ec02a59 to
550265d
Compare
| func isOnline(ctx context.Context, c *client) error { | ||
| _, err := c.mc.GetBucketLocation(ctx, "probe-health-test") | ||
| // HEAD request: with a configured region GetBucketLocation answers without contacting the storage | ||
| _, err := c.mc.BucketExists(ctx, "probe-health-test") |
There was a problem hiding this comment.
Let's not switch the health check to HEAD: HEAD errors have no body, so wrong credentials come back as a plain 403 which will now make the check pass for AccessDenied. Am I correct that the problem with keeping GetBucketLocation is that minio answers it from the configured region without sending a request?
Can you use GetBucketVersioning("probe-health-test") instead, which always reaches the storage? Also, to be safe with storages that don't implement every API, can the check treat any S3 error response as online, and fail only on network errors and credential/signature errors (InvalidAccessKeyId, SignatureDoesNotMatch, AuthorizationHeaderMalformed)?
550265d to
1fe249f
Compare
|
Thanks for the review! Yes, that's right: when the client has a region, minio-go's
I also rebased the branch onto main. |
Signed-off-by: Denis Ivanov <dendw.work@gmail.com>
Without a region minio-go resolves it with GetBucketLocation signed with us-east-1, which providers validating the credential scope reject (400 on object stat during replication). The online check now uses HEAD bucket: with a region set, GetBucketLocation no longer reaches the storage. Signed-off-by: Denis Ivanov <dendw.work@gmail.com>
With a configured region minio-go answers GetBucketLocation without a request, and a HEAD error has no body, so a bare 403 for wrong credentials looked like an online storage. GetBucketVersioning always reaches the storage: any S3 error response means it is up; network errors and InvalidAccessKeyId, SignatureDoesNotMatch, AuthorizationHeaderMalformed mean it is not. Signed-off-by: Denis Ivanov <dendw.work@gmail.com>
Replaces the fake-S3 unit test with a MinIO started with a region (env.WithRegion), which rejects requests signed for any other region. Covers replication to that storage, requests through the proxy with it as main, and the online check with valid and wrong credentials. Signed-off-by: Denis Ivanov <dendw.work@gmail.com>
Signed-off-by: Artem Torubarov <artem.torubarov@clyso.com>
1fe249f to
38e0f19
Compare
Fixes #276
Requests to storages were signed with
us-east-1regardless of the storagedefaultRegion. Providers that validate the SigV4 credential scope (e.g. Cloud.ru Object Storage) answerAuthorizationHeaderMalformed: unexpected region, expecting '<region>'(or a bare400 Bad Requestfor HEAD), so replication to such a storage fails: firstbucket:create, thenobject:sync(unable to get to object stat: 400 Bad Request) and tag sync.Three places:
pkg/s3client/aws_wrapper.go(workerHeadBucket/CreateBucket, ACL, tagging) — hardcodedus-east-1;pkg/s3client/http_forward.go— hardcodedus-east-1;pkg/s3client/client.go— created withoutRegion, so minio-go looks the region up withGetBucketLocationsigned withus-east-1, which those providers reject.Changes:
signingRegion()returns the storagedefaultRegion, orus-east-1when it is empty; the AWS SDK client and the proxy forwarding use it;Region: defaultRegion; when it is empty the lookup works as before (nous-east-1is forced, so AWS buckets in other regions keep working);isOnlineusesBucketExists(HEAD): with a configured regionGetBucketLocationanswers locally and would no longer check that the storage is reachable.Tests: region choice, signature scope of the AWS client, and an
httpteststorage asserting that withdefaultRegionthe minio client signs with that region, never calls?location, and the online check still reaches the storage (fails without the change).go test ./pkg/s3client/... ./pkg/s3/... ./pkg/objstore/... ./service/proxy/... ./service/worker/handler/...,go vet,gofmt.