mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2025-08-20 04:46:42 +08:00
S3 API: simpler way to start s3 with credentials (#7030)
* simpler way to start s3 with credentials * AWS_ACCESS_KEY_ID=access_key AWS_SECRET_ACCESS_KEY=secret_key weed s3 * last adding credentials from env variables * Update weed/s3api/auth_credentials.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * simplify * adjust doc --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
parent
d5085cd1f7
commit
e3d3c495ab
@ -160,6 +160,14 @@ var cmdS3 = &Command{
|
||||
]
|
||||
}
|
||||
|
||||
Alternatively, you can use environment variables to supplement admin credentials:
|
||||
|
||||
AWS_ACCESS_KEY_ID=your_access_key AWS_SECRET_ACCESS_KEY=your_secret_key weed s3
|
||||
|
||||
This will add admin credentials from environment variables to any existing
|
||||
configuration. Environment variables are added after loading file/filer
|
||||
configurations and are skipped if the same access key already exists.
|
||||
|
||||
`,
|
||||
}
|
||||
|
||||
|
@ -85,22 +85,6 @@ type Credential struct {
|
||||
SecretKey string
|
||||
}
|
||||
|
||||
func (i *Identity) isAnonymous() bool {
|
||||
return i.Account.Id == s3_constants.AccountAnonymousId
|
||||
}
|
||||
|
||||
func (action Action) isAdmin() bool {
|
||||
return strings.HasPrefix(string(action), s3_constants.ACTION_ADMIN)
|
||||
}
|
||||
|
||||
func (action Action) isOwner(bucket string) bool {
|
||||
return string(action) == s3_constants.ACTION_ADMIN+":"+bucket
|
||||
}
|
||||
|
||||
func (action Action) overBucket(bucket string) bool {
|
||||
return strings.HasSuffix(string(action), ":"+bucket) || strings.HasSuffix(string(action), ":*")
|
||||
}
|
||||
|
||||
// "Permission": "FULL_CONTROL"|"WRITE"|"WRITE_ACP"|"READ"|"READ_ACP"
|
||||
func (action Action) getPermission() Permission {
|
||||
switch act := strings.Split(string(action), ":")[0]; act {
|
||||
@ -147,6 +131,7 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, explicitSto
|
||||
|
||||
iam.credentialManager = credentialManager
|
||||
|
||||
// First, load configurations from file or filer
|
||||
if option.Config != "" {
|
||||
glog.V(3).Infof("loading static config file %s", option.Config)
|
||||
if err := iam.loadS3ApiConfigurationFromFile(option.Config); err != nil {
|
||||
@ -158,6 +143,57 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, explicitSto
|
||||
glog.Warningf("fail to load config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Then, add admin credentials from environment variables if available
|
||||
// This supplements the configuration by adding admin credentials from environment variables if they don't already exist.
|
||||
accessKeyId := os.Getenv("AWS_ACCESS_KEY_ID")
|
||||
secretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY")
|
||||
|
||||
if accessKeyId != "" && secretAccessKey != "" {
|
||||
glog.V(0).Infof("Adding S3 admin credentials from AWS environment variables")
|
||||
|
||||
// Check if an identity with this access key already exists
|
||||
iam.m.RLock()
|
||||
_, accessKeyExists := iam.accessKeyIdent[accessKeyId]
|
||||
iam.m.RUnlock()
|
||||
|
||||
if !accessKeyExists {
|
||||
// Create environment variable identity name
|
||||
identityNameSuffix := accessKeyId
|
||||
if len(accessKeyId) > 8 {
|
||||
identityNameSuffix = accessKeyId[:8]
|
||||
}
|
||||
|
||||
// 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,
|
||||
},
|
||||
}
|
||||
|
||||
// Add to existing configuration
|
||||
iam.m.Lock()
|
||||
iam.identities = append(iam.identities, envIdentity)
|
||||
iam.accessKeyIdent[accessKeyId] = envIdentity
|
||||
if !iam.isAuthEnabled {
|
||||
iam.isAuthEnabled = true
|
||||
}
|
||||
iam.m.Unlock()
|
||||
|
||||
glog.V(0).Infof("Added admin identity from AWS environment variables: %s", envIdentity.Name)
|
||||
} else {
|
||||
glog.V(0).Infof("Access key %s already exists, skipping environment variable credentials", accessKeyId)
|
||||
}
|
||||
}
|
||||
|
||||
return iam
|
||||
}
|
||||
|
||||
@ -538,9 +574,5 @@ func (iam *IdentityAccessManagement) LoadS3ApiConfigurationFromCredentialManager
|
||||
return fmt.Errorf("failed to load configuration from credential manager: %w", err)
|
||||
}
|
||||
|
||||
if len(s3ApiConfiguration.Identities) == 0 {
|
||||
return fmt.Errorf("no identities found")
|
||||
}
|
||||
|
||||
return iam.loadS3ApiConfiguration(s3ApiConfiguration)
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/credential"
|
||||
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@ -264,3 +266,94 @@ func TestLoadS3ApiConfiguration(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewIdentityAccessManagementWithStoreEnvVars(t *testing.T) {
|
||||
// Save original environment
|
||||
originalAccessKeyId := os.Getenv("AWS_ACCESS_KEY_ID")
|
||||
originalSecretAccessKey := os.Getenv("AWS_SECRET_ACCESS_KEY")
|
||||
|
||||
// Clean up after test
|
||||
defer func() {
|
||||
if originalAccessKeyId != "" {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", originalAccessKeyId)
|
||||
} else {
|
||||
os.Unsetenv("AWS_ACCESS_KEY_ID")
|
||||
}
|
||||
if originalSecretAccessKey != "" {
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", originalSecretAccessKey)
|
||||
} else {
|
||||
os.Unsetenv("AWS_SECRET_ACCESS_KEY")
|
||||
}
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
accessKeyId string
|
||||
secretAccessKey string
|
||||
expectEnvIdentity bool
|
||||
expectedName string
|
||||
}{
|
||||
{
|
||||
name: "Both env vars set",
|
||||
accessKeyId: "AKIA1234567890ABCDEF",
|
||||
secretAccessKey: "secret123456789012345678901234567890abcdef12",
|
||||
expectEnvIdentity: true,
|
||||
expectedName: "admin-AKIA1234",
|
||||
},
|
||||
{
|
||||
name: "Short access key",
|
||||
accessKeyId: "SHORT",
|
||||
secretAccessKey: "secret123456789012345678901234567890abcdef12",
|
||||
expectEnvIdentity: true,
|
||||
expectedName: "admin-SHORT",
|
||||
},
|
||||
{
|
||||
name: "No env vars set",
|
||||
accessKeyId: "",
|
||||
secretAccessKey: "",
|
||||
expectEnvIdentity: false,
|
||||
expectedName: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Set up environment variables
|
||||
if tt.accessKeyId != "" {
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", tt.accessKeyId)
|
||||
} else {
|
||||
os.Unsetenv("AWS_ACCESS_KEY_ID")
|
||||
}
|
||||
if tt.secretAccessKey != "" {
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", tt.secretAccessKey)
|
||||
} else {
|
||||
os.Unsetenv("AWS_SECRET_ACCESS_KEY")
|
||||
}
|
||||
|
||||
// Create IAM instance with memory store for testing
|
||||
option := &S3ApiServerOption{
|
||||
Config: "", // No config file, should use environment variables
|
||||
}
|
||||
iam := NewIdentityAccessManagementWithStore(option, string(credential.StoreTypeMemory))
|
||||
|
||||
if tt.expectEnvIdentity {
|
||||
// Check that environment variable identity was created
|
||||
found := false
|
||||
for _, identity := range iam.identities {
|
||||
if identity.Name == tt.expectedName {
|
||||
found = true
|
||||
assert.Len(t, identity.Credentials, 1, "Should have one credential")
|
||||
assert.Equal(t, tt.accessKeyId, identity.Credentials[0].AccessKey, "Access key should match environment variable")
|
||||
assert.Equal(t, tt.secretAccessKey, identity.Credentials[0].SecretKey, "Secret key should match environment variable")
|
||||
assert.Contains(t, identity.Actions, Action(ACTION_ADMIN), "Should have admin action")
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, found, "Should find identity created from environment variables")
|
||||
} else {
|
||||
// When no env vars, should have no identities (since no config file)
|
||||
assert.Len(t, iam.identities, 0, "Should have no identities when no env vars and no config file")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user