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
This commit is contained in:
Chris Lu
2026-04-03 11:20:28 -07:00
committed by GitHub
parent d3cea714d0
commit 2e98902f29
2 changed files with 18 additions and 8 deletions

View File

@@ -3,13 +3,13 @@ package dash
import ( import (
"context" "context"
"crypto/rand" "crypto/rand"
"encoding/base64"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"time" "time"
"github.com/seaweedfs/seaweedfs/weed/credential" "github.com/seaweedfs/seaweedfs/weed/credential"
"github.com/seaweedfs/seaweedfs/weed/iam"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
) )
@@ -435,10 +435,13 @@ func generateAccessKey() string {
} }
func generateSecretKey() string { func generateSecretKey() string {
// Generate 40-character secret key (AWS standard) // Use the IAM helper to generate URL-safe secret keys (no +, / characters)
b := make([]byte, 30) // 30 bytes = 40 characters in base64 // that won't break S3 signature authentication
rand.Read(b) key, err := iam.GenerateSecretAccessKey()
return base64.StdEncoding.EncodeToString(b) if err != nil {
panic(fmt.Sprintf("failed to generate secret key: %v", err))
}
return key
} }
func generateAccountId() string { func generateAccountId() string {

View File

@@ -74,9 +74,16 @@ func TestGenerateSecretKey(t *testing.T) {
key1 := generateSecretKey() key1 := generateSecretKey()
key2 := generateSecretKey() key2 := generateSecretKey()
// Check length (base64 encoding of 30 bytes = 40 characters) // Check length (IAM standard secret key length)
if len(key1) != 40 { if len(key1) != 42 {
t.Errorf("Expected secret key length 40, got %d", len(key1)) 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 // Check uniqueness