serve s3: fix each server accepting the --auth-key credentials of all the others

gofakes3 kept the keys given with --auth-key in a store global to the process,
so when more than one serve s3 was running in one rclone (eg started via the rc)
each accepted the others' credentials and a client with the key for one server
could read and write the backend of another.

This updates gofakes3 to v0.0.9 which keeps auth keys per instance and adds a
test that two servers only accept their own keys.
This commit is contained in:
Nick Craig-Wood
2026-09-04 19:00:22 +01:00
parent 65735be4da
commit d1e6e2f925
3 changed files with 37 additions and 3 deletions
+34
View File
@@ -8,6 +8,7 @@ import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"path"
"path/filepath"
@@ -15,6 +16,8 @@ import (
"testing"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
_ "github.com/rclone/rclone/backend/local"
@@ -336,6 +339,37 @@ func TestNewServerPerServerAuthProxy(t *testing.T) {
assert.Nil(t, w.provider.VFS(), "expected no fixed VFS when auth proxy is in use")
}
// TestAuthKeyPerServer checks that two servers in the same process
// with different --auth-key pairs only accept their own credentials.
func TestAuthKeyPerServer(t *testing.T) {
fstest.Initialise()
f, err := fs.NewFs(context.Background(), "testdata")
require.NoError(t, err)
urlA, keyA, secA, sA := serveS3(t, f)
defer func() { assert.NoError(t, sA.server.Shutdown()) }()
urlB, keyB, secB, sB := serveS3(t, f)
defer func() { assert.NoError(t, sB.server.Shutdown()) }()
signedGet := func(url, accessKeyID, secret string) int {
req, err := http.NewRequest("GET", url+"/", nil)
require.NoError(t, err)
req.Header.Set("X-Amz-Content-Sha256", "UNSIGNED-PAYLOAD")
err = v4.NewSigner().SignHTTP(context.Background(), aws.Credentials{AccessKeyID: accessKeyID, SecretAccessKey: secret}, req, "UNSIGNED-PAYLOAD", "s3", "us-east-1", time.Now())
require.NoError(t, err)
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err)
_, _ = io.ReadAll(resp.Body)
_ = resp.Body.Close()
return resp.StatusCode
}
assert.Equal(t, http.StatusOK, signedGet(urlA, keyA, secA), "A with A's key")
assert.Equal(t, http.StatusOK, signedGet(urlB, keyB, secB), "B with B's key")
assert.Equal(t, http.StatusForbidden, signedGet(urlA, keyB, secB), "A with B's key")
assert.Equal(t, http.StatusForbidden, signedGet(urlB, keyA, secA), "B with A's key")
}
func TestRc(t *testing.T) {
servetest.TestRc(t, rc.Params{
"type": "s3",
+1 -1
View File
@@ -74,7 +74,7 @@ require (
github.com/quasilyte/go-ruleguard/dsl v0.3.23
github.com/rclone/Proton-API-Bridge v1.0.5
github.com/rclone/go-proton-api v1.0.4
github.com/rclone/gofakes3 v0.0.8
github.com/rclone/gofakes3 v0.0.9
github.com/rfjakob/eme v1.2.0
github.com/rivo/uniseg v0.4.7
github.com/rogpeppe/go-internal v1.15.0
+2 -2
View File
@@ -496,8 +496,8 @@ github.com/rclone/Proton-API-Bridge v1.0.5 h1:K1++Qtk3PvgkiCCiv6Pahju1TMOzKY6VSw
github.com/rclone/Proton-API-Bridge v1.0.5/go.mod h1:vCeOPhlXzevN0AFojgh1zsjhetiShy/ArvJ/xkFUDWk=
github.com/rclone/go-proton-api v1.0.4 h1:AJW0e9pB4j0hVK4WqyGErFwaI+5MUQWPCtj5FYYxtPg=
github.com/rclone/go-proton-api v1.0.4/go.mod h1:QAlkFfswzrBuxvCORWV8rZdddg52hahMN98CFWoFW1E=
github.com/rclone/gofakes3 v0.0.8 h1:UKlrvEEVs/V5zs35n35avpN8zGkei/YsX14gNZr1MlA=
github.com/rclone/gofakes3 v0.0.8/go.mod h1:0udb2hmIO9mHXDAgcdycCzSPPASAGIz410t+m0LKmnE=
github.com/rclone/gofakes3 v0.0.9 h1:1EzeGoSefXmk/DrmmJvJ6B9HR9uUMih4YB2fkQk88Wg=
github.com/rclone/gofakes3 v0.0.9/go.mod h1:0udb2hmIO9mHXDAgcdycCzSPPASAGIz410t+m0LKmnE=
github.com/relvacode/iso8601 v1.7.0 h1:BXy+V60stMP6cpswc+a93Mq3e65PfXCgDFfhvNNGrdo=
github.com/relvacode/iso8601 v1.7.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I=
github.com/rfjakob/eme v1.2.0 h1:8dAHL+WVAw06+7DkRKnRiFp1JL3QjcJEZFqDnndUaSI=