From 46d09fd52e703732ac499da43e7ef2e41fc73a76 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 12 Aug 2026 11:55:17 +0100 Subject: [PATCH] serve s3: fix misleading anonymous access log and add test for auth proxy via rc GHSA-p569-5gjg-9cmj CVE-PENDING From v1.70.0 until the serve Provider refactor (f425f8d46), an S3 server started through the rc serve/start API with a per-server proxyOpt.AuthProxy decided whether to enable proxy authentication by checking the process-global proxy.Opt.AuthProxy instead of the supplied proxyOpt.AuthProxy. In the normal rc case the global is empty, so the auth proxy was silently ignored and the server served the fixed filesystem supplied to serve/start rather than routing each access key to the backend chosen by the proxy, bypassing the operator's intended per-key authorization. The Provider refactor fixed this incidentally by building the provider from the proxyOpt passed to the constructor. This adds a regression test so the per-server option cannot silently stop working again, and only logs "allowing anonymous access" when neither an auth key nor an auth proxy is configured so the log reflects the effective mode. --- cmd/serve/s3/s3_test.go | 28 ++++++++++++++++++++++++++++ cmd/serve/s3/server.go | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cmd/serve/s3/s3_test.go b/cmd/serve/s3/s3_test.go index 2baf487f3..1eea39916 100644 --- a/cmd/serve/s3/s3_test.go +++ b/cmd/serve/s3/s3_test.go @@ -308,6 +308,34 @@ func TestListBucketsAuthProxy(t *testing.T) { testListBuckets(t, cases, true) } +// TestNewServerPerServerAuthProxy checks that a per-server proxyOpt.AuthProxy +// enables proxy mode even when the process-global proxy.Opt.AuthProxy is empty, +// which is the normal case when the server is configured via serve/start. +func TestNewServerPerServerAuthProxy(t *testing.T) { + fstest.Initialise() + + // Ensure the global is empty so we only test the per-server option. + assert.Equal(t, "", proxy.Opt.AuthProxy) + + f, err := fs.NewFs(context.Background(), "testdata") + require.NoError(t, err) + + opt := Opt + opt.AuthKey = []string{"access-key,secret-key"} + opt.HTTP.ListenAddr = []string{endpoint} + + proxyOpt := proxy.Opt + proxyOpt.AuthProxy = "/path/to/auth/proxy" + + w, err := newServer(context.Background(), f, &opt, &vfscommon.Opt, &proxyOpt) + require.NoError(t, err) + defer func() { + assert.NoError(t, w.Shutdown()) + }() + assert.True(t, w.provider.IsProxy(), "expected auth proxy to be enabled by per-server option") + assert.Nil(t, w.provider.VFS(), "expected no fixed VFS when auth proxy is in use") +} + func TestRc(t *testing.T) { servetest.TestRc(t, rc.Params{ "type": "s3", diff --git a/cmd/serve/s3/server.go b/cmd/serve/s3/server.go index d7935e41d..6b5a58f74 100644 --- a/cmd/serve/s3/server.go +++ b/cmd/serve/s3/server.go @@ -74,9 +74,9 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options, vfsOpt *vfscommon.Opt fs.Debugf(f, "Using hash %v for ETag", w.etagHashType) } - if len(opt.AuthKey) == 0 { + if len(opt.AuthKey) == 0 && !w.provider.IsProxy() { fs.Logf("serve s3", "No auth provided so allowing anonymous access") - } else { + } else if len(opt.AuthKey) > 0 { w.s3Secret = getAuthSecret(opt.AuthKey) }