From 2e98902f298a716ebfa10f17efd4c80c81bf08ac Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 3 Apr 2026 11:20:28 -0700 Subject: [PATCH] fix(s3): use URL-safe secret keys for dashboard users and service accounts (#8902) * fix(s3): use URL-safe secret keys for admin dashboard users and service accounts The dashboard's generateSecretKey() used base64.StdEncoding which produces +, /, and = characters that break S3 signature authentication. Reuse the IAM package's GenerateSecretAccessKey() which was already fixed in #7990. Fixes #8898 * fix: handle error from GenerateSecretAccessKey instead of ignoring it --- weed/admin/dash/user_management.go | 13 ++++++++----- weed/admin/dash/user_management_test.go | 13 ++++++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/weed/admin/dash/user_management.go b/weed/admin/dash/user_management.go index 7832e501f..7335d70cb 100644 --- a/weed/admin/dash/user_management.go +++ b/weed/admin/dash/user_management.go @@ -3,13 +3,13 @@ package dash import ( "context" "crypto/rand" - "encoding/base64" "errors" "fmt" "strings" "time" "github.com/seaweedfs/seaweedfs/weed/credential" + "github.com/seaweedfs/seaweedfs/weed/iam" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" ) @@ -435,10 +435,13 @@ func generateAccessKey() string { } func generateSecretKey() string { - // Generate 40-character secret key (AWS standard) - b := make([]byte, 30) // 30 bytes = 40 characters in base64 - rand.Read(b) - return base64.StdEncoding.EncodeToString(b) + // Use the IAM helper to generate URL-safe secret keys (no +, / characters) + // that won't break S3 signature authentication + key, err := iam.GenerateSecretAccessKey() + if err != nil { + panic(fmt.Sprintf("failed to generate secret key: %v", err)) + } + return key } func generateAccountId() string { diff --git a/weed/admin/dash/user_management_test.go b/weed/admin/dash/user_management_test.go index 6e63bfa31..53150c897 100644 --- a/weed/admin/dash/user_management_test.go +++ b/weed/admin/dash/user_management_test.go @@ -74,9 +74,16 @@ func TestGenerateSecretKey(t *testing.T) { key1 := generateSecretKey() key2 := generateSecretKey() - // Check length (base64 encoding of 30 bytes = 40 characters) - if len(key1) != 40 { - t.Errorf("Expected secret key length 40, got %d", len(key1)) + // Check length (IAM standard secret key length) + if len(key1) != 42 { + t.Errorf("Expected secret key length 42, got %d", len(key1)) + } + + // Check that key contains only URL-safe characters (no +, /) + for _, c := range key1 { + if c == '+' || c == '/' || c == '=' { + t.Errorf("Secret key contains non-URL-safe character: %c", c) + } } // Check uniqueness