* s3api: honor attached IAM policies over legacy actions * s3api: hydrate IAM policy docs during config reload * s3api: use policy-aware auth when listing buckets * credential: propagate context through filer_etc policy reads * credential: make legacy policy deletes durable * s3api: exercise managed policy runtime loader * s3api: allow static IAM users without session tokens * iam: deny unmatched attached policies under default allow * iam: load embedded policy files from filer store * s3api: require session tokens for IAM presigning * s3api: sync runtime policies into zero-config IAM * credential: respect context in policy file loads * credential: serialize legacy policy deletes * iam: align filer policy store naming * s3api: use authenticated principals for presigning * iam: deep copy policy conditions * s3api: require request creation in policy tests * filer: keep ReadInsideFiler as the context-aware API * iam: harden filer policy store writes * credential: strengthen legacy policy serialization test * credential: forward runtime policy loaders through wrapper * s3api: harden runtime policy merging * iam: require typed already-exists errors
80 lines
2.6 KiB
Go
80 lines
2.6 KiB
Go
package filer_etc
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/credential"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
func init() {
|
|
credential.Stores = append(credential.Stores, &FilerEtcStore{})
|
|
}
|
|
|
|
// FilerEtcStore implements CredentialStore using SeaweedFS filer for storage
|
|
type FilerEtcStore struct {
|
|
filerAddressFunc func() pb.ServerAddress // Function to get current active filer
|
|
grpcDialOption grpc.DialOption
|
|
mu sync.RWMutex // Protects filerAddressFunc and grpcDialOption
|
|
policyMu sync.Mutex // Serializes legacy managed-policy mutations
|
|
}
|
|
|
|
func (store *FilerEtcStore) GetName() credential.CredentialStoreTypeName {
|
|
return credential.StoreTypeFilerEtc
|
|
}
|
|
|
|
func (store *FilerEtcStore) Initialize(configuration util.Configuration, prefix string) error {
|
|
// Handle nil configuration gracefully
|
|
if configuration != nil {
|
|
filerAddr := configuration.GetString(prefix + "filer")
|
|
if filerAddr != "" {
|
|
// Static configuration - use fixed address
|
|
store.mu.Lock()
|
|
store.filerAddressFunc = func() pb.ServerAddress {
|
|
return pb.ServerAddress(filerAddr)
|
|
}
|
|
store.mu.Unlock()
|
|
}
|
|
// TODO: Initialize grpcDialOption based on configuration
|
|
}
|
|
// Note: filerAddressFunc can be set later via SetFilerAddressFunc method
|
|
return nil
|
|
}
|
|
|
|
// SetFilerAddressFunc sets a function that returns the current active filer address
|
|
// This enables high availability by using the currently active filer
|
|
func (store *FilerEtcStore) SetFilerAddressFunc(getFiler func() pb.ServerAddress, grpcDialOption grpc.DialOption) {
|
|
store.mu.Lock()
|
|
defer store.mu.Unlock()
|
|
store.filerAddressFunc = getFiler
|
|
store.grpcDialOption = grpcDialOption
|
|
}
|
|
|
|
// withFilerClient executes a function with a filer client
|
|
func (store *FilerEtcStore) withFilerClient(fn func(client filer_pb.SeaweedFilerClient) error) error {
|
|
store.mu.RLock()
|
|
if store.filerAddressFunc == nil {
|
|
store.mu.RUnlock()
|
|
return fmt.Errorf("filer_etc: filer not yet available - please wait for filer discovery to complete and try again")
|
|
}
|
|
|
|
filerAddress := store.filerAddressFunc()
|
|
dialOption := store.grpcDialOption
|
|
store.mu.RUnlock()
|
|
|
|
if filerAddress == "" {
|
|
return fmt.Errorf("filer_etc: no filer discovered yet - please ensure a filer is running and accessible")
|
|
}
|
|
|
|
// Use the pb.WithGrpcFilerClient helper similar to existing code
|
|
return pb.WithGrpcFilerClient(false, 0, filerAddress, dialOption, fn)
|
|
}
|
|
|
|
func (store *FilerEtcStore) Shutdown() {
|
|
// No cleanup needed for file store
|
|
}
|