Browse Source

address comments

pull/7160/head
chrislu 1 month ago
parent
commit
0575d93bca
  1. 16
      .github/workflows/s3-iam-tests.yml
  2. 18
      weed/iam/integration/iam_manager.go
  3. 88
      weed/iam/integration/role_store.go
  4. 28
      weed/iam/policy/policy_engine.go
  5. 79
      weed/iam/policy/policy_store.go
  6. 4
      weed/s3api/s3api_server.go

16
.github/workflows/s3-iam-tests.yml

@ -164,6 +164,14 @@ jobs:
sudo apt-get install -y jq sudo apt-get install -y jq
chmod +x setup_keycloak.sh chmod +x setup_keycloak.sh
./setup_keycloak.sh ./setup_keycloak.sh
# Wait for the test realm to be fully available
echo "Waiting for seaweedfs-test realm to be available..."
timeout 120 bash -c 'until curl -fs http://localhost:8080/realms/seaweedfs-test/.well-known/openid-configuration > /dev/null; do echo "... waiting for realm"; sleep 3; done' || {
echo "❌ seaweedfs-test realm not available"
docker logs keycloak --tail=200 || true
exit 1
}
# Start SeaweedFS services # Start SeaweedFS services
make clean setup start-services wait-for-services make clean setup start-services wait-for-services
@ -299,6 +307,14 @@ jobs:
# Give services extra time to fully initialize # Give services extra time to fully initialize
sleep 10 sleep 10
# Ensure the seaweedfs-test realm is available before running tests
echo "Waiting for seaweedfs-test realm to be available..."
timeout 120 bash -c 'until curl -fs http://localhost:8080/realms/seaweedfs-test/.well-known/openid-configuration > /dev/null; do echo "... waiting for realm"; sleep 3; done' || {
echo "❌ seaweedfs-test realm not available"
docker logs keycloak --tail=200 || true
exit 1
}
# Verify services are accessible # Verify services are accessible
echo "=== Verifying Service Accessibility ===" echo "=== Verifying Service Accessibility ==="

18
weed/iam/integration/iam_manager.go

