mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-11 17:10:40 +02:00
* remote_storage: build S3-compatible clients through one constructor The eight non-s3 S3-SDK providers each duplicated the AWS session setup and only the s3 maker could take a custom *http.Client. Route every S3-compatible type (s3, wasabi, b2, aliyun, tencent, baidu, filebase, storj, contabo) through MakeWithHTTPClient with a single options table, and add S3CompatibleEndpoint so callers can resolve the endpoint a given type dials. No behavior change. * volume: apply the remote-endpoint check to all S3-compatible providers FetchAndWriteNeedle validated the endpoint and used the pinned dialer only for type "s3". Every S3-SDK backend (wasabi, b2, aliyun, tencent, baidu, filebase, storj, contabo) dials a caller-supplied endpoint through the same client, so gate on S3CompatibleEndpoint to apply the same check uniformly. -volume.allowUntrustedRemoteEndpoints still opts out. * volume: don't route the guarded remote-endpoint client through a proxy The guarded client exists to dial the validated endpoint directly and re-check the resolved IP at connect time. With http.ProxyFromEnvironment set, the dialer only validates the proxy's address while the proxy re-resolves the endpoint host, which reopens the rebinding window. Drop the proxy on this path; operators that need one can opt out with -volume.allowUntrustedRemoteEndpoints.
45 lines
2.0 KiB
Go
45 lines
2.0 KiB
Go
package s3
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/remote_pb"
|
|
)
|
|
|
|
// TestS3CompatibleEndpointCoversAllProviders locks the type-to-endpoint mapping
|
|
// the volume server's SSRF guard relies on. Every S3-SDK-backed provider dials
|
|
// a caller-supplied endpoint, so each must surface it here; a new sibling that
|
|
// forgets to would silently bypass the guard.
|
|
func TestS3CompatibleEndpointCoversAllProviders(t *testing.T) {
|
|
cases := []struct {
|
|
conf *remote_pb.RemoteConf
|
|
want string
|
|
}{
|
|
{&remote_pb.RemoteConf{Type: "s3", S3Endpoint: "http://s3.internal"}, "http://s3.internal"},
|
|
{&remote_pb.RemoteConf{Type: "wasabi", WasabiEndpoint: "http://wasabi.internal"}, "http://wasabi.internal"},
|
|
{&remote_pb.RemoteConf{Type: "b2", BackblazeEndpoint: "http://b2.internal"}, "http://b2.internal"},
|
|
{&remote_pb.RemoteConf{Type: "aliyun", AliyunEndpoint: "http://aliyun.internal"}, "http://aliyun.internal"},
|
|
{&remote_pb.RemoteConf{Type: "tencent", TencentEndpoint: "http://tencent.internal"}, "http://tencent.internal"},
|
|
{&remote_pb.RemoteConf{Type: "baidu", BaiduEndpoint: "http://baidu.internal"}, "http://baidu.internal"},
|
|
{&remote_pb.RemoteConf{Type: "filebase", FilebaseEndpoint: "http://filebase.internal"}, "http://filebase.internal"},
|
|
{&remote_pb.RemoteConf{Type: "storj", StorjEndpoint: "http://storj.internal"}, "http://storj.internal"},
|
|
{&remote_pb.RemoteConf{Type: "contabo", ContaboEndpoint: "http://contabo.internal"}, "http://contabo.internal"},
|
|
}
|
|
for _, tc := range cases {
|
|
endpoint, ok := S3CompatibleEndpoint(tc.conf)
|
|
if !ok {
|
|
t.Errorf("type %q: expected an S3-compatible endpoint, got ok=false", tc.conf.Type)
|
|
continue
|
|
}
|
|
if endpoint != tc.want {
|
|
t.Errorf("type %q: endpoint = %q, want %q", tc.conf.Type, endpoint, tc.want)
|
|
}
|
|
}
|
|
|
|
// Every registered maker must be an S3-compatible type; the guard treats
|
|
// anything else (gcs, azure, ...) as not dialing a caller-supplied URL.
|
|
if _, ok := S3CompatibleEndpoint(&remote_pb.RemoteConf{Type: "gcs"}); ok {
|
|
t.Error("gcs must not be reported as an S3-compatible endpoint")
|
|
}
|
|
}
|