Merge pull request #2493 from tunglambk/fix/create-bucket-location-constraint

fix: set the CreateBucket location constraint from the S3 backend region
This commit is contained in:
Ben McClelland
2026-10-13 14:20:58 -07:00
committed by GitHub
2 changed files with 58 additions and 1 deletions
+10
View File
@@ -204,6 +204,16 @@ func (s *S3Proxy) CreateBucket(ctx context.Context, input *s3.CreateBucketInput,
}
}
// the bucket is created in the backend region, which is independent of the
// gateway region the client's constraint was validated against; a regional
// S3 endpoint outside us-east-1 rejects a CreateBucket without a constraint
if region := s.client.Options().Region; region != "" && region != "us-east-1" {
if input.CreateBucketConfiguration == nil {
input.CreateBucketConfiguration = &types.CreateBucketConfiguration{}
}
input.CreateBucketConfiguration.LocationConstraint = types.BucketLocationConstraint(region)
}
// drop an empty CreateBucketConfiguration: strict backends (Ceph RGW) reject the empty element
if input.CreateBucketConfiguration != nil &&
len(input.CreateBucketConfiguration.Tags) == 0 &&
+48 -1
View File
@@ -54,10 +54,15 @@ func (c *captureHTTPClient) Do(req *http.Request) (*http.Response, error) {
}
func newCaptureProxy(t *testing.T) (*S3Proxy, *captureHTTPClient) {
t.Helper()
return newCaptureProxyWithRegion(t, "us-east-1")
}
func newCaptureProxyWithRegion(t *testing.T, region string) (*S3Proxy, *captureHTTPClient) {
t.Helper()
capture := &captureHTTPClient{}
client := s3.New(s3.Options{
Region: "us-east-1",
Region: region,
BaseEndpoint: aws.String("http://backend.test"),
UsePathStyle: true,
Credentials: credentials.NewStaticCredentialsProvider("access", "secret", ""),
@@ -169,3 +174,45 @@ func TestCreateBucketKeepsBucketInfo(t *testing.T) {
t.Errorf("CreateBucket with bucket info must forward the configuration, got %q", capture.body)
}
}
// The bucket is created in the backend region, not the gateway region the
// api layer validated the client's constraint against. A regional endpoint
// outside us-east-1 rejects a CreateBucket that carries no constraint, so the
// backend has to add its own even when the api layer sent none.
func TestCreateBucketSetsBackendRegionConstraint(t *testing.T) {
p, capture := newCaptureProxyWithRegion(t, "eu-west-1")
err := p.CreateBucket(context.Background(), &s3.CreateBucketInput{
Bucket: aws.String("test-bucket"),
CreateBucketConfiguration: &types.CreateBucketConfiguration{},
}, []byte{})
if err != nil {
t.Fatalf("CreateBucket: %v", err)
}
if !strings.Contains(string(capture.body), "<LocationConstraint>eu-west-1</LocationConstraint>") {
t.Errorf("CreateBucket against a regional backend must carry the backend region constraint, got %q", capture.body)
}
}
func TestCreateBucketKeepsTagsAndSetsBackendRegionConstraint(t *testing.T) {
p, capture := newCaptureProxyWithRegion(t, "eu-west-1")
err := p.CreateBucket(context.Background(), &s3.CreateBucketInput{
Bucket: aws.String("test-bucket"),
CreateBucketConfiguration: &types.CreateBucketConfiguration{
Tags: []types.Tag{
{Key: aws.String("env"), Value: aws.String("test")},
},
},
}, []byte{})
if err != nil {
t.Fatalf("CreateBucket: %v", err)
}
body := string(capture.body)
if !strings.Contains(body, "<LocationConstraint>eu-west-1</LocationConstraint>") {
t.Errorf("CreateBucket against a regional backend must carry the backend region constraint, got %q", body)
}
if !strings.Contains(body, "<Key>env</Key>") || !strings.Contains(body, "<Value>test</Value>") {
t.Errorf("CreateBucket must keep the requested tags, got %q", body)
}
}