From 1ea6b0c0d9a572a7e1355794b893e1bb20ae4d1a Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Thu, 8 Jan 2026 20:35:37 -0800 Subject: [PATCH] cleanup: deduplicate environment variable credential loading Previously, `weed mini` logic duplicated the credential loading process by creating a temporary IAM config file from environment variables. `auth_credentials.go` also had fallback logic to load these variables. This change: 1. Updates `auth_credentials.go` to *always* check for and merge AWS environment variable credentials (`AWS_ACCESS_KEY_ID`, etc.) into the identity list. This ensures they are available regardless of whether other configurations (static file or filer) are loaded. 2. Removes the redundant file creation logic from `weed/command/mini.go`. 3. Updates `weed mini` user messages to accurately reflect that credentials are loaded from environment variables in-memory. This results in a cleaner implementation where `weed/s3api` manages all credential loading logic, and `weed mini` simply relies on it. --- weed/command/mini.go | 38 +---------- weed/s3api/auth_credentials.go | 114 ++++++++++++++++++++++----------- 2 files changed, 77 insertions(+), 75 deletions(-) diff --git a/weed/command/mini.go b/weed/command/mini.go index e12cab35e..000c4921a 100644 --- a/weed/command/mini.go +++ b/weed/command/mini.go @@ -11,10 +11,8 @@ import ( "strings" "time" - "github.com/seaweedfs/seaweedfs/weed/filer" "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/pb" - iam_pb "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" "github.com/seaweedfs/seaweedfs/weed/security" stats_collect "github.com/seaweedfs/seaweedfs/weed/stats" "github.com/seaweedfs/seaweedfs/weed/util" @@ -916,37 +914,7 @@ func startS3Service() { secretKey := os.Getenv("AWS_SECRET_ACCESS_KEY") if accessKey != "" && secretKey != "" { - user := "mini" - iamCfg := &iam_pb.S3ApiConfiguration{} - ident := &iam_pb.Identity{Name: user} - ident.Credentials = append(ident.Credentials, &iam_pb.Credential{AccessKey: accessKey, SecretKey: secretKey}) - ident.Actions = append(ident.Actions, "Admin") - iamCfg.Identities = append(iamCfg.Identities, ident) - - iamPath := filepath.Join(*miniDataFolders, "iam_config.json") - - // Check if IAM config file already exists - if _, err := os.Stat(iamPath); err == nil { - // File exists, skip writing to preserve existing configuration - glog.V(1).Infof("IAM config file already exists at %s, preserving existing configuration", iamPath) - *miniIamConfig = iamPath - } else if os.IsNotExist(err) { - // File does not exist, create and write new configuration - f, err := os.OpenFile(iamPath, os.O_CREATE|os.O_WRONLY, 0600) - if err != nil { - glog.Fatalf("failed to create IAM config file %s: %v", iamPath, err) - } - defer f.Close() - if err := filer.ProtoToText(f, iamCfg); err != nil { - glog.Fatalf("failed to write IAM config to %s: %v", iamPath, err) - } - *miniIamConfig = iamPath - createdInitialIAM = true // Mark that we created initial IAM config - glog.V(1).Infof("Created initial IAM config at %s", iamPath) - } else { - // Error checking file existence - glog.Fatalf("failed to check IAM config file existence at %s: %v", iamPath, err) - } + createdInitialIAM = true } miniS3Options.localFilerSocket = miniFilerOptions.localSocket @@ -1153,9 +1121,7 @@ const credentialsInstructionTemplate = ` ` const credentialsCreatedMessage = ` - Initial S3 credentials created: - user: mini - Note: credentials have been written to the IAM configuration file. + Initial S3 credentials loaded from environment variables. ` // printWelcomeMessage prints the welcome message after all services are running diff --git a/weed/s3api/auth_credentials.go b/weed/s3api/auth_credentials.go index 8647d032c..ba9560d0a 100644 --- a/weed/s3api/auth_credentials.go +++ b/weed/s3api/auth_credentials.go @@ -160,9 +160,6 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, explicitSto iam.credentialManager = credentialManager - // Track whether any configuration was successfully loaded - configLoaded := false - // First, try to load configurations from file or filer // First, try to load configurations from file or filer startConfigFile := option.Config @@ -184,7 +181,6 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, explicitSto for _, identity := range iam.identities { iam.staticIdentityNames[identity.Name] = true } - configLoaded = len(iam.identities) > 0 iam.m.Unlock() } @@ -197,51 +193,91 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, explicitSto // Only consider config loaded if we actually have identities // Don't block environment variable fallback just because filer call succeeded - iam.m.RLock() - configLoaded = len(iam.identities) > 0 - iam.m.RUnlock() + // iam.m.RLock() + // configLoaded = len(iam.identities) > 0 + // iam.m.RUnlock() + + // Check for AWS environment variables and merge them if present + // This serves as an in-memory "static" configuration + accessKeyId := os.Getenv("AWS_ACCESS_KEY_ID") + secretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY") + + if accessKeyId != "" && secretAccessKey != "" { + // Create environment variable identity name + identityNameSuffix := accessKeyId + if len(accessKeyId) > 8 { + identityNameSuffix = accessKeyId[:8] + } + identityName := "admin-" + identityNameSuffix + + // Create admin identity with environment variable credentials + envIdentity := &Identity{ + Name: identityName, + Account: &AccountAdmin, + Credentials: []*Credential{ + { + AccessKey: accessKeyId, + SecretKey: secretAccessKey, + }, + }, + Actions: []Action{ + s3_constants.ACTION_ADMIN, + }, + } - // Only use environment variables as fallback if no configuration was loaded - if !configLoaded { - accessKeyId := os.Getenv("AWS_ACCESS_KEY_ID") - secretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY") + iam.m.Lock() - if accessKeyId != "" && secretAccessKey != "" { - glog.V(1).Infof("No S3 configuration found, using AWS environment variables as fallback") + // Initialize maps if they are nil (if no config loaded yet) + if iam.staticIdentityNames == nil { + iam.staticIdentityNames = make(map[string]bool) + } - // Create environment variable identity name - identityNameSuffix := accessKeyId - if len(accessKeyId) > 8 { - identityNameSuffix = accessKeyId[:8] + // Check if identity already exists (avoid duplicates) + exists := false + for _, ident := range iam.identities { + if ident.Name == identityName { + exists = true + break } + } - // Create admin identity with environment variable credentials - envIdentity := &Identity{ - Name: "admin-" + identityNameSuffix, - Account: &AccountAdmin, - Credentials: []*Credential{ - { - AccessKey: accessKeyId, - SecretKey: secretAccessKey, - }, - }, - Actions: []Action{ - s3_constants.ACTION_ADMIN, - }, + if !exists { + glog.V(1).Infof("Added admin identity from AWS environment variables: %s", envIdentity.Name) + + // Add to identities list + iam.identities = append(iam.identities, envIdentity) + + // Update credential mappings + if iam.accessKeyIdent == nil { + iam.accessKeyIdent = make(map[string]*Identity) } + iam.accessKeyIdent[accessKeyId] = envIdentity - // Set as the only configuration - iam.m.Lock() - if len(iam.identities) == 0 { - iam.identities = []*Identity{envIdentity} - iam.accessKeyIdent = map[string]*Identity{accessKeyId: envIdentity} - iam.nameToIdentity = map[string]*Identity{envIdentity.Name: envIdentity} - iam.isAuthEnabled = true + if iam.nameToIdentity == nil { + iam.nameToIdentity = make(map[string]*Identity) } - iam.m.Unlock() + iam.nameToIdentity[envIdentity.Name] = envIdentity - glog.V(1).Infof("Added admin identity from AWS environment variables: %s", envIdentity.Name) + // Treat env var identity as static (immutable) + iam.staticIdentityNames[envIdentity.Name] = true + + // Ensure defaults exist if this is the first identity + if iam.accounts == nil { + iam.accounts = make(map[string]*Account) + iam.accounts[AccountAdmin.Id] = &AccountAdmin + iam.accounts[AccountAnonymous.Id] = &AccountAnonymous + } + if iam.emailAccount == nil { + iam.emailAccount = make(map[string]*Account) + iam.emailAccount[AccountAdmin.EmailAddress] = &AccountAdmin + iam.emailAccount[AccountAnonymous.EmailAddress] = &AccountAnonymous + } + + // Enable auth if we have identities + iam.isAuthEnabled = true } + + iam.m.Unlock() } return iam