@ -139,16 +139,16 @@ func (m *IAMManager) RegisterIdentityProvider(provider providers.IdentityProvide
} }
// CreatePolicy creates a new policy // CreatePolicy creates a new policy
func (m *IAMManager) CreatePolicy(ctx context.Context, name string, policyDoc *policy.PolicyDocument) error {
func (m *IAMManager) CreatePolicy(ctx context.Context, filerAddress string, name string, policyDoc *policy.PolicyDocument) error {
if !m.initialized { if !m.initialized {
return fmt.Errorf("IAM manager not initialized") return fmt.Errorf("IAM manager not initialized")
} }
return m.policyEngine.AddPolicy(name, policyDoc)
return m.policyEngine.AddPolicy(filerAddress, name, policyDoc)
} }
// CreateRole creates a new role with trust policy and attached policies // CreateRole creates a new role with trust policy and attached policies
func (m *IAMManager) CreateRole(ctx context.Context, roleName string, roleDef *RoleDefinition) error {
func (m *IAMManager) CreateRole(ctx context.Context, filerAddress string, roleName string, roleDef *RoleDefinition) error {
if !m.initialized { if !m.initialized {
return fmt.Errorf("IAM manager not initialized") return fmt.Errorf("IAM manager not initialized")
} }
@ -174,7 +174,7 @@ func (m *IAMManager) CreateRole(ctx context.Context, roleName string, roleDef *R
} }
// Store role definition // Store role definition
return m.roleStore.StoreRole(ctx, roleName, roleDef)
return m.roleStore.StoreRole(ctx, "", roleName, roleDef)
} }
// AssumeRoleWithWebIdentity assumes a role using web identity (OIDC) // AssumeRoleWithWebIdentity assumes a role using web identity (OIDC)
@ -187,7 +187,7 @@ func (m *IAMManager) AssumeRoleWithWebIdentity(ctx context.Context, request *sts
roleName := extractRoleNameFromArn(request.RoleArn) roleName := extractRoleNameFromArn(request.RoleArn)
// Get role definition // Get role definition
roleDef, err := m.roleStore.GetRole(ctx, roleName)
roleDef, err := m.roleStore.GetRole(ctx, "", roleName)
if err != nil { if err != nil {
return nil, fmt.Errorf("role not found: %s", roleName) return nil, fmt.Errorf("role not found: %s", roleName)
} }
@ -211,7 +211,7 @@ func (m *IAMManager) AssumeRoleWithCredentials(ctx context.Context, request *sts
roleName := extractRoleNameFromArn(request.RoleArn) roleName := extractRoleNameFromArn(request.RoleArn)
// Get role definition // Get role definition
roleDef, err := m.roleStore.GetRole(ctx, roleName)
roleDef, err := m.roleStore.GetRole(ctx, "", roleName)
if err != nil { if err != nil {
return nil, fmt.Errorf("role not found: %s", roleName) return nil, fmt.Errorf("role not found: %s", roleName)
} }
@ -246,7 +246,7 @@ func (m *IAMManager) IsActionAllowed(ctx context.Context, request *ActionRequest
} }
// Get role definition // Get role definition
roleDef, err := m.roleStore.GetRole(ctx, roleName)
roleDef, err := m.roleStore.GetRole(ctx, "", roleName)
if err != nil { if err != nil {
return false, fmt.Errorf("role not found: %s", roleName) return false, fmt.Errorf("role not found: %s", roleName)
} }
@ -260,7 +260,7 @@ func (m *IAMManager) IsActionAllowed(ctx context.Context, request *ActionRequest
} }
// Evaluate policies attached to the role // Evaluate policies attached to the role
result, err := m.policyEngine.Evaluate(ctx, evalCtx, roleDef.AttachedPolicies)
result, err := m.policyEngine.Evaluate(ctx, "", evalCtx, roleDef.AttachedPolicies)
if err != nil { if err != nil {
return false, fmt.Errorf("policy evaluation failed: %w", err) return false, fmt.Errorf("policy evaluation failed: %w", err)
} }
@ -271,7 +271,7 @@ func (m *IAMManager) IsActionAllowed(ctx context.Context, request *ActionRequest
// ValidateTrustPolicy validates if a principal can assume a role (for testing) // ValidateTrustPolicy validates if a principal can assume a role (for testing)
func (m *IAMManager) ValidateTrustPolicy(ctx context.Context, roleArn, provider, userID string) bool { func (m *IAMManager) ValidateTrustPolicy(ctx context.Context, roleArn, provider, userID string) bool {
roleName := extractRoleNameFromArn(roleArn) roleName := extractRoleNameFromArn(roleArn)
roleDef, err := m.roleStore.GetRole(ctx, roleName)
roleDef, err := m.roleStore.GetRole(ctx, "", roleName)
if err != nil { if err != nil {
return false return false
} }

88
weed/iam/integration/role_store.go

@ -17,17 +17,17 @@ import (
// RoleStore defines the interface for storing IAM role definitions // RoleStore defines the interface for storing IAM role definitions
type RoleStore interface { type RoleStore interface {
// StoreRole stores a role definition
StoreRole(ctx context.Context, roleName string, role *RoleDefinition) error
// StoreRole stores a role definition (filerAddress ignored for memory stores)
StoreRole(ctx context.Context, filerAddress string, roleName string, role *RoleDefinition) error
// GetRole retrieves a role definition
GetRole(ctx context.Context, roleName string) (*RoleDefinition, error)
// GetRole retrieves a role definition (filerAddress ignored for memory stores)
GetRole(ctx context.Context, filerAddress string, roleName string) (*RoleDefinition, error)
// ListRoles lists all role names
ListRoles(ctx context.Context) ([]string, error)
// ListRoles lists all role names (filerAddress ignored for memory stores)
ListRoles(ctx context.Context, filerAddress string) ([]string, error)
// DeleteRole deletes a role definition
DeleteRole(ctx context.Context, roleName string) error
// DeleteRole deletes a role definition (filerAddress ignored for memory stores)
DeleteRole(ctx context.Context, filerAddress string, roleName string) error
} }
// MemoryRoleStore implements RoleStore using in-memory storage // MemoryRoleStore implements RoleStore using in-memory storage
@ -43,8 +43,8 @@ func NewMemoryRoleStore() *MemoryRoleStore {
} }
} }
// StoreRole stores a role definition in memory
func (m *MemoryRoleStore) StoreRole(ctx context.Context, roleName string, role *RoleDefinition) error {
// StoreRole stores a role definition in memory (filerAddress ignored for memory store)
func (m *MemoryRoleStore) StoreRole(ctx context.Context, filerAddress string, roleName string, role *RoleDefinition) error {
if roleName == "" { if roleName == "" {
return fmt.Errorf("role name cannot be empty") return fmt.Errorf("role name cannot be empty")
} }
@ -60,8 +60,8 @@ func (m *MemoryRoleStore) StoreRole(ctx context.Context, roleName string, role *
return nil return nil
} }
// GetRole retrieves a role definition from memory
func (m *MemoryRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDefinition, error) {
// GetRole retrieves a role definition from memory (filerAddress ignored for memory store)
func (m *MemoryRoleStore) GetRole(ctx context.Context, filerAddress string, roleName string) (*RoleDefinition, error) {
if roleName == "" { if roleName == "" {
return nil, fmt.Errorf("role name cannot be empty") return nil, fmt.Errorf("role name cannot be empty")
} }
@ -78,8 +78,8 @@ func (m *MemoryRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDe
return copyRoleDefinition(role), nil return copyRoleDefinition(role), nil
} }
// ListRoles lists all role names in memory
func (m *MemoryRoleStore) ListRoles(ctx context.Context) ([]string, error) {
// ListRoles lists all role names in memory (filerAddress ignored for memory store)
func (m *MemoryRoleStore) ListRoles(ctx context.Context, filerAddress string) ([]string, error) {
m.mutex.RLock() m.mutex.RLock()
defer m.mutex.RUnlock() defer m.mutex.RUnlock()
@ -91,8 +91,8 @@ func (m *MemoryRoleStore) ListRoles(ctx context.Context) ([]string, error) {
return names, nil return names, nil
} }
// DeleteRole deletes a role definition from memory
func (m *MemoryRoleStore) DeleteRole(ctx context.Context, roleName string) error {
// DeleteRole deletes a role definition from memory (filerAddress ignored for memory store)
func (m *MemoryRoleStore) DeleteRole(ctx context.Context, filerAddress string, roleName string) error {
if roleName == "" { if roleName == "" {
return fmt.Errorf("role name cannot be empty") return fmt.Errorf("role name cannot be empty")
} }
@ -136,9 +136,8 @@ func copyRoleDefinition(original *RoleDefinition) *RoleDefinition {
// FilerRoleStore implements RoleStore using SeaweedFS filer // FilerRoleStore implements RoleStore using SeaweedFS filer
type FilerRoleStore struct { type FilerRoleStore struct {
filerGrpcAddress string
grpcDialOption grpc.DialOption
basePath string
grpcDialOption grpc.DialOption
basePath string
} }
// NewFilerRoleStore creates a new filer-based role store // NewFilerRoleStore creates a new filer-based role store
@ -147,29 +146,23 @@ func NewFilerRoleStore(config map[string]interface{}) (*FilerRoleStore, error) {
basePath: "/etc/iam/roles", // Default path for role storage - aligned with /etc/ convention basePath: "/etc/iam/roles", // Default path for role storage - aligned with /etc/ convention
} }
// Parse configuration
// Parse configuration - only basePath and other settings, NOT filerAddress
if config != nil { if config != nil {
if filerAddr, ok := config["filerAddress"].(string); ok {
store.filerGrpcAddress = filerAddr
}
if basePath, ok := config["basePath"].(string); ok {
if basePath, ok := config["basePath"].(string); ok && basePath != "" {
store.basePath = strings.TrimSuffix(basePath, "/") store.basePath = strings.TrimSuffix(basePath, "/")
} }
} }
// Validate configuration
if store.filerGrpcAddress == "" {
return nil, fmt.Errorf("filer address is required for FilerRoleStore")
}
glog.V(2).Infof("Initialized FilerRoleStore with filer %s, basePath %s",
store.filerGrpcAddress, store.basePath)
glog.V(2).Infof("Initialized FilerRoleStore with basePath %s", store.basePath)
return store, nil return store, nil
} }
// StoreRole stores a role definition in filer // StoreRole stores a role definition in filer
func (f *FilerRoleStore) StoreRole(ctx context.Context, roleName string, role *RoleDefinition) error {
func (f *FilerRoleStore) StoreRole(ctx context.Context, filerAddress string, roleName string, role *RoleDefinition) error {
if filerAddress == "" {
return fmt.Errorf("filer address is required for FilerRoleStore")
}
if roleName == "" { if roleName == "" {
return fmt.Errorf("role name cannot be empty") return fmt.Errorf("role name cannot be empty")
} }
@ -186,7 +179,7 @@ func (f *FilerRoleStore) StoreRole(ctx context.Context, roleName string, role *R
rolePath := f.getRolePath(roleName) rolePath := f.getRolePath(roleName)
// Store in filer // Store in filer
return f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
return f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.CreateEntryRequest{ request := &filer_pb.CreateEntryRequest{
Directory: f.basePath, Directory: f.basePath,
Entry: &filer_pb.Entry{ Entry: &filer_pb.Entry{
@ -214,13 +207,16 @@ func (f *FilerRoleStore) StoreRole(ctx context.Context, roleName string, role *R
} }
// GetRole retrieves a role definition from filer // GetRole retrieves a role definition from filer
func (f *FilerRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDefinition, error) {
func (f *FilerRoleStore) GetRole(ctx context.Context, filerAddress string, roleName string) (*RoleDefinition, error) {
if filerAddress == "" {
return nil, fmt.Errorf("filer address is required for FilerRoleStore")
}
if roleName == "" { if roleName == "" {
return nil, fmt.Errorf("role name cannot be empty") return nil, fmt.Errorf("role name cannot be empty")
} }
var roleData []byte var roleData []byte
err := f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
err := f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.LookupDirectoryEntryRequest{ request := &filer_pb.LookupDirectoryEntryRequest{
Directory: f.basePath, Directory: f.basePath,
Name: f.getRoleFileName(roleName), Name: f.getRoleFileName(roleName),
@ -254,10 +250,14 @@ func (f *FilerRoleStore) GetRole(ctx context.Context, roleName string) (*RoleDef
} }
// ListRoles lists all role names in filer // ListRoles lists all role names in filer
func (f *FilerRoleStore) ListRoles(ctx context.Context) ([]string, error) {
func (f *FilerRoleStore) ListRoles(ctx context.Context, filerAddress string) ([]string, error) {
if filerAddress == "" {
return nil, fmt.Errorf("filer address is required for FilerRoleStore")
}
var roleNames []string var roleNames []string
err := f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
err := f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.ListEntriesRequest{ request := &filer_pb.ListEntriesRequest{
Directory: f.basePath, Directory: f.basePath,
Prefix: "", Prefix: "",
@ -301,12 +301,15 @@ func (f *FilerRoleStore) ListRoles(ctx context.Context) ([]string, error) {
} }
// DeleteRole deletes a role definition from filer // DeleteRole deletes a role definition from filer
func (f *FilerRoleStore) DeleteRole(ctx context.Context, roleName string) error {
func (f *FilerRoleStore) DeleteRole(ctx context.Context, filerAddress string, roleName string) error {
if filerAddress == "" {
return fmt.Errorf("filer address is required for FilerRoleStore")
}
if roleName == "" { if roleName == "" {
return fmt.Errorf("role name cannot be empty") return fmt.Errorf("role name cannot be empty")
} }
return f.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
return f.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.DeleteEntryRequest{ request := &filer_pb.DeleteEntryRequest{
Directory: f.basePath, Directory: f.basePath,
Name: f.getRoleFileName(roleName), Name: f.getRoleFileName(roleName),
@ -333,6 +336,9 @@ func (f *FilerRoleStore) getRolePath(roleName string) string {
return f.basePath + "/" + f.getRoleFileName(roleName) return f.basePath + "/" + f.getRoleFileName(roleName)
} }
func (f *FilerRoleStore) withFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
return pb.WithGrpcFilerClient(false, 0, pb.ServerAddress(f.filerGrpcAddress), f.grpcDialOption, fn)
func (f *FilerRoleStore) withFilerClient(filerAddress string, fn func(filer_pb.SeaweedFilerClient) error) error {
if filerAddress == "" {
return fmt.Errorf("filer address is required for FilerRoleStore")
}
return pb.WithGrpcFilerClient(false, 0, pb.ServerAddress(filerAddress), f.grpcDialOption, fn)
} }

28
weed/iam/policy/policy_engine.go

@ -139,17 +139,17 @@ type EvaluationDetails struct {
// PolicyStore defines the interface for storing and retrieving policies // PolicyStore defines the interface for storing and retrieving policies
type PolicyStore interface { type PolicyStore interface {
// StorePolicy stores a policy document
StorePolicy(ctx context.Context, name string, policy *PolicyDocument) error
// StorePolicy stores a policy document (filerAddress ignored for memory stores)
StorePolicy(ctx context.Context, filerAddress string, name string, policy *PolicyDocument) error
// GetPolicy retrieves a policy document
GetPolicy(ctx context.Context, name string) (*PolicyDocument, error)
// GetPolicy retrieves a policy document (filerAddress ignored for memory stores)
GetPolicy(ctx context.Context, filerAddress string, name string) (*PolicyDocument, error)
// DeletePolicy deletes a policy document
DeletePolicy(ctx context.Context, name string) error
// DeletePolicy deletes a policy document (filerAddress ignored for memory stores)
DeletePolicy(ctx context.Context, filerAddress string, name string) error
// ListPolicies lists all policy names
ListPolicies(ctx context.Context) ([]string, error)
// ListPolicies lists all policy names (filerAddress ignored for memory stores)
ListPolicies(ctx context.Context, filerAddress string) ([]string, error)
} }
// NewPolicyEngine creates a new policy engine // NewPolicyEngine creates a new policy engine
@ -210,8 +210,8 @@ func (e *PolicyEngine) IsInitialized() bool {
return e.initialized return e.initialized
} }
// AddPolicy adds a policy to the engine
func (e *PolicyEngine) AddPolicy(name string, policy *PolicyDocument) error {
// AddPolicy adds a policy to the engine (filerAddress ignored for memory stores)
func (e *PolicyEngine) AddPolicy(filerAddress string, name string, policy *PolicyDocument) error {
if !e.initialized { if !e.initialized {
return fmt.Errorf("policy engine not initialized") return fmt.Errorf("policy engine not initialized")
} }
@ -228,11 +228,11 @@ func (e *PolicyEngine) AddPolicy(name string, policy *PolicyDocument) error {
return fmt.Errorf("invalid policy document: %w", err) return fmt.Errorf("invalid policy document: %w", err)
} }
return e.store.StorePolicy(context.Background(), name, policy)
return e.store.StorePolicy(context.Background(), filerAddress, name, policy)
} }
// Evaluate evaluates policies against a request context
func (e *PolicyEngine) Evaluate(ctx context.Context, evalCtx *EvaluationContext, policyNames []string) (*EvaluationResult, error) {
// Evaluate evaluates policies against a request context (filerAddress ignored for memory stores)
func (e *PolicyEngine) Evaluate(ctx context.Context, filerAddress string, evalCtx *EvaluationContext, policyNames []string) (*EvaluationResult, error) {
if !e.initialized { if !e.initialized {
return nil, fmt.Errorf("policy engine not initialized") return nil, fmt.Errorf("policy engine not initialized")
} }
@ -257,7 +257,7 @@ func (e *PolicyEngine) Evaluate(ctx context.Context, evalCtx *EvaluationContext,
// Evaluate each policy // Evaluate each policy
for _, policyName := range policyNames { for _, policyName := range policyNames {
policy, err := e.store.GetPolicy(ctx, policyName)
policy, err := e.store.GetPolicy(ctx, filerAddress, policyName)
if err != nil { if err != nil {
continue // Skip policies that can't be loaded continue // Skip policies that can't be loaded
} }

79
weed/iam/policy/policy_store.go

@ -27,8 +27,8 @@ func NewMemoryPolicyStore() *MemoryPolicyStore {
} }
} }
// StorePolicy stores a policy document in memory
func (s *MemoryPolicyStore) StorePolicy(ctx context.Context, name string, policy *PolicyDocument) error {
// StorePolicy stores a policy document in memory (filerAddress ignored for memory store)
func (s *MemoryPolicyStore) StorePolicy(ctx context.Context, filerAddress string, name string, policy *PolicyDocument) error {
if name == "" { if name == "" {
return fmt.Errorf("policy name cannot be empty") return fmt.Errorf("policy name cannot be empty")
} }
@ -45,8 +45,8 @@ func (s *MemoryPolicyStore) StorePolicy(ctx context.Context, name string, policy
return nil return nil
} }
// GetPolicy retrieves a policy document from memory
func (s *MemoryPolicyStore) GetPolicy(ctx context.Context, name string) (*PolicyDocument, error) {
// GetPolicy retrieves a policy document from memory (filerAddress ignored for memory store)
func (s *MemoryPolicyStore) GetPolicy(ctx context.Context, filerAddress string, name string) (*PolicyDocument, error) {
if name == "" { if name == "" {
return nil, fmt.Errorf("policy name cannot be empty") return nil, fmt.Errorf("policy name cannot be empty")
} }
@ -63,8 +63,8 @@ func (s *MemoryPolicyStore) GetPolicy(ctx context.Context, name string) (*Policy
return copyPolicyDocument(policy), nil return copyPolicyDocument(policy), nil
} }
// DeletePolicy deletes a policy document from memory
func (s *MemoryPolicyStore) DeletePolicy(ctx context.Context, name string) error {
// DeletePolicy deletes a policy document from memory (filerAddress ignored for memory store)
func (s *MemoryPolicyStore) DeletePolicy(ctx context.Context, filerAddress string, name string) error {
if name == "" { if name == "" {
return fmt.Errorf("policy name cannot be empty") return fmt.Errorf("policy name cannot be empty")
} }
@ -76,8 +76,8 @@ func (s *MemoryPolicyStore) DeletePolicy(ctx context.Context, name string) error
return nil return nil
} }
// ListPolicies lists all policy names in memory
func (s *MemoryPolicyStore) ListPolicies(ctx context.Context) ([]string, error) {
// ListPolicies lists all policy names in memory (filerAddress ignored for memory store)
func (s *MemoryPolicyStore) ListPolicies(ctx context.Context, filerAddress string) ([]string, error) {
s.mutex.RLock() s.mutex.RLock()
defer s.mutex.RUnlock() defer s.mutex.RUnlock()
@ -148,9 +148,8 @@ func copyPolicyDocument(original *PolicyDocument) *PolicyDocument {
// FilerPolicyStore implements PolicyStore using SeaweedFS filer // FilerPolicyStore implements PolicyStore using SeaweedFS filer
type FilerPolicyStore struct { type FilerPolicyStore struct {
filerGrpcAddress string
grpcDialOption grpc.DialOption
basePath string
grpcDialOption grpc.DialOption
basePath string
} }
// NewFilerPolicyStore creates a new filer-based policy store // NewFilerPolicyStore creates a new filer-based policy store
@ -159,29 +158,23 @@ func NewFilerPolicyStore(config map[string]interface{}) (*FilerPolicyStore, erro
basePath: "/etc/iam/policies", // Default path for policy storage - aligned with /etc/ convention basePath: "/etc/iam/policies", // Default path for policy storage - aligned with /etc/ convention
} }
// Parse configuration
// Parse configuration - only basePath and other settings, NOT filerAddress
if config != nil { if config != nil {
if filerAddr, ok := config["filerAddress"].(string); ok {
store.filerGrpcAddress = filerAddr
}
if basePath, ok := config["basePath"].(string); ok {
if basePath, ok := config["basePath"].(string); ok && basePath != "" {
store.basePath = strings.TrimSuffix(basePath, "/") store.basePath = strings.TrimSuffix(basePath, "/")
} }
} }
// Validate configuration
if store.filerGrpcAddress == "" {
return nil, fmt.Errorf("filer address is required for FilerPolicyStore")
}
glog.V(2).Infof("Initialized FilerPolicyStore with filer %s, basePath %s",
store.filerGrpcAddress, store.basePath)
glog.V(2).Infof("Initialized FilerPolicyStore with basePath %s", store.basePath)
return store, nil return store, nil
} }
// StorePolicy stores a policy document in filer // StorePolicy stores a policy document in filer
func (s *FilerPolicyStore) StorePolicy(ctx context.Context, name string, policy *PolicyDocument) error {
func (s *FilerPolicyStore) StorePolicy(ctx context.Context, filerAddress string, name string, policy *PolicyDocument) error {
if filerAddress == "" {
return fmt.Errorf("filer address is required for FilerPolicyStore")
}
if name == "" { if name == "" {
return fmt.Errorf("policy name cannot be empty") return fmt.Errorf("policy name cannot be empty")
} }
@ -198,7 +191,7 @@ func (s *FilerPolicyStore) StorePolicy(ctx context.Context, name string, policy
policyPath := s.getPolicyPath(name) policyPath := s.getPolicyPath(name)
// Store in filer // Store in filer
return s.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
return s.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.CreateEntryRequest{ request := &filer_pb.CreateEntryRequest{
Directory: s.basePath, Directory: s.basePath,
Entry: &filer_pb.Entry{ Entry: &filer_pb.Entry{
@ -226,13 +219,16 @@ func (s *FilerPolicyStore) StorePolicy(ctx context.Context, name string, policy
} }
// GetPolicy retrieves a policy document from filer // GetPolicy retrieves a policy document from filer
func (s *FilerPolicyStore) GetPolicy(ctx context.Context, name string) (*PolicyDocument, error) {
func (s *FilerPolicyStore) GetPolicy(ctx context.Context, filerAddress string, name string) (*PolicyDocument, error) {
if filerAddress == "" {
return nil, fmt.Errorf("filer address is required for FilerPolicyStore")
}
if name == "" { if name == "" {
return nil, fmt.Errorf("policy name cannot be empty") return nil, fmt.Errorf("policy name cannot be empty")
} }
var policyData []byte var policyData []byte
err := s.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
err := s.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.LookupDirectoryEntryRequest{ request := &filer_pb.LookupDirectoryEntryRequest{
Directory: s.basePath, Directory: s.basePath,
Name: s.getPolicyFileName(name), Name: s.getPolicyFileName(name),
@ -266,12 +262,15 @@ func (s *FilerPolicyStore) GetPolicy(ctx context.Context, name string) (*PolicyD
} }
// DeletePolicy deletes a policy document from filer // DeletePolicy deletes a policy document from filer
func (s *FilerPolicyStore) DeletePolicy(ctx context.Context, name string) error {
func (s *FilerPolicyStore) DeletePolicy(ctx context.Context, filerAddress string, name string) error {
if filerAddress == "" {
return fmt.Errorf("filer address is required for FilerPolicyStore")
}
if name == "" { if name == "" {
return fmt.Errorf("policy name cannot be empty") return fmt.Errorf("policy name cannot be empty")
} }
return s.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
return s.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.DeleteEntryRequest{ request := &filer_pb.DeleteEntryRequest{
Directory: s.basePath, Directory: s.basePath,
Name: s.getPolicyFileName(name), Name: s.getPolicyFileName(name),
@ -304,10 +303,14 @@ func (s *FilerPolicyStore) DeletePolicy(ctx context.Context, name string) error
} }
// ListPolicies lists all policy names in filer // ListPolicies lists all policy names in filer
func (s *FilerPolicyStore) ListPolicies(ctx context.Context) ([]string, error) {
func (s *FilerPolicyStore) ListPolicies(ctx context.Context, filerAddress string) ([]string, error) {
if filerAddress == "" {
return nil, fmt.Errorf("filer address is required for FilerPolicyStore")
}
var policyNames []string var policyNames []string
err := s.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
err := s.withFilerClient(filerAddress, func(client filer_pb.SeaweedFilerClient) error {
// List all entries in the policy directory // List all entries in the policy directory
request := &filer_pb.ListEntriesRequest{ request := &filer_pb.ListEntriesRequest{
Directory: s.basePath, Directory: s.basePath,
@ -353,20 +356,14 @@ func (s *FilerPolicyStore) ListPolicies(ctx context.Context) ([]string, error) {
// Helper methods // Helper methods
// SetFilerClient sets the filer client connection details
func (s *FilerPolicyStore) SetFilerClient(filerAddress string, grpcDialOption grpc.DialOption) {
s.filerGrpcAddress = filerAddress
s.grpcDialOption = grpcDialOption
}
// withFilerClient executes a function with a filer client // withFilerClient executes a function with a filer client
func (s *FilerPolicyStore) withFilerClient(fn func(client filer_pb.SeaweedFilerClient) error) error {
if s.filerGrpcAddress == "" {
return fmt.Errorf("filer address not configured")
func (s *FilerPolicyStore) withFilerClient(filerAddress string, fn func(client filer_pb.SeaweedFilerClient) error) error {
if filerAddress == "" {
return fmt.Errorf("filer address is required for FilerPolicyStore")
} }
// Use the pb.WithGrpcFilerClient helper similar to existing SeaweedFS code // Use the pb.WithGrpcFilerClient helper similar to existing SeaweedFS code
return pb.WithGrpcFilerClient(false, 0, pb.ServerAddress(s.filerGrpcAddress), s.grpcDialOption, fn)
return pb.WithGrpcFilerClient(false, 0, pb.ServerAddress(filerAddress), s.grpcDialOption, fn)
} }
// getPolicyPath returns the full path for a policy // getPolicyPath returns the full path for a policy

4
weed/s3api/s3api_server.go

@ -474,14 +474,14 @@ func loadIAMManagerFromConfig(configPath string) (*integration.IAMManager, error
// Load policies // Load policies
for _, policyDef := range configRoot.Policies { for _, policyDef := range configRoot.Policies {
if err := iamManager.CreatePolicy(context.Background(), policyDef.Name, policyDef.Document); err != nil {
if err := iamManager.CreatePolicy(context.Background(), "", policyDef.Name, policyDef.Document); err != nil {
glog.Warningf("Failed to create policy %s: %v", policyDef.Name, err) glog.Warningf("Failed to create policy %s: %v", policyDef.Name, err)
} }
} }
// Load roles // Load roles
for _, roleDef := range configRoot.Roles { for _, roleDef := range configRoot.Roles {
if err := iamManager.CreateRole(context.Background(), roleDef.RoleName, roleDef); err != nil {
if err := iamManager.CreateRole(context.Background(), "", roleDef.RoleName, roleDef); err != nil {
glog.Warningf("Failed to create role %s: %v", roleDef.RoleName, err) glog.Warningf("Failed to create role %s: %v", roleDef.RoleName, err)
} }
} }

Loading…
Cancel
Save