objstore: support GCS S3-compatible signing#69721
Conversation
|
Skipping CI for Draft Pull Request. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds GCS S3-compatible endpoint detection, a custom SigV4 signer that excludes ChangesGCS S3-compatible signing
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant NewS3Storage
participant isGCSS3Compatible
participant gcsS3CompatibleSigner
participant v4Signer
NewS3Storage->>isGCSS3Compatible: inspect provider and endpoint
isGCSS3Compatible-->>NewS3Storage: return compatibility result
NewS3Storage->>gcsS3CompatibleSigner: configure HTTPSignerV4
gcsS3CompatibleSigner->>v4Signer: sign request without Accept-Encoding
v4Signer-->>gcsS3CompatibleSigner: return signed request
gcsS3CompatibleSigner-->>NewS3Storage: restore Accept-Encoding
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
dcb9b59 to
339f3fa
Compare
339f3fa to
b2ee22c
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #69721 +/- ##
================================================
- Coverage 76.3227% 73.9111% -2.4117%
================================================
Files 2041 2057 +16
Lines 560306 587856 +27550
================================================
+ Hits 427641 434491 +6850
- Misses 131764 152142 +20378
- Partials 901 1223 +322
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
🔍 Starting code review for this PR... |
ingress-bot
left a comment
There was a problem hiding this comment.
This review was generated by AI and should be verified by a human reviewer.
Manual follow-up is recommended before merge.
Summary
- Total findings: 6
- Inline comments: 2
- Summary-only findings (no inline anchor): 4
Findings (highest risk first)
🟡 [Minor] (5)
- Header assertions run in the httptest handler goroutine, degrading the regression guard (pkg/objstore/s3store/gcs_test.go:163)
- New GCS carve-out in officialS3 has no rationale comment near the enforcement point (pkg/objstore/s3store/store.go:243)
- Signer header-stripping test is driven through full storage construction instead of the signer directly (pkg/objstore/s3store/gcs_test.go:50, pkg/objstore/s3store/gcs_s3_signer.go:34)
- GCS signer regression test runs require.* assertions and mutates a shared counter inside the httptest handler goroutine (pkg/objstore/s3store/gcs_test.go:63, pkg/objstore/s3store/gcs_test.go:70, pkg/objstore/s3store/gcs_test.go:98)
- GCS signer test asserts and mutates shared state inside the httptest handler goroutine (pkg/objstore/s3store/gcs_test.go:65, pkg/objstore/s3store/gcs_test.go:71, pkg/objstore/s3store/gcs_test.go:98)
🧹 [Nit] (1)
- getSignedHeaders name implies a parsed list but returns a raw joined string (pkg/objstore/s3store/gcs_test.go:201)
Unanchored findings
🟡 [Minor] (3)
- Header assertions run in the httptest handler goroutine, degrading the regression guard
- Request: Capture the signed-header snapshot(s) from the handler into a slice/channel guarded from the goroutine (or record and compare after
NewS3Storagereturns), then run therequire.*header assertions in the test goroutine so a leaked header is reported directly and cleanly.
- Request: Capture the signed-header snapshot(s) from the handler into a slice/channel guarded from the goroutine (or record and compare after
- New GCS carve-out in officialS3 has no rationale comment near the enforcement point
- Request: Add a short comment on or right above this line stating that GCS-compatible backends are excluded from AWS bucket-region auto-detection because that API is AWS-specific and not meaningful against a GCS endpoint.
- Signer header-stripping test is driven through full storage construction instead of the signer directly
- Request: Add a direct unit test that calls
newGCSS3CompatibleSigner().SignHTTP(ctx, creds, req, ...)on a constructed request and asserts the header set, so signer behavior is isolated from storage construction and permission-check request counts. Keep the current integration-style test only if it needs to prove the signer wiring itself (o.HTTPSignerV4 = ...), not the header-stripping logic.
- Request: Add a direct unit test that calls
🧹 [Nit] (1)
- getSignedHeaders name implies a parsed list but returns a raw joined string
- Request: Rename to something like
signedHeadersRaw/signedHeaderList(string) or split the value into a[]stringand use exact element checks (e.g.require.NotContains(t, headers, "accept-encoding")on a slice) to make the return shape match the name.
- Request: Rename to something like
|
/retest |
ingress-bot
left a comment
There was a problem hiding this comment.
This review was generated by AI and should be verified by a human reviewer.
Manual follow-up is recommended before merge.
Summary
- Total findings: 3
- Inline comments: 2
- Summary-only findings (no inline anchor): 1
Findings (highest risk first)
🟡 [Minor] (3)
- New GCS host constant breaks the file's existing domain-naming convention (pkg/objstore/s3store/store.go:52, pkg/objstore/s3store/store.go:54)
- Endpoint-based GCS reclassification of existing configs has no end-to-end regression coverage (pkg/objstore/s3store/store.go:243, pkg/objstore/s3store/store.go:316, pkg/objstore/s3store/gcs_test.go:196)
- Virtual-hosted GCS endpoint is not detected, so the GCS signer is silently skipped (pkg/objstore/s3store/store.go:327)
Unanchored findings
🟡 [Minor] (1)
- New GCS host constant breaks the file's existing domain-naming convention
- Request: Rename
gcsEndpointto follow the existingdomain*convention (for exampledomainGCS), or rename both to a shared, consistent scheme ifEndpointis intended to become the new convention going forward.
- Request: Rename
| // SDK v1 did not. Keep sending them, but exclude all three from the canonical | ||
| // request to stay close to the AWS SDK v1 signing behavior. | ||
| savedHeaders := http.Header{} | ||
| for _, key := range []string{"Accept-Encoding", "Amz-Sdk-Invocation-Id", "Amz-Sdk-Request"} { |
There was a problem hiding this comment.
seems only remove Accept-Encoding is enough according to aws/aws-sdk-go-v2#1816 (comment) , why remove the other 2
There was a problem hiding this comment.
Updated in fe72e6f . I narrowed the signer wrapper to remove only Accept-Encoding from the canonical request.
I also verified this with a live GCS S3-compatible end-to-end run before changing the main PR: exact-file import covered GetObject, wildcard import covered ListObjectsV2 plus GetObject, and retry injection still completed without SignatureDoesNotMatch. The PR description now summarizes that coverage.
| // Perform region detection and validation | ||
| var detectedRegion string | ||
| officialS3 := len(qs.Provider) == 0 || qs.Provider == "aws" | ||
| officialS3 := !gcsS3Compatible && (len(qs.Provider) == 0 || qs.Provider == "aws") |
There was a problem hiding this comment.
a little hard to read, maybe qs.Provider == "aws" || (len(qs.Provider) == 0 && !gcsS3Compatible)
There was a problem hiding this comment.
Adjusted in fe72e6f . I split the provider check into awsProvider and then use officialS3 := awsProvider && !gcsS3Compatible.
I avoided the exact suggested expression because provider=aws with a GCS endpoint still needs the GCS-compatible path; otherwise it can fall back into AWS bucket-region discovery and hit the same HeadBucket issue.
| // Perform region detection and validation | ||
| var detectedRegion string | ||
| officialS3 := len(qs.Provider) == 0 || qs.Provider == "aws" | ||
| officialS3 := !gcsS3Compatible && (len(qs.Provider) == 0 || qs.Provider == "aws") |
There was a problem hiding this comment.
and please comment why we check gcsS3Compatible here, i.e. HeadBucket issue...
There was a problem hiding this comment.
Done in fe72e6f . I added the comment right above officialS3 to explain why GCS S3-compatible endpoints bypass AWS bucket-region discovery: the HeadBucket request can be rejected before normal object access starts, and the configured region is only used for signing in this path.
| // GCS S3 interoperability rejects signatures that include Accept-Encoding. | ||
| // AWS SDK v2 also signs the SDK request metadata headers below, while AWS | ||
| // SDK v1 did not. Keep sending them, but exclude all three from the canonical | ||
| // request to stay close to the AWS SDK v1 signing behavior. |
There was a problem hiding this comment.
please add solution sources as comment
There was a problem hiding this comment.
Added in fe72e6f . The signer comment now links the AWS SDK Go v2 issue for the Accept-Encoding signing behavior, and the GCS interoperability / request endpoint links stay next to the gcsEndpoint constant where we define the endpoint detection rule.
|
/cherry-pick release-nextgen-202603 |
|
@D3Hunter: once the present PR merges, I will cherry-pick it on top of release-nextgen-202603 in the new PR and assign it to you. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository. |
|
/retest |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: D3Hunter, GMHDBJD The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/retest |
|
@D3Hunter: new pull request created to branch DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the ti-community-infra/tichi repository. |
What problem does this PR solve?
Issue Number: close #69718
Problem Summary:
IMPORT INTOcan fail when reading source files from GCS through the S3-compatible endpoint after the S3 implementation moved to AWS SDK for Go v2.With gcs s3 compatible endpoint, SDK v2 can sign
accept-encodinginto the SigV4 canonical request. GCS S3 interoperability can reject these requests withSignatureDoesNotMatch, and region discovery can fail onHeadBucketbefore the import starts.What changed and how does it work?
This PR adds a GCS S3-compatible mode for the S3 object store:
provider=gcsandendpoint=https://storage.googleapis.com, or virtual-hosted GCS endpoints.accept-encodingfrom the canonical request while still sending the header on the HTTP request.The signer keeps the AWS SDK v2 client path. Live GCS S3-compatible testing showed that
amz-sdk-invocation-idandamz-sdk-requestcan remain signed; onlyaccept-encodingneeds to be excluded.Check List
Tests
Manual live test against the real GCS S3-compatible endpoint:
IMPORT INTOsucceeded, which validates both source discovery (ListObjectsV2) and the following object reads (GetObject).ADMIN CHECK TABLE.SignatureDoesNotMatch,Forbidden, orfailed to walk dir.Side effects
Documentation
Release note
Please refer to Release Notes Language Style Guide to write a quality release note.
Summary by CodeRabbit