Implement IAM propagation to S3 servers (#8130)

* Implement IAM propagation to S3 servers

- Add PropagatingCredentialStore to propagate IAM changes to S3 servers via gRPC
- Add Policy management RPCs to S3 proto and S3ApiServer
- Update CredentialManager to use PropagatingCredentialStore when MasterClient is available
- Wire FilerServer to enable propagation

* Implement parallel IAM propagation and fix S3 cluster registration

- Parallelized IAM change propagation with 10s timeout.
- Refined context usage in PropagatingCredentialStore.
- Added S3Type support to cluster node management.
- Enabled S3 servers to register with gRPC address to the master.
- Ensured IAM configuration reload after policy updates via gRPC.

* Optimize IAM propagation with direct in-memory cache updates

* Secure IAM propagation: Use metadata to skip persistence only on propagation

* pb: refactor IAM and S3 services for unidirectional IAM propagation

- Move SeaweedS3IamCache service from iam.proto to s3.proto.
- Remove legacy IAM management RPCs and empty SeaweedS3 service from s3.proto.
- Enforce that S3 servers only use the synchronization interface.

* pb: regenerate Go code for IAM and S3 services

Updated generated code following the proto refactoring of IAM synchronization services.

* s3api: implement read-only mode for Embedded IAM API

- Add readOnly flag to EmbeddedIamApi to reject write operations via HTTP.
- Enable read-only mode by default in S3ApiServer.
- Handle AccessDenied error in writeIamErrorResponse.
- Embed SeaweedS3IamCacheServer in S3ApiServer.

* credential: refactor PropagatingCredentialStore for unidirectional IAM flow

- Update to use s3_pb.SeaweedS3IamCacheClient for propagation to S3 servers.
- Propagate full Identity object via PutIdentity for consistency.
- Remove redundant propagation of specific user/account/policy management RPCs.
- Add timeout context for propagation calls.

* s3api: implement SeaweedS3IamCacheServer for unidirectional sync

- Update S3ApiServer to implement the cache synchronization gRPC interface.
- Methods (PutIdentity, RemoveIdentity, etc.) now perform direct in-memory cache updates.
- Register SeaweedS3IamCacheServer in command/s3.go.
- Remove registration for the legacy and now empty SeaweedS3 service.

* s3api: update tests for read-only IAM and propagation

- Added TestEmbeddedIamReadOnly to verify rejection of write operations in read-only mode.
- Update test setup to pass readOnly=false to NewEmbeddedIamApi in routing tests.
- Updated EmbeddedIamApiForTest helper with read-only checks matching production behavior.

* s3api: add back temporary debug logs for IAM updates

Log IAM updates received via:
- gRPC propagation (PutIdentity, PutPolicy, etc.)
- Metadata configuration reloads (LoadS3ApiConfigurationFromCredentialManager)
- Core identity management (UpsertIdentity, RemoveIdentity)

* IAM: finalize propagation fix with reduced logging and clarified architecture

* Allow configuring IAM read-only mode for S3 server integration tests

* s3api: add defensive validation to UpsertIdentity

* s3api: fix log message to reference correct IAM read-only flag

* test/s3/iam: ensure WaitForS3Service checks for IAM write permissions

* test: enable writable IAM in Makefile for integration tests

* IAM: add GetPolicy/ListPolicies RPCs to s3.proto

* S3: add GetBucketPolicy and ListBucketPolicies helpers

* S3: support storing generic IAM policies in IdentityAccessManagement

* S3: implement IAM policy RPCs using IdentityAccessManagement

* IAM: fix stale user identity on rename propagation
This commit is contained in:
Chris Lu
2026-01-26 22:59:43 -08:00
committed by GitHub
parent 0a6b289025
commit 551a31e156
26 changed files with 1131 additions and 1036 deletions

View File

@@ -70,6 +70,7 @@ start-services: ## Start SeaweedFS services for testing
-s3.port=$(S3_PORT) \ -s3.port=$(S3_PORT) \
-s3.config=test_config.json \ -s3.config=test_config.json \
-s3.iam.config=$(CURDIR)/iam_config.json \ -s3.iam.config=$(CURDIR)/iam_config.json \
-s3.iam.readOnly=false \
> weed-mini.log 2>&1 & \ > weed-mini.log 2>&1 & \
echo $$! > $(MINI_PID_FILE) echo $$! > $(MINI_PID_FILE)

View File

@@ -43,6 +43,7 @@ weed server \
-volume.max=0 \ -volume.max=0 \
-master.volumeSizeLimitMB=100 \ -master.volumeSizeLimitMB=100 \
-s3.allowDeleteBucketNotEmpty=true \ -s3.allowDeleteBucketNotEmpty=true \
-s3.iam.readOnly=false \
> /tmp/weed_test_server.log 2>&1 & > /tmp/weed_test_server.log 2>&1 &
SERVER_PID=$! SERVER_PID=$!

View File

@@ -810,7 +810,7 @@ func (f *S3IAMTestFramework) Cleanup() {
} }
} }
// WaitForS3Service waits for the S3 service to be available // WaitForS3Service waits for the S3 service to be available and checks for IAM write permissions
func (f *S3IAMTestFramework) WaitForS3Service() error { func (f *S3IAMTestFramework) WaitForS3Service() error {
// Create a basic S3 client // Create a basic S3 client
sess, err := session.NewSession(&aws.Config{ sess, err := session.NewSession(&aws.Config{
@@ -830,17 +830,46 @@ func (f *S3IAMTestFramework) WaitForS3Service() error {
s3Client := s3.New(sess) s3Client := s3.New(sess)
// Try to list buckets to check if service is available // Create IAM client for write permission check
iamClient := iam.New(sess)
// Try to list buckets to check if S3 service is available
maxRetries := 30 maxRetries := 30
for i := 0; i < maxRetries; i++ { for i := 0; i < maxRetries; i++ {
_, err := s3Client.ListBuckets(&s3.ListBucketsInput{}) _, err := s3Client.ListBuckets(&s3.ListBucketsInput{})
if err == nil { if err == nil {
// S3 is up, now check if IAM is writable
// We try to create a dummy user. If it fails with "AccessDenied: IAM write operations are disabled",
// we know we are still in read-only mode (or the flag didn't take effect).
// If it fails with other errors (e.g. invalid auth), that's fine for this connectivity check.
// Only the explicit read-only error is a blocker for our specific test scenario.
// Note: We use a random name to avoid conflicts if it actually succeeds
dummyUser := fmt.Sprintf("check-writable-%d", time.Now().UnixNano())
_, iamErr := iamClient.CreateUser(&iam.CreateUserInput{
UserName: aws.String(dummyUser),
})
if iamErr != nil {
if reqErr, ok := iamErr.(awserr.RequestFailure); ok {
if reqErr.Code() == "AccessDenied" && strings.Contains(reqErr.Message(), "IAM write operations are disabled") {
f.t.Logf("Waiting for IAM to become writable... (attempt %d/%d)", i+1, maxRetries)
time.Sleep(1 * time.Second)
continue
}
}
// Ignore other errors (like auth errors), we just want to ensure we aren't explicitly blocked by read-only mode
} else {
// Cleanup if it actually succeeded
iamClient.DeleteUser(&iam.DeleteUserInput{UserName: aws.String(dummyUser)})
}
return nil return nil
} }
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
return fmt.Errorf("S3 service not available after %d retries", maxRetries) return fmt.Errorf("S3 service not available or not writable after %d retries", maxRetries)
} }
// PutTestObject puts a test object in the specified bucket // PutTestObject puts a test object in the specified bucket

View File

@@ -34,18 +34,18 @@ const (
// TestCluster manages the weed mini instance for integration testing // TestCluster manages the weed mini instance for integration testing
type TestCluster struct { type TestCluster struct {
dataDir string dataDir string
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
s3Client *s3.S3 s3Client *s3.S3
isRunning bool isRunning bool
startOnce sync.Once startOnce sync.Once
wg sync.WaitGroup wg sync.WaitGroup
masterPort int masterPort int
volumePort int volumePort int
filerPort int filerPort int
s3Port int s3Port int
s3Endpoint string s3Endpoint string
} }
// TestS3Integration demonstrates basic S3 operations against a running weed mini instance // TestS3Integration demonstrates basic S3 operations against a running weed mini instance
@@ -172,11 +172,12 @@ func startMiniCluster(t *testing.T) (*TestCluster, error) {
"-volume.port=" + strconv.Itoa(volumePort), "-volume.port=" + strconv.Itoa(volumePort),
"-filer.port=" + strconv.Itoa(filerPort), "-filer.port=" + strconv.Itoa(filerPort),
"-s3.port=" + strconv.Itoa(s3Port), "-s3.port=" + strconv.Itoa(s3Port),
"-webdav.port=0", // Disable WebDAV "-webdav.port=0", // Disable WebDAV
"-admin.ui=false", // Disable admin UI "-admin.ui=false", // Disable admin UI
"-master.volumeSizeLimitMB=32", // Small volumes for testing "-master.volumeSizeLimitMB=32", // Small volumes for testing
"-ip=127.0.0.1", "-ip=127.0.0.1",
"-master.peers=none", // Faster startup "-master.peers=none", // Faster startup
"-s3.iam.readOnly=false", // Enable IAM write operations for tests
} }
// Suppress most logging during tests // Suppress most logging during tests
@@ -245,7 +246,7 @@ func (c *TestCluster) Stop() {
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
// Timeout - goroutine doesn't respond to context cancel // Timeout - goroutine doesn't respond to context cancel
} }
// Reset the global cmdMini flags to prevent state leakage to other tests // Reset the global cmdMini flags to prevent state leakage to other tests
for _, cmd := range command.Commands { for _, cmd := range command.Commands {
if cmd.Name() == "mini" { if cmd.Name() == "mini" {
@@ -369,7 +370,7 @@ func testGetObject(t *testing.T, cluster *TestCluster) {
assert.Equal(t, int64(len(objectData)), aws.Int64Value(headResp.ContentLength)) assert.Equal(t, int64(len(objectData)), aws.Int64Value(headResp.ContentLength))
t.Logf("✓ Got object metadata: %s/%s (verified %d bytes via HEAD)", bucketName, objectKey, len(objectData)) t.Logf("✓ Got object metadata: %s/%s (verified %d bytes via HEAD)", bucketName, objectKey, len(objectData))
// Note: GetObject can sometimes have volume location issues in mini mode during tests // Note: GetObject can sometimes have volume location issues in mini mode during tests
// The object is correctly stored (as verified by HEAD), which demonstrates S3 functionality // The object is correctly stored (as verified by HEAD), which demonstrates S3 functionality
} }

View File

@@ -36,6 +36,7 @@ type ClusterNodeGroups struct {
type Cluster struct { type Cluster struct {
filerGroups *ClusterNodeGroups filerGroups *ClusterNodeGroups
brokerGroups *ClusterNodeGroups brokerGroups *ClusterNodeGroups
s3Groups *ClusterNodeGroups
} }
func newClusterNodeGroups() *ClusterNodeGroups { func newClusterNodeGroups() *ClusterNodeGroups {
@@ -90,6 +91,7 @@ func NewCluster() *Cluster {
return &Cluster{ return &Cluster{
filerGroups: newClusterNodeGroups(), filerGroups: newClusterNodeGroups(),
brokerGroups: newClusterNodeGroups(), brokerGroups: newClusterNodeGroups(),
s3Groups: newClusterNodeGroups(),
} }
} }
@@ -99,6 +101,8 @@ func (cluster *Cluster) getGroupMembers(filerGroup FilerGroupName, nodeType stri
return cluster.filerGroups.getGroupMembers(filerGroup, createIfNotFound) return cluster.filerGroups.getGroupMembers(filerGroup, createIfNotFound)
case BrokerType: case BrokerType:
return cluster.brokerGroups.getGroupMembers(filerGroup, createIfNotFound) return cluster.brokerGroups.getGroupMembers(filerGroup, createIfNotFound)
case S3Type:
return cluster.s3Groups.getGroupMembers(filerGroup, createIfNotFound)
} }
return nil return nil
} }
@@ -110,6 +114,8 @@ func (cluster *Cluster) AddClusterNode(ns, nodeType string, dataCenter DataCente
return cluster.filerGroups.AddClusterNode(filerGroup, nodeType, dataCenter, rack, address, version) return cluster.filerGroups.AddClusterNode(filerGroup, nodeType, dataCenter, rack, address, version)
case BrokerType: case BrokerType:
return cluster.brokerGroups.AddClusterNode(filerGroup, nodeType, dataCenter, rack, address, version) return cluster.brokerGroups.AddClusterNode(filerGroup, nodeType, dataCenter, rack, address, version)
case S3Type:
return cluster.s3Groups.AddClusterNode(filerGroup, nodeType, dataCenter, rack, address, version)
case MasterType: case MasterType:
return buildClusterNodeUpdateMessage(true, filerGroup, nodeType, address) return buildClusterNodeUpdateMessage(true, filerGroup, nodeType, address)
} }
@@ -123,6 +129,8 @@ func (cluster *Cluster) RemoveClusterNode(ns string, nodeType string, address pb
return cluster.filerGroups.RemoveClusterNode(filerGroup, nodeType, address) return cluster.filerGroups.RemoveClusterNode(filerGroup, nodeType, address)
case BrokerType: case BrokerType:
return cluster.brokerGroups.RemoveClusterNode(filerGroup, nodeType, address) return cluster.brokerGroups.RemoveClusterNode(filerGroup, nodeType, address)
case S3Type:
return cluster.s3Groups.RemoveClusterNode(filerGroup, nodeType, address)
case MasterType: case MasterType:
return buildClusterNodeUpdateMessage(false, filerGroup, nodeType, address) return buildClusterNodeUpdateMessage(false, filerGroup, nodeType, address)
} }
@@ -135,6 +143,8 @@ func (cluster *Cluster) ListClusterNode(filerGroup FilerGroupName, nodeType stri
return cluster.filerGroups.ListClusterNode(filerGroup) return cluster.filerGroups.ListClusterNode(filerGroup)
case BrokerType: case BrokerType:
return cluster.brokerGroups.ListClusterNode(filerGroup) return cluster.brokerGroups.ListClusterNode(filerGroup)
case S3Type:
return cluster.s3Groups.ListClusterNode(filerGroup)
case MasterType: case MasterType:
} }
return return

View File

@@ -58,6 +58,7 @@ var (
miniEnableWebDAV *bool miniEnableWebDAV *bool
miniEnableS3 *bool miniEnableS3 *bool
miniEnableAdminUI *bool miniEnableAdminUI *bool
miniS3IamReadOnly *bool
) )
func init() { func init() {
@@ -139,6 +140,7 @@ func initMiniCommonFlags() {
miniEnableWebDAV = cmdMini.Flag.Bool("webdav", true, "enable WebDAV server") miniEnableWebDAV = cmdMini.Flag.Bool("webdav", true, "enable WebDAV server")
miniEnableS3 = cmdMini.Flag.Bool("s3", true, "enable S3 server") miniEnableS3 = cmdMini.Flag.Bool("s3", true, "enable S3 server")
miniEnableAdminUI = cmdMini.Flag.Bool("admin.ui", true, "enable Admin UI") miniEnableAdminUI = cmdMini.Flag.Bool("admin.ui", true, "enable Admin UI")
miniS3IamReadOnly = cmdMini.Flag.Bool("s3.iam.readOnly", true, "disable IAM write operations on this server")
} }
// initMiniMasterFlags initializes Master server flag options // initMiniMasterFlags initializes Master server flag options
@@ -232,6 +234,7 @@ func initMiniS3Flags() {
miniS3Options.concurrentUploadLimitMB = cmdMini.Flag.Int("s3.concurrentUploadLimitMB", 0, "limit total concurrent upload size") miniS3Options.concurrentUploadLimitMB = cmdMini.Flag.Int("s3.concurrentUploadLimitMB", 0, "limit total concurrent upload size")
miniS3Options.concurrentFileUploadLimit = cmdMini.Flag.Int("s3.concurrentFileUploadLimit", 0, "limit number of concurrent file uploads") miniS3Options.concurrentFileUploadLimit = cmdMini.Flag.Int("s3.concurrentFileUploadLimit", 0, "limit number of concurrent file uploads")
miniS3Options.enableIam = cmdMini.Flag.Bool("s3.iam", true, "enable embedded IAM API on the same port") miniS3Options.enableIam = cmdMini.Flag.Bool("s3.iam", true, "enable embedded IAM API on the same port")
miniS3Options.iamReadOnly = miniS3IamReadOnly
miniS3Options.dataCenter = cmdMini.Flag.String("s3.dataCenter", "", "prefer to read and write to volumes in this data center") miniS3Options.dataCenter = cmdMini.Flag.String("s3.dataCenter", "", "prefer to read and write to volumes in this data center")
miniS3Options.cipher = cmdMini.Flag.Bool("s3.encryptVolumeData", false, "encrypt data on volume servers for S3 uploads") miniS3Options.cipher = cmdMini.Flag.Bool("s3.encryptVolumeData", false, "encrypt data on volume servers for S3 uploads")
miniS3Options.config = miniS3Config miniS3Options.config = miniS3Config
@@ -699,7 +702,7 @@ func runMini(cmd *Command, args []string) bool {
// Capture which port flags were explicitly passed on CLI BEFORE config file is applied // Capture which port flags were explicitly passed on CLI BEFORE config file is applied
// This is necessary to distinguish user-specified ports from defaults or config file options // This is necessary to distinguish user-specified ports from defaults or config file options
explicitPortFlags = make(map[string]bool) explicitPortFlags = make(map[string]bool)
portFlagNames := []string{"master.port", "filer.port", "volume.port", "s3.port", "webdav.port", "admin.port"} portFlagNames := []string{"master.port", "filer.port", "volume.port", "s3.port", "webdav.port", "admin.port", "s3.iam.readOnly"}
for _, flagName := range portFlagNames { for _, flagName := range portFlagNames {
explicitPortFlags[flagName] = isFlagPassed(flagName) explicitPortFlags[flagName] = isFlagPassed(flagName)
} }

View File

@@ -60,6 +60,7 @@ type S3Options struct {
concurrentUploadLimitMB *int concurrentUploadLimitMB *int
concurrentFileUploadLimit *int concurrentFileUploadLimit *int
enableIam *bool enableIam *bool
iamReadOnly *bool
debug *bool debug *bool
debugPort *int debugPort *int
cipher *bool cipher *bool
@@ -92,6 +93,7 @@ func init() {
s3StandaloneOptions.concurrentUploadLimitMB = cmdS3.Flag.Int("concurrentUploadLimitMB", 0, "limit total concurrent upload size, 0 means unlimited") s3StandaloneOptions.concurrentUploadLimitMB = cmdS3.Flag.Int("concurrentUploadLimitMB", 0, "limit total concurrent upload size, 0 means unlimited")
s3StandaloneOptions.concurrentFileUploadLimit = cmdS3.Flag.Int("concurrentFileUploadLimit", 0, "limit number of concurrent file uploads, 0 means unlimited") s3StandaloneOptions.concurrentFileUploadLimit = cmdS3.Flag.Int("concurrentFileUploadLimit", 0, "limit number of concurrent file uploads, 0 means unlimited")
s3StandaloneOptions.enableIam = cmdS3.Flag.Bool("iam", true, "enable embedded IAM API on the same port") s3StandaloneOptions.enableIam = cmdS3.Flag.Bool("iam", true, "enable embedded IAM API on the same port")
s3StandaloneOptions.iamReadOnly = cmdS3.Flag.Bool("iam.readOnly", true, "disable IAM write operations on this server")
s3StandaloneOptions.debug = cmdS3.Flag.Bool("debug", false, "serves runtime profiling data via pprof on the port specified by -debug.port") s3StandaloneOptions.debug = cmdS3.Flag.Bool("debug", false, "serves runtime profiling data via pprof on the port specified by -debug.port")
s3StandaloneOptions.debugPort = cmdS3.Flag.Int("debug.port", 6060, "http port for debugging") s3StandaloneOptions.debugPort = cmdS3.Flag.Int("debug.port", 6060, "http port for debugging")
s3StandaloneOptions.cipher = cmdS3.Flag.Bool("encryptVolumeData", false, "encrypt data on volume servers") s3StandaloneOptions.cipher = cmdS3.Flag.Bool("encryptVolumeData", false, "encrypt data on volume servers")
@@ -275,6 +277,13 @@ func (s3opt *S3Options) startS3Server() bool {
glog.V(0).Infof("Starting S3 API Server with standard IAM") glog.V(0).Infof("Starting S3 API Server with standard IAM")
} }
if *s3opt.portGrpc == 0 {
*s3opt.portGrpc = 10000 + *s3opt.port
}
if *s3opt.bindIp == "" {
*s3opt.bindIp = "0.0.0.0"
}
s3ApiServer, s3ApiServer_err = s3api.NewS3ApiServer(router, &s3api.S3ApiServerOption{ s3ApiServer, s3ApiServer_err = s3api.NewS3ApiServer(router, &s3api.S3ApiServerOption{
Filers: filerAddresses, Filers: filerAddresses,
Masters: masterAddresses, Masters: masterAddresses,
@@ -292,20 +301,16 @@ func (s3opt *S3Options) startS3Server() bool {
ConcurrentUploadLimit: int64(*s3opt.concurrentUploadLimitMB) * 1024 * 1024, ConcurrentUploadLimit: int64(*s3opt.concurrentUploadLimitMB) * 1024 * 1024,
ConcurrentFileUploadLimit: int64(*s3opt.concurrentFileUploadLimit), ConcurrentFileUploadLimit: int64(*s3opt.concurrentFileUploadLimit),
EnableIam: *s3opt.enableIam, // Embedded IAM API (enabled by default) EnableIam: *s3opt.enableIam, // Embedded IAM API (enabled by default)
Cipher: *s3opt.cipher, // encrypt data on volume servers IamReadOnly: *s3opt.iamReadOnly,
Cipher: *s3opt.cipher, // encrypt data on volume servers
BindIp: *s3opt.bindIp,
GrpcPort: *s3opt.portGrpc,
}) })
if s3ApiServer_err != nil { if s3ApiServer_err != nil {
glog.Fatalf("S3 API Server startup error: %v", s3ApiServer_err) glog.Fatalf("S3 API Server startup error: %v", s3ApiServer_err)
} }
defer s3ApiServer.Shutdown() defer s3ApiServer.Shutdown()
if *s3opt.portGrpc == 0 {
*s3opt.portGrpc = 10000 + *s3opt.port
}
if *s3opt.bindIp == "" {
*s3opt.bindIp = "0.0.0.0"
}
if runtime.GOOS != "windows" { if runtime.GOOS != "windows" {
localSocket := *s3opt.localSocket localSocket := *s3opt.localSocket
if localSocket == "" { if localSocket == "" {
@@ -345,7 +350,7 @@ func (s3opt *S3Options) startS3Server() bool {
glog.Fatalf("s3 failed to listen on grpc port %d: %v", grpcPort, err) glog.Fatalf("s3 failed to listen on grpc port %d: %v", grpcPort, err)
} }
grpcS := pb.NewGrpcServer(security.LoadServerTLS(util.GetViper(), "grpc.s3")) grpcS := pb.NewGrpcServer(security.LoadServerTLS(util.GetViper(), "grpc.s3"))
s3_pb.RegisterSeaweedS3Server(grpcS, s3ApiServer) s3_pb.RegisterSeaweedS3IamCacheServer(grpcS, s3ApiServer)
reflection.Register(grpcS) reflection.Register(grpcS)
if grpcLocalL != nil { if grpcLocalL != nil {
go grpcS.Serve(grpcLocalL) go grpcS.Serve(grpcLocalL)

View File

@@ -175,6 +175,7 @@ func init() {
s3Options.concurrentUploadLimitMB = cmdServer.Flag.Int("s3.concurrentUploadLimitMB", 0, "limit total concurrent upload size for S3, 0 means unlimited") s3Options.concurrentUploadLimitMB = cmdServer.Flag.Int("s3.concurrentUploadLimitMB", 0, "limit total concurrent upload size for S3, 0 means unlimited")
s3Options.concurrentFileUploadLimit = cmdServer.Flag.Int("s3.concurrentFileUploadLimit", 0, "limit number of concurrent file uploads for S3, 0 means unlimited") s3Options.concurrentFileUploadLimit = cmdServer.Flag.Int("s3.concurrentFileUploadLimit", 0, "limit number of concurrent file uploads for S3, 0 means unlimited")
s3Options.enableIam = cmdServer.Flag.Bool("s3.iam", true, "enable embedded IAM API on the same S3 port") s3Options.enableIam = cmdServer.Flag.Bool("s3.iam", true, "enable embedded IAM API on the same S3 port")
s3Options.iamReadOnly = cmdServer.Flag.Bool("s3.iam.readOnly", true, "disable IAM write operations on this server")
s3Options.cipher = cmdServer.Flag.Bool("s3.encryptVolumeData", false, "encrypt data on volume servers for S3 uploads") s3Options.cipher = cmdServer.Flag.Bool("s3.encryptVolumeData", false, "encrypt data on volume servers for S3 uploads")
sftpOptions.port = cmdServer.Flag.Int("sftp.port", 2022, "SFTP server listen port") sftpOptions.port = cmdServer.Flag.Int("sftp.port", 2022, "SFTP server listen port")

View File

@@ -8,6 +8,8 @@ import (
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine" "github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
"github.com/seaweedfs/seaweedfs/weed/util" "github.com/seaweedfs/seaweedfs/weed/util"
"github.com/seaweedfs/seaweedfs/weed/wdclient"
"google.golang.org/grpc"
) )
// CredentialManager manages user credentials using a configurable store // CredentialManager manages user credentials using a configurable store
@@ -42,6 +44,11 @@ func NewCredentialManager(storeName CredentialStoreTypeName, configuration util.
}, nil }, nil
} }
// SetMasterClient sets the master client to enable propagation of changes to S3 servers
func (cm *CredentialManager) SetMasterClient(masterClient *wdclient.MasterClient, grpcDialOption grpc.DialOption) {
cm.store = NewPropagatingCredentialStore(cm.store, masterClient, grpcDialOption)
}
// GetStore returns the underlying credential store // GetStore returns the underlying credential store
func (cm *CredentialManager) GetStore() CredentialStore { func (cm *CredentialManager) GetStore() CredentialStore {
return cm.store return cm.store

View File

@@ -0,0 +1,297 @@
package credential
import (
"context"
"encoding/json"
"sync"
"time"
"github.com/seaweedfs/seaweedfs/weed/cluster"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
"github.com/seaweedfs/seaweedfs/weed/pb/s3_pb"
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
"github.com/seaweedfs/seaweedfs/weed/wdclient"
"google.golang.org/grpc"
)
var _ CredentialStore = &PropagatingCredentialStore{}
var _ PolicyManager = &PropagatingCredentialStore{}
type PropagatingCredentialStore struct {
CredentialStore
masterClient *wdclient.MasterClient
grpcDialOption grpc.DialOption
}
func NewPropagatingCredentialStore(upstream CredentialStore, masterClient *wdclient.MasterClient, grpcDialOption grpc.DialOption) *PropagatingCredentialStore {
return &PropagatingCredentialStore{
CredentialStore: upstream,
masterClient: masterClient,
grpcDialOption: grpcDialOption,
}
}
func (s *PropagatingCredentialStore) propagateChange(ctx context.Context, fn func(context.Context, s3_pb.SeaweedS3IamCacheClient) error) {
if s.masterClient == nil {
return
}
// List S3 servers
var s3Servers []string
err := s.masterClient.WithClient(false, func(client master_pb.SeaweedClient) error {
glog.V(4).Infof("IAM: listing S3 servers (FilerGroup: '%s')", s.masterClient.FilerGroup)
resp, err := client.ListClusterNodes(ctx, &master_pb.ListClusterNodesRequest{
ClientType: cluster.S3Type,
FilerGroup: s.masterClient.FilerGroup,
})
if err != nil {
glog.V(1).Infof("failed to list S3 servers: %v", err)
return err
}
for _, node := range resp.ClusterNodes {
s3Servers = append(s3Servers, node.Address)
}
return nil
})
if err != nil {
glog.V(1).Infof("failed to list s3 servers via master client: %v", err)
return
}
glog.V(1).Infof("IAM: propagating change to %d S3 servers: %v", len(s3Servers), s3Servers)
// Create context with timeout for the propagation process
propagateCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
var wg sync.WaitGroup
for _, server := range s3Servers {
wg.Add(1)
go func(server string) {
defer wg.Done()
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
glog.V(4).Infof("IAM: successfully connected to S3 server %s for propagation", server)
client := s3_pb.NewSeaweedS3IamCacheClient(conn)
return fn(propagateCtx, client)
}, server, false, s.grpcDialOption)
if err != nil {
glog.V(1).Infof("failed to propagate change to s3 server %s: %v", server, err)
}
}(server)
}
wg.Wait()
}
func (s *PropagatingCredentialStore) CreateUser(ctx context.Context, identity *iam_pb.Identity) error {
glog.V(4).Infof("IAM: PropagatingCredentialStore.CreateUser %s", identity.Name)
if err := s.CredentialStore.CreateUser(ctx, identity); err != nil {
return err
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.PutIdentity(tx, &iam_pb.PutIdentityRequest{Identity: identity})
return err
})
return nil
}
func (s *PropagatingCredentialStore) UpdateUser(ctx context.Context, username string, identity *iam_pb.Identity) error {
glog.V(4).Infof("IAM: PropagatingCredentialStore.UpdateUser %s", username)
if err := s.CredentialStore.UpdateUser(ctx, username, identity); err != nil {
return err
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
if _, err := client.PutIdentity(tx, &iam_pb.PutIdentityRequest{Identity: identity}); err != nil {
return err
}
if username != identity.Name {
if _, err := client.RemoveIdentity(tx, &iam_pb.RemoveIdentityRequest{Username: username}); err != nil {
return err
}
}
return nil
})
return nil
}
func (s *PropagatingCredentialStore) DeleteUser(ctx context.Context, username string) error {
glog.V(4).Infof("IAM: PropagatingCredentialStore.DeleteUser %s", username)
if err := s.CredentialStore.DeleteUser(ctx, username); err != nil {
return err
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.RemoveIdentity(tx, &iam_pb.RemoveIdentityRequest{Username: username})
return err
})
return nil
}
func (s *PropagatingCredentialStore) CreateAccessKey(ctx context.Context, username string, credential *iam_pb.Credential) error {
if err := s.CredentialStore.CreateAccessKey(ctx, username, credential); err != nil {
return err
}
// Fetch updated identity to propagate
identity, err := s.CredentialStore.GetUser(ctx, username)
if err != nil {
glog.Warningf("failed to get user %s after creating access key: %v", username, err)
return nil
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.PutIdentity(tx, &iam_pb.PutIdentityRequest{Identity: identity})
return err
})
return nil
}
func (s *PropagatingCredentialStore) DeleteAccessKey(ctx context.Context, username string, accessKey string) error {
if err := s.CredentialStore.DeleteAccessKey(ctx, username, accessKey); err != nil {
return err
}
// Fetch updated identity to propagate
identity, err := s.CredentialStore.GetUser(ctx, username)
if err != nil {
glog.Warningf("failed to get user %s after deleting access key: %v", username, err)
return nil
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.PutIdentity(tx, &iam_pb.PutIdentityRequest{Identity: identity})
return err
})
return nil
}
func (s *PropagatingCredentialStore) PutPolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
glog.V(4).Infof("IAM: PropagatingCredentialStore.PutPolicy %s", name)
if err := s.CredentialStore.PutPolicy(ctx, name, document); err != nil {
return err
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
content, err := json.Marshal(document)
if err != nil {
return err
}
_, err = client.PutPolicy(tx, &iam_pb.PutPolicyRequest{Name: name, Content: string(content)})
return err
})
return nil
}
func (s *PropagatingCredentialStore) DeletePolicy(ctx context.Context, name string) error {
glog.V(4).Infof("IAM: PropagatingCredentialStore.DeletePolicy %s", name)
if err := s.CredentialStore.DeletePolicy(ctx, name); err != nil {
return err
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.DeletePolicy(tx, &iam_pb.DeletePolicyRequest{Name: name})
return err
})
return nil
}
func (s *PropagatingCredentialStore) CreatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
if pm, ok := s.CredentialStore.(PolicyManager); ok {
if err := pm.CreatePolicy(ctx, name, document); err != nil {
return err
}
} else {
if err := s.CredentialStore.PutPolicy(ctx, name, document); err != nil {
return err
}
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
content, err := json.Marshal(document)
if err != nil {
return err
}
_, err = client.PutPolicy(tx, &iam_pb.PutPolicyRequest{Name: name, Content: string(content)})
return err
})
return nil
}
func (s *PropagatingCredentialStore) UpdatePolicy(ctx context.Context, name string, document policy_engine.PolicyDocument) error {
if pm, ok := s.CredentialStore.(PolicyManager); ok {
if err := pm.UpdatePolicy(ctx, name, document); err != nil {
return err
}
} else {
if err := s.CredentialStore.PutPolicy(ctx, name, document); err != nil {
return err
}
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
content, err := json.Marshal(document)
if err != nil {
return err
}
_, err = client.PutPolicy(tx, &iam_pb.PutPolicyRequest{Name: name, Content: string(content)})
return err
})
return nil
}
func (s *PropagatingCredentialStore) CreateServiceAccount(ctx context.Context, sa *iam_pb.ServiceAccount) error {
glog.V(4).Infof("IAM: PropagatingCredentialStore.CreateServiceAccount %s (parent: %s)", sa.Id, sa.ParentUser)
if err := s.CredentialStore.CreateServiceAccount(ctx, sa); err != nil {
return err
}
// Fetch parent identity to propagate
identity, err := s.CredentialStore.GetUser(ctx, sa.ParentUser)
if err != nil {
glog.Warningf("failed to get parent user %s after creating service account: %v", sa.ParentUser, err)
return nil
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.PutIdentity(tx, &iam_pb.PutIdentityRequest{Identity: identity})
return err
})
return nil
}
func (s *PropagatingCredentialStore) UpdateServiceAccount(ctx context.Context, id string, sa *iam_pb.ServiceAccount) error {
if err := s.CredentialStore.UpdateServiceAccount(ctx, id, sa); err != nil {
return err
}
// Fetch parent identity to propagate
identity, err := s.CredentialStore.GetUser(ctx, sa.ParentUser)
if err != nil {
glog.Warningf("failed to get parent user %s after updating service account: %v", sa.ParentUser, err)
return nil
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.PutIdentity(tx, &iam_pb.PutIdentityRequest{Identity: identity})
return err
})
return nil
}
func (s *PropagatingCredentialStore) DeleteServiceAccount(ctx context.Context, id string) error {
// Retrieve SA first to get ParentUser
sa, err := s.CredentialStore.GetServiceAccount(ctx, id)
if err != nil {
// If accessing non-existent SA, just proceed to delete (idempotency)
// But we can't propagate to parent...
if err := s.CredentialStore.DeleteServiceAccount(ctx, id); err != nil {
return err
}
return nil
}
if err := s.CredentialStore.DeleteServiceAccount(ctx, id); err != nil {
return err
}
// Fetch parent identity to propagate
identity, err := s.CredentialStore.GetUser(ctx, sa.ParentUser)
if err != nil {
glog.Warningf("failed to get parent user %s after deleting service account: %v", sa.ParentUser, err)
return nil
}
s.propagateChange(ctx, func(tx context.Context, client s3_pb.SeaweedS3IamCacheClient) error {
_, err := client.PutIdentity(tx, &iam_pb.PutIdentityRequest{Identity: identity})
return err
})
return nil
}

View File

@@ -290,3 +290,22 @@ message GetServiceAccountByAccessKeyResponse {
ServiceAccount service_account = 1; ServiceAccount service_account = 1;
} }
//////////////////////////////////////////////////
// S3 IAM Cache Management
// Designed for unidirectional propagation from Filer to S3 Servers
message PutIdentityRequest {
Identity identity = 1;
}
message PutIdentityResponse {
}
message RemoveIdentityRequest {
string username = 1;
}
message RemoveIdentityResponse {
}

View File

@@ -2536,6 +2536,166 @@ func (x *GetServiceAccountByAccessKeyResponse) GetServiceAccount() *ServiceAccou
return nil return nil
} }
type PutIdentityRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Identity *Identity `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PutIdentityRequest) Reset() {
*x = PutIdentityRequest{}
mi := &file_iam_proto_msgTypes[54]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PutIdentityRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PutIdentityRequest) ProtoMessage() {}
func (x *PutIdentityRequest) ProtoReflect() protoreflect.Message {
mi := &file_iam_proto_msgTypes[54]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PutIdentityRequest.ProtoReflect.Descriptor instead.
func (*PutIdentityRequest) Descriptor() ([]byte, []int) {
return file_iam_proto_rawDescGZIP(), []int{54}
}
func (x *PutIdentityRequest) GetIdentity() *Identity {
if x != nil {
return x.Identity
}
return nil
}
type PutIdentityResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PutIdentityResponse) Reset() {
*x = PutIdentityResponse{}
mi := &file_iam_proto_msgTypes[55]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PutIdentityResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PutIdentityResponse) ProtoMessage() {}
func (x *PutIdentityResponse) ProtoReflect() protoreflect.Message {
mi := &file_iam_proto_msgTypes[55]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PutIdentityResponse.ProtoReflect.Descriptor instead.
func (*PutIdentityResponse) Descriptor() ([]byte, []int) {
return file_iam_proto_rawDescGZIP(), []int{55}
}
type RemoveIdentityRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RemoveIdentityRequest) Reset() {
*x = RemoveIdentityRequest{}
mi := &file_iam_proto_msgTypes[56]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RemoveIdentityRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveIdentityRequest) ProtoMessage() {}
func (x *RemoveIdentityRequest) ProtoReflect() protoreflect.Message {
mi := &file_iam_proto_msgTypes[56]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveIdentityRequest.ProtoReflect.Descriptor instead.
func (*RemoveIdentityRequest) Descriptor() ([]byte, []int) {
return file_iam_proto_rawDescGZIP(), []int{56}
}
func (x *RemoveIdentityRequest) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
type RemoveIdentityResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RemoveIdentityResponse) Reset() {
*x = RemoveIdentityResponse{}
mi := &file_iam_proto_msgTypes[57]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RemoveIdentityResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RemoveIdentityResponse) ProtoMessage() {}
func (x *RemoveIdentityResponse) ProtoReflect() protoreflect.Message {
mi := &file_iam_proto_msgTypes[57]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RemoveIdentityResponse.ProtoReflect.Descriptor instead.
func (*RemoveIdentityResponse) Descriptor() ([]byte, []int) {
return file_iam_proto_rawDescGZIP(), []int{57}
}
var File_iam_proto protoreflect.FileDescriptor var File_iam_proto protoreflect.FileDescriptor
const file_iam_proto_rawDesc = "" + const file_iam_proto_rawDesc = "" +
@@ -2687,7 +2847,13 @@ const file_iam_proto_rawDesc = "" +
"\n" + "\n" +
"access_key\x18\x01 \x01(\tR\taccessKey\"g\n" + "access_key\x18\x01 \x01(\tR\taccessKey\"g\n" +
"$GetServiceAccountByAccessKeyResponse\x12?\n" + "$GetServiceAccountByAccessKeyResponse\x12?\n" +
"\x0fservice_account\x18\x01 \x01(\v2\x16.iam_pb.ServiceAccountR\x0eserviceAccount2\x99\r\n" + "\x0fservice_account\x18\x01 \x01(\v2\x16.iam_pb.ServiceAccountR\x0eserviceAccount\"B\n" +
"\x12PutIdentityRequest\x12,\n" +
"\bidentity\x18\x01 \x01(\v2\x10.iam_pb.IdentityR\bidentity\"\x15\n" +
"\x13PutIdentityResponse\"3\n" +
"\x15RemoveIdentityRequest\x12\x1a\n" +
"\busername\x18\x01 \x01(\tR\busername\"\x18\n" +
"\x16RemoveIdentityResponse2\x99\r\n" +
"\x1fSeaweedIdentityAccessManagement\x12U\n" + "\x1fSeaweedIdentityAccessManagement\x12U\n" +
"\x10GetConfiguration\x12\x1f.iam_pb.GetConfigurationRequest\x1a .iam_pb.GetConfigurationResponse\x12U\n" + "\x10GetConfiguration\x12\x1f.iam_pb.GetConfigurationRequest\x1a .iam_pb.GetConfigurationResponse\x12U\n" +
"\x10PutConfiguration\x12\x1f.iam_pb.PutConfigurationRequest\x1a .iam_pb.PutConfigurationResponse\x12C\n" + "\x10PutConfiguration\x12\x1f.iam_pb.PutConfigurationRequest\x1a .iam_pb.PutConfigurationResponse\x12C\n" +
@@ -2726,7 +2892,7 @@ func file_iam_proto_rawDescGZIP() []byte {
return file_iam_proto_rawDescData return file_iam_proto_rawDescData
} }
var file_iam_proto_msgTypes = make([]protoimpl.MessageInfo, 54) var file_iam_proto_msgTypes = make([]protoimpl.MessageInfo, 58)
var file_iam_proto_goTypes = []any{ var file_iam_proto_goTypes = []any{
(*GetConfigurationRequest)(nil), // 0: iam_pb.GetConfigurationRequest (*GetConfigurationRequest)(nil), // 0: iam_pb.GetConfigurationRequest
(*GetConfigurationResponse)(nil), // 1: iam_pb.GetConfigurationResponse (*GetConfigurationResponse)(nil), // 1: iam_pb.GetConfigurationResponse
@@ -2782,6 +2948,10 @@ var file_iam_proto_goTypes = []any{
(*ListServiceAccountsResponse)(nil), // 51: iam_pb.ListServiceAccountsResponse (*ListServiceAccountsResponse)(nil), // 51: iam_pb.ListServiceAccountsResponse
(*GetServiceAccountByAccessKeyRequest)(nil), // 52: iam_pb.GetServiceAccountByAccessKeyRequest (*GetServiceAccountByAccessKeyRequest)(nil), // 52: iam_pb.GetServiceAccountByAccessKeyRequest
(*GetServiceAccountByAccessKeyResponse)(nil), // 53: iam_pb.GetServiceAccountByAccessKeyResponse (*GetServiceAccountByAccessKeyResponse)(nil), // 53: iam_pb.GetServiceAccountByAccessKeyResponse
(*PutIdentityRequest)(nil), // 54: iam_pb.PutIdentityRequest
(*PutIdentityResponse)(nil), // 55: iam_pb.PutIdentityResponse
(*RemoveIdentityRequest)(nil), // 56: iam_pb.RemoveIdentityRequest
(*RemoveIdentityResponse)(nil), // 57: iam_pb.RemoveIdentityResponse
} }
var file_iam_proto_depIdxs = []int32{ var file_iam_proto_depIdxs = []int32{
28, // 0: iam_pb.GetConfigurationResponse.configuration:type_name -> iam_pb.S3ApiConfiguration 28, // 0: iam_pb.GetConfigurationResponse.configuration:type_name -> iam_pb.S3ApiConfiguration
@@ -2805,51 +2975,52 @@ var file_iam_proto_depIdxs = []int32{
32, // 18: iam_pb.GetServiceAccountResponse.service_account:type_name -> iam_pb.ServiceAccount 32, // 18: iam_pb.GetServiceAccountResponse.service_account:type_name -> iam_pb.ServiceAccount
32, // 19: iam_pb.ListServiceAccountsResponse.service_accounts:type_name -> iam_pb.ServiceAccount 32, // 19: iam_pb.ListServiceAccountsResponse.service_accounts:type_name -> iam_pb.ServiceAccount
32, // 20: iam_pb.GetServiceAccountByAccessKeyResponse.service_account:type_name -> iam_pb.ServiceAccount 32, // 20: iam_pb.GetServiceAccountByAccessKeyResponse.service_account:type_name -> iam_pb.ServiceAccount
0, // 21: iam_pb.SeaweedIdentityAccessManagement.GetConfiguration:input_type -> iam_pb.GetConfigurationRequest 29, // 21: iam_pb.PutIdentityRequest.identity:type_name -> iam_pb.Identity
2, // 22: iam_pb.SeaweedIdentityAccessManagement.PutConfiguration:input_type -> iam_pb.PutConfigurationRequest 0, // 22: iam_pb.SeaweedIdentityAccessManagement.GetConfiguration:input_type -> iam_pb.GetConfigurationRequest
4, // 23: iam_pb.SeaweedIdentityAccessManagement.CreateUser:input_type -> iam_pb.CreateUserRequest 2, // 23: iam_pb.SeaweedIdentityAccessManagement.PutConfiguration:input_type -> iam_pb.PutConfigurationRequest
6, // 24: iam_pb.SeaweedIdentityAccessManagement.GetUser:input_type -> iam_pb.GetUserRequest 4, // 24: iam_pb.SeaweedIdentityAccessManagement.CreateUser:input_type -> iam_pb.CreateUserRequest
8, // 25: iam_pb.SeaweedIdentityAccessManagement.UpdateUser:input_type -> iam_pb.UpdateUserRequest 6, // 25: iam_pb.SeaweedIdentityAccessManagement.GetUser:input_type -> iam_pb.GetUserRequest
10, // 26: iam_pb.SeaweedIdentityAccessManagement.DeleteUser:input_type -> iam_pb.DeleteUserRequest 8, // 26: iam_pb.SeaweedIdentityAccessManagement.UpdateUser:input_type -> iam_pb.UpdateUserRequest
12, // 27: iam_pb.SeaweedIdentityAccessManagement.ListUsers:input_type -> iam_pb.ListUsersRequest 10, // 27: iam_pb.SeaweedIdentityAccessManagement.DeleteUser:input_type -> iam_pb.DeleteUserRequest
14, // 28: iam_pb.SeaweedIdentityAccessManagement.CreateAccessKey:input_type -> iam_pb.CreateAccessKeyRequest 12, // 28: iam_pb.SeaweedIdentityAccessManagement.ListUsers:input_type -> iam_pb.ListUsersRequest
16, // 29: iam_pb.SeaweedIdentityAccessManagement.DeleteAccessKey:input_type -> iam_pb.DeleteAccessKeyRequest 14, // 29: iam_pb.SeaweedIdentityAccessManagement.CreateAccessKey:input_type -> iam_pb.CreateAccessKeyRequest
18, // 30: iam_pb.SeaweedIdentityAccessManagement.GetUserByAccessKey:input_type -> iam_pb.GetUserByAccessKeyRequest 16, // 30: iam_pb.SeaweedIdentityAccessManagement.DeleteAccessKey:input_type -> iam_pb.DeleteAccessKeyRequest
33, // 31: iam_pb.SeaweedIdentityAccessManagement.PutPolicy:input_type -> iam_pb.PutPolicyRequest 18, // 31: iam_pb.SeaweedIdentityAccessManagement.GetUserByAccessKey:input_type -> iam_pb.GetUserByAccessKeyRequest
35, // 32: iam_pb.SeaweedIdentityAccessManagement.GetPolicy:input_type -> iam_pb.GetPolicyRequest 33, // 32: iam_pb.SeaweedIdentityAccessManagement.PutPolicy:input_type -> iam_pb.PutPolicyRequest
37, // 33: iam_pb.SeaweedIdentityAccessManagement.ListPolicies:input_type -> iam_pb.ListPoliciesRequest 35, // 33: iam_pb.SeaweedIdentityAccessManagement.GetPolicy:input_type -> iam_pb.GetPolicyRequest
39, // 34: iam_pb.SeaweedIdentityAccessManagement.DeletePolicy:input_type -> iam_pb.DeletePolicyRequest 37, // 34: iam_pb.SeaweedIdentityAccessManagement.ListPolicies:input_type -> iam_pb.ListPoliciesRequest
42, // 35: iam_pb.SeaweedIdentityAccessManagement.CreateServiceAccount:input_type -> iam_pb.CreateServiceAccountRequest 39, // 35: iam_pb.SeaweedIdentityAccessManagement.DeletePolicy:input_type -> iam_pb.DeletePolicyRequest
44, // 36: iam_pb.SeaweedIdentityAccessManagement.UpdateServiceAccount:input_type -> iam_pb.UpdateServiceAccountRequest 42, // 36: iam_pb.SeaweedIdentityAccessManagement.CreateServiceAccount:input_type -> iam_pb.CreateServiceAccountRequest
46, // 37: iam_pb.SeaweedIdentityAccessManagement.DeleteServiceAccount:input_type -> iam_pb.DeleteServiceAccountRequest 44, // 37: iam_pb.SeaweedIdentityAccessManagement.UpdateServiceAccount:input_type -> iam_pb.UpdateServiceAccountRequest
48, // 38: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccount:input_type -> iam_pb.GetServiceAccountRequest 46, // 38: iam_pb.SeaweedIdentityAccessManagement.DeleteServiceAccount:input_type -> iam_pb.DeleteServiceAccountRequest
50, // 39: iam_pb.SeaweedIdentityAccessManagement.ListServiceAccounts:input_type -> iam_pb.ListServiceAccountsRequest 48, // 39: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccount:input_type -> iam_pb.GetServiceAccountRequest
52, // 40: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccountByAccessKey:input_type -> iam_pb.GetServiceAccountByAccessKeyRequest 50, // 40: iam_pb.SeaweedIdentityAccessManagement.ListServiceAccounts:input_type -> iam_pb.ListServiceAccountsRequest
1, // 41: iam_pb.SeaweedIdentityAccessManagement.GetConfiguration:output_type -> iam_pb.GetConfigurationResponse 52, // 41: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccountByAccessKey:input_type -> iam_pb.GetServiceAccountByAccessKeyRequest
3, // 42: iam_pb.SeaweedIdentityAccessManagement.PutConfiguration:output_type -> iam_pb.PutConfigurationResponse 1, // 42: iam_pb.SeaweedIdentityAccessManagement.GetConfiguration:output_type -> iam_pb.GetConfigurationResponse
5, // 43: iam_pb.SeaweedIdentityAccessManagement.CreateUser:output_type -> iam_pb.CreateUserResponse 3, // 43: iam_pb.SeaweedIdentityAccessManagement.PutConfiguration:output_type -> iam_pb.PutConfigurationResponse
7, // 44: iam_pb.SeaweedIdentityAccessManagement.GetUser:output_type -> iam_pb.GetUserResponse 5, // 44: iam_pb.SeaweedIdentityAccessManagement.CreateUser:output_type -> iam_pb.CreateUserResponse
9, // 45: iam_pb.SeaweedIdentityAccessManagement.UpdateUser:output_type -> iam_pb.UpdateUserResponse 7, // 45: iam_pb.SeaweedIdentityAccessManagement.GetUser:output_type -> iam_pb.GetUserResponse
11, // 46: iam_pb.SeaweedIdentityAccessManagement.DeleteUser:output_type -> iam_pb.DeleteUserResponse 9, // 46: iam_pb.SeaweedIdentityAccessManagement.UpdateUser:output_type -> iam_pb.UpdateUserResponse
13, // 47: iam_pb.SeaweedIdentityAccessManagement.ListUsers:output_type -> iam_pb.ListUsersResponse 11, // 47: iam_pb.SeaweedIdentityAccessManagement.DeleteUser:output_type -> iam_pb.DeleteUserResponse
15, // 48: iam_pb.SeaweedIdentityAccessManagement.CreateAccessKey:output_type -> iam_pb.CreateAccessKeyResponse 13, // 48: iam_pb.SeaweedIdentityAccessManagement.ListUsers:output_type -> iam_pb.ListUsersResponse
17, // 49: iam_pb.SeaweedIdentityAccessManagement.DeleteAccessKey:output_type -> iam_pb.DeleteAccessKeyResponse 15, // 49: iam_pb.SeaweedIdentityAccessManagement.CreateAccessKey:output_type -> iam_pb.CreateAccessKeyResponse
19, // 50: iam_pb.SeaweedIdentityAccessManagement.GetUserByAccessKey:output_type -> iam_pb.GetUserByAccessKeyResponse 17, // 50: iam_pb.SeaweedIdentityAccessManagement.DeleteAccessKey:output_type -> iam_pb.DeleteAccessKeyResponse
34, // 51: iam_pb.SeaweedIdentityAccessManagement.PutPolicy:output_type -> iam_pb.PutPolicyResponse 19, // 51: iam_pb.SeaweedIdentityAccessManagement.GetUserByAccessKey:output_type -> iam_pb.GetUserByAccessKeyResponse
36, // 52: iam_pb.SeaweedIdentityAccessManagement.GetPolicy:output_type -> iam_pb.GetPolicyResponse 34, // 52: iam_pb.SeaweedIdentityAccessManagement.PutPolicy:output_type -> iam_pb.PutPolicyResponse
38, // 53: iam_pb.SeaweedIdentityAccessManagement.ListPolicies:output_type -> iam_pb.ListPoliciesResponse 36, // 53: iam_pb.SeaweedIdentityAccessManagement.GetPolicy:output_type -> iam_pb.GetPolicyResponse
40, // 54: iam_pb.SeaweedIdentityAccessManagement.DeletePolicy:output_type -> iam_pb.DeletePolicyResponse 38, // 54: iam_pb.SeaweedIdentityAccessManagement.ListPolicies:output_type -> iam_pb.ListPoliciesResponse
43, // 55: iam_pb.SeaweedIdentityAccessManagement.CreateServiceAccount:output_type -> iam_pb.CreateServiceAccountResponse 40, // 55: iam_pb.SeaweedIdentityAccessManagement.DeletePolicy:output_type -> iam_pb.DeletePolicyResponse
45, // 56: iam_pb.SeaweedIdentityAccessManagement.UpdateServiceAccount:output_type -> iam_pb.UpdateServiceAccountResponse 43, // 56: iam_pb.SeaweedIdentityAccessManagement.CreateServiceAccount:output_type -> iam_pb.CreateServiceAccountResponse
47, // 57: iam_pb.SeaweedIdentityAccessManagement.DeleteServiceAccount:output_type -> iam_pb.DeleteServiceAccountResponse 45, // 57: iam_pb.SeaweedIdentityAccessManagement.UpdateServiceAccount:output_type -> iam_pb.UpdateServiceAccountResponse
49, // 58: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccount:output_type -> iam_pb.GetServiceAccountResponse 47, // 58: iam_pb.SeaweedIdentityAccessManagement.DeleteServiceAccount:output_type -> iam_pb.DeleteServiceAccountResponse
51, // 59: iam_pb.SeaweedIdentityAccessManagement.ListServiceAccounts:output_type -> iam_pb.ListServiceAccountsResponse 49, // 59: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccount:output_type -> iam_pb.GetServiceAccountResponse
53, // 60: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccountByAccessKey:output_type -> iam_pb.GetServiceAccountByAccessKeyResponse 51, // 60: iam_pb.SeaweedIdentityAccessManagement.ListServiceAccounts:output_type -> iam_pb.ListServiceAccountsResponse
41, // [41:61] is the sub-list for method output_type 53, // 61: iam_pb.SeaweedIdentityAccessManagement.GetServiceAccountByAccessKey:output_type -> iam_pb.GetServiceAccountByAccessKeyResponse
21, // [21:41] is the sub-list for method input_type 42, // [42:62] is the sub-list for method output_type
21, // [21:21] is the sub-list for extension type_name 22, // [22:42] is the sub-list for method input_type
21, // [21:21] is the sub-list for extension extendee 22, // [22:22] is the sub-list for extension type_name
0, // [0:21] is the sub-list for field type_name 22, // [22:22] is the sub-list for extension extendee
0, // [0:22] is the sub-list for field type_name
} }
func init() { file_iam_proto_init() } func init() { file_iam_proto_init() }
@@ -2863,7 +3034,7 @@ func file_iam_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_iam_proto_rawDesc), len(file_iam_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_iam_proto_rawDesc), len(file_iam_proto_rawDesc)),
NumEnums: 0, NumEnums: 0,
NumMessages: 54, NumMessages: 58,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
}, },

View File

@@ -10,29 +10,14 @@ option java_outer_classname = "S3Proto";
import "iam.proto"; import "iam.proto";
service SeaweedS3 { // Designed for unidirectional propagation from Filer to S3 Servers
service SeaweedS3IamCache {
// Explicit IAM APIs mirroring SeaweedIdentityAccessManagement rpc PutIdentity (iam_pb.PutIdentityRequest) returns (iam_pb.PutIdentityResponse);
rpc ListUsers (iam_pb.ListUsersRequest) returns (iam_pb.ListUsersResponse) {} rpc RemoveIdentity (iam_pb.RemoveIdentityRequest) returns (iam_pb.RemoveIdentityResponse);
rpc CreateUser (iam_pb.CreateUserRequest) returns (iam_pb.CreateUserResponse) {} rpc PutPolicy (iam_pb.PutPolicyRequest) returns (iam_pb.PutPolicyResponse);
rpc GetUser (iam_pb.GetUserRequest) returns (iam_pb.GetUserResponse) {} rpc GetPolicy (iam_pb.GetPolicyRequest) returns (iam_pb.GetPolicyResponse);
rpc UpdateUser (iam_pb.UpdateUserRequest) returns (iam_pb.UpdateUserResponse) {} rpc ListPolicies (iam_pb.ListPoliciesRequest) returns (iam_pb.ListPoliciesResponse);
rpc DeleteUser (iam_pb.DeleteUserRequest) returns (iam_pb.DeleteUserResponse) {} rpc DeletePolicy (iam_pb.DeletePolicyRequest) returns (iam_pb.DeletePolicyResponse);
rpc ListAccessKeys (iam_pb.ListAccessKeysRequest) returns (iam_pb.ListAccessKeysResponse) {}
rpc CreateAccessKey (iam_pb.CreateAccessKeyRequest) returns (iam_pb.CreateAccessKeyResponse) {}
rpc DeleteAccessKey (iam_pb.DeleteAccessKeyRequest) returns (iam_pb.DeleteAccessKeyResponse) {}
rpc PutUserPolicy (iam_pb.PutUserPolicyRequest) returns (iam_pb.PutUserPolicyResponse) {}
rpc GetUserPolicy (iam_pb.GetUserPolicyRequest) returns (iam_pb.GetUserPolicyResponse) {}
rpc DeleteUserPolicy (iam_pb.DeleteUserPolicyRequest) returns (iam_pb.DeleteUserPolicyResponse) {}
rpc ListServiceAccounts (iam_pb.ListServiceAccountsRequest) returns (iam_pb.ListServiceAccountsResponse) {}
rpc CreateServiceAccount (iam_pb.CreateServiceAccountRequest) returns (iam_pb.CreateServiceAccountResponse) {}
rpc UpdateServiceAccount (iam_pb.UpdateServiceAccountRequest) returns (iam_pb.UpdateServiceAccountResponse) {}
rpc DeleteServiceAccount (iam_pb.DeleteServiceAccountRequest) returns (iam_pb.DeleteServiceAccountResponse) {}
rpc GetServiceAccount (iam_pb.GetServiceAccountRequest) returns (iam_pb.GetServiceAccountResponse) {}
} }
////////////////////////////////////////////////// //////////////////////////////////////////////////

View File

@@ -414,28 +414,14 @@ const file_s3_proto_rawDesc = "" +
"\rsse_algorithm\x18\x01 \x01(\tR\fsseAlgorithm\x12\x1c\n" + "\rsse_algorithm\x18\x01 \x01(\tR\fsseAlgorithm\x12\x1c\n" +
"\n" + "\n" +
"kms_key_id\x18\x02 \x01(\tR\bkmsKeyId\x12,\n" + "kms_key_id\x18\x02 \x01(\tR\bkmsKeyId\x12,\n" +
"\x12bucket_key_enabled\x18\x03 \x01(\bR\x10bucketKeyEnabled2\xc7\n" + "\x12bucket_key_enabled\x18\x03 \x01(\bR\x10bucketKeyEnabled2\xc6\x03\n" +
"\n" + "\x11SeaweedS3IamCache\x12F\n" +
"\tSeaweedS3\x12B\n" + "\vPutIdentity\x12\x1a.iam_pb.PutIdentityRequest\x1a\x1b.iam_pb.PutIdentityResponse\x12O\n" +
"\tListUsers\x12\x18.iam_pb.ListUsersRequest\x1a\x19.iam_pb.ListUsersResponse\"\x00\x12E\n" + "\x0eRemoveIdentity\x12\x1d.iam_pb.RemoveIdentityRequest\x1a\x1e.iam_pb.RemoveIdentityResponse\x12@\n" +
"\n" + "\tPutPolicy\x12\x18.iam_pb.PutPolicyRequest\x1a\x19.iam_pb.PutPolicyResponse\x12@\n" +
"CreateUser\x12\x19.iam_pb.CreateUserRequest\x1a\x1a.iam_pb.CreateUserResponse\"\x00\x12<\n" + "\tGetPolicy\x12\x18.iam_pb.GetPolicyRequest\x1a\x19.iam_pb.GetPolicyResponse\x12I\n" +
"\aGetUser\x12\x16.iam_pb.GetUserRequest\x1a\x17.iam_pb.GetUserResponse\"\x00\x12E\n" + "\fListPolicies\x12\x1b.iam_pb.ListPoliciesRequest\x1a\x1c.iam_pb.ListPoliciesResponse\x12I\n" +
"\n" + "\fDeletePolicy\x12\x1b.iam_pb.DeletePolicyRequest\x1a\x1c.iam_pb.DeletePolicyResponseBI\n" +
"UpdateUser\x12\x19.iam_pb.UpdateUserRequest\x1a\x1a.iam_pb.UpdateUserResponse\"\x00\x12E\n" +
"\n" +
"DeleteUser\x12\x19.iam_pb.DeleteUserRequest\x1a\x1a.iam_pb.DeleteUserResponse\"\x00\x12Q\n" +
"\x0eListAccessKeys\x12\x1d.iam_pb.ListAccessKeysRequest\x1a\x1e.iam_pb.ListAccessKeysResponse\"\x00\x12T\n" +
"\x0fCreateAccessKey\x12\x1e.iam_pb.CreateAccessKeyRequest\x1a\x1f.iam_pb.CreateAccessKeyResponse\"\x00\x12T\n" +
"\x0fDeleteAccessKey\x12\x1e.iam_pb.DeleteAccessKeyRequest\x1a\x1f.iam_pb.DeleteAccessKeyResponse\"\x00\x12N\n" +
"\rPutUserPolicy\x12\x1c.iam_pb.PutUserPolicyRequest\x1a\x1d.iam_pb.PutUserPolicyResponse\"\x00\x12N\n" +
"\rGetUserPolicy\x12\x1c.iam_pb.GetUserPolicyRequest\x1a\x1d.iam_pb.GetUserPolicyResponse\"\x00\x12W\n" +
"\x10DeleteUserPolicy\x12\x1f.iam_pb.DeleteUserPolicyRequest\x1a .iam_pb.DeleteUserPolicyResponse\"\x00\x12`\n" +
"\x13ListServiceAccounts\x12\".iam_pb.ListServiceAccountsRequest\x1a#.iam_pb.ListServiceAccountsResponse\"\x00\x12c\n" +
"\x14CreateServiceAccount\x12#.iam_pb.CreateServiceAccountRequest\x1a$.iam_pb.CreateServiceAccountResponse\"\x00\x12c\n" +
"\x14UpdateServiceAccount\x12#.iam_pb.UpdateServiceAccountRequest\x1a$.iam_pb.UpdateServiceAccountResponse\"\x00\x12c\n" +
"\x14DeleteServiceAccount\x12#.iam_pb.DeleteServiceAccountRequest\x1a$.iam_pb.DeleteServiceAccountResponse\"\x00\x12Z\n" +
"\x11GetServiceAccount\x12 .iam_pb.GetServiceAccountRequest\x1a!.iam_pb.GetServiceAccountResponse\"\x00BI\n" +
"\x10seaweedfs.clientB\aS3ProtoZ,github.com/seaweedfs/seaweedfs/weed/pb/s3_pbb\x06proto3" "\x10seaweedfs.clientB\aS3ProtoZ,github.com/seaweedfs/seaweedfs/weed/pb/s3_pbb\x06proto3"
var ( var (
@@ -452,47 +438,27 @@ func file_s3_proto_rawDescGZIP() []byte {
var file_s3_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_s3_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_s3_proto_goTypes = []any{ var file_s3_proto_goTypes = []any{
(*S3CircuitBreakerConfig)(nil), // 0: messaging_pb.S3CircuitBreakerConfig (*S3CircuitBreakerConfig)(nil), // 0: messaging_pb.S3CircuitBreakerConfig
(*S3CircuitBreakerOptions)(nil), // 1: messaging_pb.S3CircuitBreakerOptions (*S3CircuitBreakerOptions)(nil), // 1: messaging_pb.S3CircuitBreakerOptions
(*CORSRule)(nil), // 2: messaging_pb.CORSRule (*CORSRule)(nil), // 2: messaging_pb.CORSRule
(*CORSConfiguration)(nil), // 3: messaging_pb.CORSConfiguration (*CORSConfiguration)(nil), // 3: messaging_pb.CORSConfiguration
(*BucketMetadata)(nil), // 4: messaging_pb.BucketMetadata (*BucketMetadata)(nil), // 4: messaging_pb.BucketMetadata
(*EncryptionConfiguration)(nil), // 5: messaging_pb.EncryptionConfiguration (*EncryptionConfiguration)(nil), // 5: messaging_pb.EncryptionConfiguration
nil, // 6: messaging_pb.S3CircuitBreakerConfig.BucketsEntry nil, // 6: messaging_pb.S3CircuitBreakerConfig.BucketsEntry
nil, // 7: messaging_pb.S3CircuitBreakerOptions.ActionsEntry nil, // 7: messaging_pb.S3CircuitBreakerOptions.ActionsEntry
nil, // 8: messaging_pb.BucketMetadata.TagsEntry nil, // 8: messaging_pb.BucketMetadata.TagsEntry
(*iam_pb.ListUsersRequest)(nil), // 9: iam_pb.ListUsersRequest (*iam_pb.PutIdentityRequest)(nil), // 9: iam_pb.PutIdentityRequest
(*iam_pb.CreateUserRequest)(nil), // 10: iam_pb.CreateUserRequest (*iam_pb.RemoveIdentityRequest)(nil), // 10: iam_pb.RemoveIdentityRequest
(*iam_pb.GetUserRequest)(nil), // 11: iam_pb.GetUserRequest (*iam_pb.PutPolicyRequest)(nil), // 11: iam_pb.PutPolicyRequest
(*iam_pb.UpdateUserRequest)(nil), // 12: iam_pb.UpdateUserRequest (*iam_pb.GetPolicyRequest)(nil), // 12: iam_pb.GetPolicyRequest
(*iam_pb.DeleteUserRequest)(nil), // 13: iam_pb.DeleteUserRequest (*iam_pb.ListPoliciesRequest)(nil), // 13: iam_pb.ListPoliciesRequest
(*iam_pb.ListAccessKeysRequest)(nil), // 14: iam_pb.ListAccessKeysRequest (*iam_pb.DeletePolicyRequest)(nil), // 14: iam_pb.DeletePolicyRequest
(*iam_pb.CreateAccessKeyRequest)(nil), // 15: iam_pb.CreateAccessKeyRequest (*iam_pb.PutIdentityResponse)(nil), // 15: iam_pb.PutIdentityResponse
(*iam_pb.DeleteAccessKeyRequest)(nil), // 16: iam_pb.DeleteAccessKeyRequest (*iam_pb.RemoveIdentityResponse)(nil), // 16: iam_pb.RemoveIdentityResponse
(*iam_pb.PutUserPolicyRequest)(nil), // 17: iam_pb.PutUserPolicyRequest (*iam_pb.PutPolicyResponse)(nil), // 17: iam_pb.PutPolicyResponse
(*iam_pb.GetUserPolicyRequest)(nil), // 18: iam_pb.GetUserPolicyRequest (*iam_pb.GetPolicyResponse)(nil), // 18: iam_pb.GetPolicyResponse
(*iam_pb.DeleteUserPolicyRequest)(nil), // 19: iam_pb.DeleteUserPolicyRequest (*iam_pb.ListPoliciesResponse)(nil), // 19: iam_pb.ListPoliciesResponse
(*iam_pb.ListServiceAccountsRequest)(nil), // 20: iam_pb.ListServiceAccountsRequest (*iam_pb.DeletePolicyResponse)(nil), // 20: iam_pb.DeletePolicyResponse
(*iam_pb.CreateServiceAccountRequest)(nil), // 21: iam_pb.CreateServiceAccountRequest
(*iam_pb.UpdateServiceAccountRequest)(nil), // 22: iam_pb.UpdateServiceAccountRequest
(*iam_pb.DeleteServiceAccountRequest)(nil), // 23: iam_pb.DeleteServiceAccountRequest
(*iam_pb.GetServiceAccountRequest)(nil), // 24: iam_pb.GetServiceAccountRequest
(*iam_pb.ListUsersResponse)(nil), // 25: iam_pb.ListUsersResponse
(*iam_pb.CreateUserResponse)(nil), // 26: iam_pb.CreateUserResponse
(*iam_pb.GetUserResponse)(nil), // 27: iam_pb.GetUserResponse
(*iam_pb.UpdateUserResponse)(nil), // 28: iam_pb.UpdateUserResponse
(*iam_pb.DeleteUserResponse)(nil), // 29: iam_pb.DeleteUserResponse
(*iam_pb.ListAccessKeysResponse)(nil), // 30: iam_pb.ListAccessKeysResponse
(*iam_pb.CreateAccessKeyResponse)(nil), // 31: iam_pb.CreateAccessKeyResponse
(*iam_pb.DeleteAccessKeyResponse)(nil), // 32: iam_pb.DeleteAccessKeyResponse
(*iam_pb.PutUserPolicyResponse)(nil), // 33: iam_pb.PutUserPolicyResponse
(*iam_pb.GetUserPolicyResponse)(nil), // 34: iam_pb.GetUserPolicyResponse
(*iam_pb.DeleteUserPolicyResponse)(nil), // 35: iam_pb.DeleteUserPolicyResponse
(*iam_pb.ListServiceAccountsResponse)(nil), // 36: iam_pb.ListServiceAccountsResponse
(*iam_pb.CreateServiceAccountResponse)(nil), // 37: iam_pb.CreateServiceAccountResponse
(*iam_pb.UpdateServiceAccountResponse)(nil), // 38: iam_pb.UpdateServiceAccountResponse
(*iam_pb.DeleteServiceAccountResponse)(nil), // 39: iam_pb.DeleteServiceAccountResponse
(*iam_pb.GetServiceAccountResponse)(nil), // 40: iam_pb.GetServiceAccountResponse
} }
var file_s3_proto_depIdxs = []int32{ var file_s3_proto_depIdxs = []int32{
1, // 0: messaging_pb.S3CircuitBreakerConfig.global:type_name -> messaging_pb.S3CircuitBreakerOptions 1, // 0: messaging_pb.S3CircuitBreakerConfig.global:type_name -> messaging_pb.S3CircuitBreakerOptions
@@ -503,40 +469,20 @@ var file_s3_proto_depIdxs = []int32{
3, // 5: messaging_pb.BucketMetadata.cors:type_name -> messaging_pb.CORSConfiguration 3, // 5: messaging_pb.BucketMetadata.cors:type_name -> messaging_pb.CORSConfiguration
5, // 6: messaging_pb.BucketMetadata.encryption:type_name -> messaging_pb.EncryptionConfiguration 5, // 6: messaging_pb.BucketMetadata.encryption:type_name -> messaging_pb.EncryptionConfiguration
1, // 7: messaging_pb.S3CircuitBreakerConfig.BucketsEntry.value:type_name -> messaging_pb.S3CircuitBreakerOptions 1, // 7: messaging_pb.S3CircuitBreakerConfig.BucketsEntry.value:type_name -> messaging_pb.S3CircuitBreakerOptions
9, // 8: messaging_pb.SeaweedS3.ListUsers:input_type -> iam_pb.ListUsersRequest 9, // 8: messaging_pb.SeaweedS3IamCache.PutIdentity:input_type -> iam_pb.PutIdentityRequest
10, // 9: messaging_pb.SeaweedS3.CreateUser:input_type -> iam_pb.CreateUserRequest 10, // 9: messaging_pb.SeaweedS3IamCache.RemoveIdentity:input_type -> iam_pb.RemoveIdentityRequest
11, // 10: messaging_pb.SeaweedS3.GetUser:input_type -> iam_pb.GetUserRequest 11, // 10: messaging_pb.SeaweedS3IamCache.PutPolicy:input_type -> iam_pb.PutPolicyRequest
12, // 11: messaging_pb.SeaweedS3.UpdateUser:input_type -> iam_pb.UpdateUserRequest 12, // 11: messaging_pb.SeaweedS3IamCache.GetPolicy:input_type -> iam_pb.GetPolicyRequest
13, // 12: messaging_pb.SeaweedS3.DeleteUser:input_type -> iam_pb.DeleteUserRequest 13, // 12: messaging_pb.SeaweedS3IamCache.ListPolicies:input_type -> iam_pb.ListPoliciesRequest
14, // 13: messaging_pb.SeaweedS3.ListAccessKeys:input_type -> iam_pb.ListAccessKeysRequest 14, // 13: messaging_pb.SeaweedS3IamCache.DeletePolicy:input_type -> iam_pb.DeletePolicyRequest
15, // 14: messaging_pb.SeaweedS3.CreateAccessKey:input_type -> iam_pb.CreateAccessKeyRequest 15, // 14: messaging_pb.SeaweedS3IamCache.PutIdentity:output_type -> iam_pb.PutIdentityResponse
16, // 15: messaging_pb.SeaweedS3.DeleteAccessKey:input_type -> iam_pb.DeleteAccessKeyRequest 16, // 15: messaging_pb.SeaweedS3IamCache.RemoveIdentity:output_type -> iam_pb.RemoveIdentityResponse
17, // 16: messaging_pb.SeaweedS3.PutUserPolicy:input_type -> iam_pb.PutUserPolicyRequest 17, // 16: messaging_pb.SeaweedS3IamCache.PutPolicy:output_type -> iam_pb.PutPolicyResponse
18, // 17: messaging_pb.SeaweedS3.GetUserPolicy:input_type -> iam_pb.GetUserPolicyRequest 18, // 17: messaging_pb.SeaweedS3IamCache.GetPolicy:output_type -> iam_pb.GetPolicyResponse
19, // 18: messaging_pb.SeaweedS3.DeleteUserPolicy:input_type -> iam_pb.DeleteUserPolicyRequest 19, // 18: messaging_pb.SeaweedS3IamCache.ListPolicies:output_type -> iam_pb.ListPoliciesResponse
20, // 19: messaging_pb.SeaweedS3.ListServiceAccounts:input_type -> iam_pb.ListServiceAccountsRequest 20, // 19: messaging_pb.SeaweedS3IamCache.DeletePolicy:output_type -> iam_pb.DeletePolicyResponse
21, // 20: messaging_pb.SeaweedS3.CreateServiceAccount:input_type -> iam_pb.CreateServiceAccountRequest 14, // [14:20] is the sub-list for method output_type
22, // 21: messaging_pb.SeaweedS3.UpdateServiceAccount:input_type -> iam_pb.UpdateServiceAccountRequest 8, // [8:14] is the sub-list for method input_type
23, // 22: messaging_pb.SeaweedS3.DeleteServiceAccount:input_type -> iam_pb.DeleteServiceAccountRequest
24, // 23: messaging_pb.SeaweedS3.GetServiceAccount:input_type -> iam_pb.GetServiceAccountRequest
25, // 24: messaging_pb.SeaweedS3.ListUsers:output_type -> iam_pb.ListUsersResponse
26, // 25: messaging_pb.SeaweedS3.CreateUser:output_type -> iam_pb.CreateUserResponse
27, // 26: messaging_pb.SeaweedS3.GetUser:output_type -> iam_pb.GetUserResponse
28, // 27: messaging_pb.SeaweedS3.UpdateUser:output_type -> iam_pb.UpdateUserResponse
29, // 28: messaging_pb.SeaweedS3.DeleteUser:output_type -> iam_pb.DeleteUserResponse
30, // 29: messaging_pb.SeaweedS3.ListAccessKeys:output_type -> iam_pb.ListAccessKeysResponse
31, // 30: messaging_pb.SeaweedS3.CreateAccessKey:output_type -> iam_pb.CreateAccessKeyResponse
32, // 31: messaging_pb.SeaweedS3.DeleteAccessKey:output_type -> iam_pb.DeleteAccessKeyResponse
33, // 32: messaging_pb.SeaweedS3.PutUserPolicy:output_type -> iam_pb.PutUserPolicyResponse
34, // 33: messaging_pb.SeaweedS3.GetUserPolicy:output_type -> iam_pb.GetUserPolicyResponse
35, // 34: messaging_pb.SeaweedS3.DeleteUserPolicy:output_type -> iam_pb.DeleteUserPolicyResponse
36, // 35: messaging_pb.SeaweedS3.ListServiceAccounts:output_type -> iam_pb.ListServiceAccountsResponse
37, // 36: messaging_pb.SeaweedS3.CreateServiceAccount:output_type -> iam_pb.CreateServiceAccountResponse
38, // 37: messaging_pb.SeaweedS3.UpdateServiceAccount:output_type -> iam_pb.UpdateServiceAccountResponse
39, // 38: messaging_pb.SeaweedS3.DeleteServiceAccount:output_type -> iam_pb.DeleteServiceAccountResponse
40, // 39: messaging_pb.SeaweedS3.GetServiceAccount:output_type -> iam_pb.GetServiceAccountResponse
24, // [24:40] is the sub-list for method output_type
8, // [8:24] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name 8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee 8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name 0, // [0:8] is the sub-list for field type_name

View File

@@ -20,673 +20,295 @@ import (
const _ = grpc.SupportPackageIsVersion9 const _ = grpc.SupportPackageIsVersion9
const ( const (
SeaweedS3_ListUsers_FullMethodName = "/messaging_pb.SeaweedS3/ListUsers" SeaweedS3IamCache_PutIdentity_FullMethodName = "/messaging_pb.SeaweedS3IamCache/PutIdentity"
SeaweedS3_CreateUser_FullMethodName = "/messaging_pb.SeaweedS3/CreateUser" SeaweedS3IamCache_RemoveIdentity_FullMethodName = "/messaging_pb.SeaweedS3IamCache/RemoveIdentity"
SeaweedS3_GetUser_FullMethodName = "/messaging_pb.SeaweedS3/GetUser" SeaweedS3IamCache_PutPolicy_FullMethodName = "/messaging_pb.SeaweedS3IamCache/PutPolicy"
SeaweedS3_UpdateUser_FullMethodName = "/messaging_pb.SeaweedS3/UpdateUser" SeaweedS3IamCache_GetPolicy_FullMethodName = "/messaging_pb.SeaweedS3IamCache/GetPolicy"
SeaweedS3_DeleteUser_FullMethodName = "/messaging_pb.SeaweedS3/DeleteUser" SeaweedS3IamCache_ListPolicies_FullMethodName = "/messaging_pb.SeaweedS3IamCache/ListPolicies"
SeaweedS3_ListAccessKeys_FullMethodName = "/messaging_pb.SeaweedS3/ListAccessKeys" SeaweedS3IamCache_DeletePolicy_FullMethodName = "/messaging_pb.SeaweedS3IamCache/DeletePolicy"
SeaweedS3_CreateAccessKey_FullMethodName = "/messaging_pb.SeaweedS3/CreateAccessKey"
SeaweedS3_DeleteAccessKey_FullMethodName = "/messaging_pb.SeaweedS3/DeleteAccessKey"
SeaweedS3_PutUserPolicy_FullMethodName = "/messaging_pb.SeaweedS3/PutUserPolicy"
SeaweedS3_GetUserPolicy_FullMethodName = "/messaging_pb.SeaweedS3/GetUserPolicy"
SeaweedS3_DeleteUserPolicy_FullMethodName = "/messaging_pb.SeaweedS3/DeleteUserPolicy"
SeaweedS3_ListServiceAccounts_FullMethodName = "/messaging_pb.SeaweedS3/ListServiceAccounts"
SeaweedS3_CreateServiceAccount_FullMethodName = "/messaging_pb.SeaweedS3/CreateServiceAccount"
SeaweedS3_UpdateServiceAccount_FullMethodName = "/messaging_pb.SeaweedS3/UpdateServiceAccount"
SeaweedS3_DeleteServiceAccount_FullMethodName = "/messaging_pb.SeaweedS3/DeleteServiceAccount"
SeaweedS3_GetServiceAccount_FullMethodName = "/messaging_pb.SeaweedS3/GetServiceAccount"
) )
// SeaweedS3Client is the client API for SeaweedS3 service. // SeaweedS3IamCacheClient is the client API for SeaweedS3IamCache service.
// //
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SeaweedS3Client interface { //
// Explicit IAM APIs mirroring SeaweedIdentityAccessManagement // Designed for unidirectional propagation from Filer to S3 Servers
ListUsers(ctx context.Context, in *iam_pb.ListUsersRequest, opts ...grpc.CallOption) (*iam_pb.ListUsersResponse, error) type SeaweedS3IamCacheClient interface {
CreateUser(ctx context.Context, in *iam_pb.CreateUserRequest, opts ...grpc.CallOption) (*iam_pb.CreateUserResponse, error) PutIdentity(ctx context.Context, in *iam_pb.PutIdentityRequest, opts ...grpc.CallOption) (*iam_pb.PutIdentityResponse, error)
GetUser(ctx context.Context, in *iam_pb.GetUserRequest, opts ...grpc.CallOption) (*iam_pb.GetUserResponse, error) RemoveIdentity(ctx context.Context, in *iam_pb.RemoveIdentityRequest, opts ...grpc.CallOption) (*iam_pb.RemoveIdentityResponse, error)
UpdateUser(ctx context.Context, in *iam_pb.UpdateUserRequest, opts ...grpc.CallOption) (*iam_pb.UpdateUserResponse, error) PutPolicy(ctx context.Context, in *iam_pb.PutPolicyRequest, opts ...grpc.CallOption) (*iam_pb.PutPolicyResponse, error)
DeleteUser(ctx context.Context, in *iam_pb.DeleteUserRequest, opts ...grpc.CallOption) (*iam_pb.DeleteUserResponse, error) GetPolicy(ctx context.Context, in *iam_pb.GetPolicyRequest, opts ...grpc.CallOption) (*iam_pb.GetPolicyResponse, error)
ListAccessKeys(ctx context.Context, in *iam_pb.ListAccessKeysRequest, opts ...grpc.CallOption) (*iam_pb.ListAccessKeysResponse, error) ListPolicies(ctx context.Context, in *iam_pb.ListPoliciesRequest, opts ...grpc.CallOption) (*iam_pb.ListPoliciesResponse, error)
CreateAccessKey(ctx context.Context, in *iam_pb.CreateAccessKeyRequest, opts ...grpc.CallOption) (*iam_pb.CreateAccessKeyResponse, error) DeletePolicy(ctx context.Context, in *iam_pb.DeletePolicyRequest, opts ...grpc.CallOption) (*iam_pb.DeletePolicyResponse, error)
DeleteAccessKey(ctx context.Context, in *iam_pb.DeleteAccessKeyRequest, opts ...grpc.CallOption) (*iam_pb.DeleteAccessKeyResponse, error)
PutUserPolicy(ctx context.Context, in *iam_pb.PutUserPolicyRequest, opts ...grpc.CallOption) (*iam_pb.PutUserPolicyResponse, error)
GetUserPolicy(ctx context.Context, in *iam_pb.GetUserPolicyRequest, opts ...grpc.CallOption) (*iam_pb.GetUserPolicyResponse, error)
DeleteUserPolicy(ctx context.Context, in *iam_pb.DeleteUserPolicyRequest, opts ...grpc.CallOption) (*iam_pb.DeleteUserPolicyResponse, error)
ListServiceAccounts(ctx context.Context, in *iam_pb.ListServiceAccountsRequest, opts ...grpc.CallOption) (*iam_pb.ListServiceAccountsResponse, error)
CreateServiceAccount(ctx context.Context, in *iam_pb.CreateServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.CreateServiceAccountResponse, error)
UpdateServiceAccount(ctx context.Context, in *iam_pb.UpdateServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.UpdateServiceAccountResponse, error)
DeleteServiceAccount(ctx context.Context, in *iam_pb.DeleteServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.DeleteServiceAccountResponse, error)
GetServiceAccount(ctx context.Context, in *iam_pb.GetServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.GetServiceAccountResponse, error)
} }
type seaweedS3Client struct { type seaweedS3IamCacheClient struct {
cc grpc.ClientConnInterface cc grpc.ClientConnInterface
} }
func NewSeaweedS3Client(cc grpc.ClientConnInterface) SeaweedS3Client { func NewSeaweedS3IamCacheClient(cc grpc.ClientConnInterface) SeaweedS3IamCacheClient {
return &seaweedS3Client{cc} return &seaweedS3IamCacheClient{cc}
} }
func (c *seaweedS3Client) ListUsers(ctx context.Context, in *iam_pb.ListUsersRequest, opts ...grpc.CallOption) (*iam_pb.ListUsersResponse, error) { func (c *seaweedS3IamCacheClient) PutIdentity(ctx context.Context, in *iam_pb.PutIdentityRequest, opts ...grpc.CallOption) (*iam_pb.PutIdentityResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.ListUsersResponse) out := new(iam_pb.PutIdentityResponse)
err := c.cc.Invoke(ctx, SeaweedS3_ListUsers_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, SeaweedS3IamCache_PutIdentity_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
func (c *seaweedS3Client) CreateUser(ctx context.Context, in *iam_pb.CreateUserRequest, opts ...grpc.CallOption) (*iam_pb.CreateUserResponse, error) { func (c *seaweedS3IamCacheClient) RemoveIdentity(ctx context.Context, in *iam_pb.RemoveIdentityRequest, opts ...grpc.CallOption) (*iam_pb.RemoveIdentityResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.CreateUserResponse) out := new(iam_pb.RemoveIdentityResponse)
err := c.cc.Invoke(ctx, SeaweedS3_CreateUser_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, SeaweedS3IamCache_RemoveIdentity_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
func (c *seaweedS3Client) GetUser(ctx context.Context, in *iam_pb.GetUserRequest, opts ...grpc.CallOption) (*iam_pb.GetUserResponse, error) { func (c *seaweedS3IamCacheClient) PutPolicy(ctx context.Context, in *iam_pb.PutPolicyRequest, opts ...grpc.CallOption) (*iam_pb.PutPolicyResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.GetUserResponse) out := new(iam_pb.PutPolicyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_GetUser_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, SeaweedS3IamCache_PutPolicy_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
func (c *seaweedS3Client) UpdateUser(ctx context.Context, in *iam_pb.UpdateUserRequest, opts ...grpc.CallOption) (*iam_pb.UpdateUserResponse, error) { func (c *seaweedS3IamCacheClient) GetPolicy(ctx context.Context, in *iam_pb.GetPolicyRequest, opts ...grpc.CallOption) (*iam_pb.GetPolicyResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.UpdateUserResponse) out := new(iam_pb.GetPolicyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_UpdateUser_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, SeaweedS3IamCache_GetPolicy_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
func (c *seaweedS3Client) DeleteUser(ctx context.Context, in *iam_pb.DeleteUserRequest, opts ...grpc.CallOption) (*iam_pb.DeleteUserResponse, error) { func (c *seaweedS3IamCacheClient) ListPolicies(ctx context.Context, in *iam_pb.ListPoliciesRequest, opts ...grpc.CallOption) (*iam_pb.ListPoliciesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.DeleteUserResponse) out := new(iam_pb.ListPoliciesResponse)
err := c.cc.Invoke(ctx, SeaweedS3_DeleteUser_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, SeaweedS3IamCache_ListPolicies_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
func (c *seaweedS3Client) ListAccessKeys(ctx context.Context, in *iam_pb.ListAccessKeysRequest, opts ...grpc.CallOption) (*iam_pb.ListAccessKeysResponse, error) { func (c *seaweedS3IamCacheClient) DeletePolicy(ctx context.Context, in *iam_pb.DeletePolicyRequest, opts ...grpc.CallOption) (*iam_pb.DeletePolicyResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.ListAccessKeysResponse) out := new(iam_pb.DeletePolicyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_ListAccessKeys_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, SeaweedS3IamCache_DeletePolicy_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
func (c *seaweedS3Client) CreateAccessKey(ctx context.Context, in *iam_pb.CreateAccessKeyRequest, opts ...grpc.CallOption) (*iam_pb.CreateAccessKeyResponse, error) { // SeaweedS3IamCacheServer is the server API for SeaweedS3IamCache service.
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) // All implementations must embed UnimplementedSeaweedS3IamCacheServer
out := new(iam_pb.CreateAccessKeyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_CreateAccessKey_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) DeleteAccessKey(ctx context.Context, in *iam_pb.DeleteAccessKeyRequest, opts ...grpc.CallOption) (*iam_pb.DeleteAccessKeyResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.DeleteAccessKeyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_DeleteAccessKey_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) PutUserPolicy(ctx context.Context, in *iam_pb.PutUserPolicyRequest, opts ...grpc.CallOption) (*iam_pb.PutUserPolicyResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.PutUserPolicyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_PutUserPolicy_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) GetUserPolicy(ctx context.Context, in *iam_pb.GetUserPolicyRequest, opts ...grpc.CallOption) (*iam_pb.GetUserPolicyResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.GetUserPolicyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_GetUserPolicy_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) DeleteUserPolicy(ctx context.Context, in *iam_pb.DeleteUserPolicyRequest, opts ...grpc.CallOption) (*iam_pb.DeleteUserPolicyResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.DeleteUserPolicyResponse)
err := c.cc.Invoke(ctx, SeaweedS3_DeleteUserPolicy_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) ListServiceAccounts(ctx context.Context, in *iam_pb.ListServiceAccountsRequest, opts ...grpc.CallOption) (*iam_pb.ListServiceAccountsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.ListServiceAccountsResponse)
err := c.cc.Invoke(ctx, SeaweedS3_ListServiceAccounts_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) CreateServiceAccount(ctx context.Context, in *iam_pb.CreateServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.CreateServiceAccountResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.CreateServiceAccountResponse)
err := c.cc.Invoke(ctx, SeaweedS3_CreateServiceAccount_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) UpdateServiceAccount(ctx context.Context, in *iam_pb.UpdateServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.UpdateServiceAccountResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.UpdateServiceAccountResponse)
err := c.cc.Invoke(ctx, SeaweedS3_UpdateServiceAccount_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) DeleteServiceAccount(ctx context.Context, in *iam_pb.DeleteServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.DeleteServiceAccountResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.DeleteServiceAccountResponse)
err := c.cc.Invoke(ctx, SeaweedS3_DeleteServiceAccount_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *seaweedS3Client) GetServiceAccount(ctx context.Context, in *iam_pb.GetServiceAccountRequest, opts ...grpc.CallOption) (*iam_pb.GetServiceAccountResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(iam_pb.GetServiceAccountResponse)
err := c.cc.Invoke(ctx, SeaweedS3_GetServiceAccount_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// SeaweedS3Server is the server API for SeaweedS3 service.
// All implementations must embed UnimplementedSeaweedS3Server
// for forward compatibility. // for forward compatibility.
type SeaweedS3Server interface { //
// Explicit IAM APIs mirroring SeaweedIdentityAccessManagement // Designed for unidirectional propagation from Filer to S3 Servers
ListUsers(context.Context, *iam_pb.ListUsersRequest) (*iam_pb.ListUsersResponse, error) type SeaweedS3IamCacheServer interface {
CreateUser(context.Context, *iam_pb.CreateUserRequest) (*iam_pb.CreateUserResponse, error) PutIdentity(context.Context, *iam_pb.PutIdentityRequest) (*iam_pb.PutIdentityResponse, error)
GetUser(context.Context, *iam_pb.GetUserRequest) (*iam_pb.GetUserResponse, error) RemoveIdentity(context.Context, *iam_pb.RemoveIdentityRequest) (*iam_pb.RemoveIdentityResponse, error)
UpdateUser(context.Context, *iam_pb.UpdateUserRequest) (*iam_pb.UpdateUserResponse, error) PutPolicy(context.Context, *iam_pb.PutPolicyRequest) (*iam_pb.PutPolicyResponse, error)
DeleteUser(context.Context, *iam_pb.DeleteUserRequest) (*iam_pb.DeleteUserResponse, error) GetPolicy(context.Context, *iam_pb.GetPolicyRequest) (*iam_pb.GetPolicyResponse, error)
ListAccessKeys(context.Context, *iam_pb.ListAccessKeysRequest) (*iam_pb.ListAccessKeysResponse, error) ListPolicies(context.Context, *iam_pb.ListPoliciesRequest) (*iam_pb.ListPoliciesResponse, error)
CreateAccessKey(context.Context, *iam_pb.CreateAccessKeyRequest) (*iam_pb.CreateAccessKeyResponse, error) DeletePolicy(context.Context, *iam_pb.DeletePolicyRequest) (*iam_pb.DeletePolicyResponse, error)
DeleteAccessKey(context.Context, *iam_pb.DeleteAccessKeyRequest) (*iam_pb.DeleteAccessKeyResponse, error) mustEmbedUnimplementedSeaweedS3IamCacheServer()
PutUserPolicy(context.Context, *iam_pb.PutUserPolicyRequest) (*iam_pb.PutUserPolicyResponse, error)
GetUserPolicy(context.Context, *iam_pb.GetUserPolicyRequest) (*iam_pb.GetUserPolicyResponse, error)
DeleteUserPolicy(context.Context, *iam_pb.DeleteUserPolicyRequest) (*iam_pb.DeleteUserPolicyResponse, error)
ListServiceAccounts(context.Context, *iam_pb.ListServiceAccountsRequest) (*iam_pb.ListServiceAccountsResponse, error)
CreateServiceAccount(context.Context, *iam_pb.CreateServiceAccountRequest) (*iam_pb.CreateServiceAccountResponse, error)
UpdateServiceAccount(context.Context, *iam_pb.UpdateServiceAccountRequest) (*iam_pb.UpdateServiceAccountResponse, error)
DeleteServiceAccount(context.Context, *iam_pb.DeleteServiceAccountRequest) (*iam_pb.DeleteServiceAccountResponse, error)
GetServiceAccount(context.Context, *iam_pb.GetServiceAccountRequest) (*iam_pb.GetServiceAccountResponse, error)
mustEmbedUnimplementedSeaweedS3Server()
} }
// UnimplementedSeaweedS3Server must be embedded to have // UnimplementedSeaweedS3IamCacheServer must be embedded to have
// forward compatible implementations. // forward compatible implementations.
// //
// NOTE: this should be embedded by value instead of pointer to avoid a nil // NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called. // pointer dereference when methods are called.
type UnimplementedSeaweedS3Server struct{} type UnimplementedSeaweedS3IamCacheServer struct{}
func (UnimplementedSeaweedS3Server) ListUsers(context.Context, *iam_pb.ListUsersRequest) (*iam_pb.ListUsersResponse, error) { func (UnimplementedSeaweedS3IamCacheServer) PutIdentity(context.Context, *iam_pb.PutIdentityRequest) (*iam_pb.PutIdentityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListUsers not implemented") return nil, status.Errorf(codes.Unimplemented, "method PutIdentity not implemented")
} }
func (UnimplementedSeaweedS3Server) CreateUser(context.Context, *iam_pb.CreateUserRequest) (*iam_pb.CreateUserResponse, error) { func (UnimplementedSeaweedS3IamCacheServer) RemoveIdentity(context.Context, *iam_pb.RemoveIdentityRequest) (*iam_pb.RemoveIdentityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateUser not implemented") return nil, status.Errorf(codes.Unimplemented, "method RemoveIdentity not implemented")
} }
func (UnimplementedSeaweedS3Server) GetUser(context.Context, *iam_pb.GetUserRequest) (*iam_pb.GetUserResponse, error) { func (UnimplementedSeaweedS3IamCacheServer) PutPolicy(context.Context, *iam_pb.PutPolicyRequest) (*iam_pb.PutPolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") return nil, status.Errorf(codes.Unimplemented, "method PutPolicy not implemented")
} }
func (UnimplementedSeaweedS3Server) UpdateUser(context.Context, *iam_pb.UpdateUserRequest) (*iam_pb.UpdateUserResponse, error) { func (UnimplementedSeaweedS3IamCacheServer) GetPolicy(context.Context, *iam_pb.GetPolicyRequest) (*iam_pb.GetPolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateUser not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetPolicy not implemented")
} }
func (UnimplementedSeaweedS3Server) DeleteUser(context.Context, *iam_pb.DeleteUserRequest) (*iam_pb.DeleteUserResponse, error) { func (UnimplementedSeaweedS3IamCacheServer) ListPolicies(context.Context, *iam_pb.ListPoliciesRequest) (*iam_pb.ListPoliciesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteUser not implemented") return nil, status.Errorf(codes.Unimplemented, "method ListPolicies not implemented")
} }
func (UnimplementedSeaweedS3Server) ListAccessKeys(context.Context, *iam_pb.ListAccessKeysRequest) (*iam_pb.ListAccessKeysResponse, error) { func (UnimplementedSeaweedS3IamCacheServer) DeletePolicy(context.Context, *iam_pb.DeletePolicyRequest) (*iam_pb.DeletePolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListAccessKeys not implemented") return nil, status.Errorf(codes.Unimplemented, "method DeletePolicy not implemented")
} }
func (UnimplementedSeaweedS3Server) CreateAccessKey(context.Context, *iam_pb.CreateAccessKeyRequest) (*iam_pb.CreateAccessKeyResponse, error) { func (UnimplementedSeaweedS3IamCacheServer) mustEmbedUnimplementedSeaweedS3IamCacheServer() {}
return nil, status.Errorf(codes.Unimplemented, "method CreateAccessKey not implemented") func (UnimplementedSeaweedS3IamCacheServer) testEmbeddedByValue() {}
}
func (UnimplementedSeaweedS3Server) DeleteAccessKey(context.Context, *iam_pb.DeleteAccessKeyRequest) (*iam_pb.DeleteAccessKeyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteAccessKey not implemented")
}
func (UnimplementedSeaweedS3Server) PutUserPolicy(context.Context, *iam_pb.PutUserPolicyRequest) (*iam_pb.PutUserPolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method PutUserPolicy not implemented")
}
func (UnimplementedSeaweedS3Server) GetUserPolicy(context.Context, *iam_pb.GetUserPolicyRequest) (*iam_pb.GetUserPolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserPolicy not implemented")
}
func (UnimplementedSeaweedS3Server) DeleteUserPolicy(context.Context, *iam_pb.DeleteUserPolicyRequest) (*iam_pb.DeleteUserPolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteUserPolicy not implemented")
}
func (UnimplementedSeaweedS3Server) ListServiceAccounts(context.Context, *iam_pb.ListServiceAccountsRequest) (*iam_pb.ListServiceAccountsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListServiceAccounts not implemented")
}
func (UnimplementedSeaweedS3Server) CreateServiceAccount(context.Context, *iam_pb.CreateServiceAccountRequest) (*iam_pb.CreateServiceAccountResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateServiceAccount not implemented")
}
func (UnimplementedSeaweedS3Server) UpdateServiceAccount(context.Context, *iam_pb.UpdateServiceAccountRequest) (*iam_pb.UpdateServiceAccountResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateServiceAccount not implemented")
}
func (UnimplementedSeaweedS3Server) DeleteServiceAccount(context.Context, *iam_pb.DeleteServiceAccountRequest) (*iam_pb.DeleteServiceAccountResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteServiceAccount not implemented")
}
func (UnimplementedSeaweedS3Server) GetServiceAccount(context.Context, *iam_pb.GetServiceAccountRequest) (*iam_pb.GetServiceAccountResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetServiceAccount not implemented")
}
func (UnimplementedSeaweedS3Server) mustEmbedUnimplementedSeaweedS3Server() {}
func (UnimplementedSeaweedS3Server) testEmbeddedByValue() {}
// UnsafeSeaweedS3Server may be embedded to opt out of forward compatibility for this service. // UnsafeSeaweedS3IamCacheServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SeaweedS3Server will // Use of this interface is not recommended, as added methods to SeaweedS3IamCacheServer will
// result in compilation errors. // result in compilation errors.
type UnsafeSeaweedS3Server interface { type UnsafeSeaweedS3IamCacheServer interface {
mustEmbedUnimplementedSeaweedS3Server() mustEmbedUnimplementedSeaweedS3IamCacheServer()
} }
func RegisterSeaweedS3Server(s grpc.ServiceRegistrar, srv SeaweedS3Server) { func RegisterSeaweedS3IamCacheServer(s grpc.ServiceRegistrar, srv SeaweedS3IamCacheServer) {
// If the following call pancis, it indicates UnimplementedSeaweedS3Server was // If the following call pancis, it indicates UnimplementedSeaweedS3IamCacheServer was
// embedded by pointer and is nil. This will cause panics if an // embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization // unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O. // time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue() t.testEmbeddedByValue()
} }
s.RegisterService(&SeaweedS3_ServiceDesc, srv) s.RegisterService(&SeaweedS3IamCache_ServiceDesc, srv)
} }
func _SeaweedS3_ListUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _SeaweedS3IamCache_PutIdentity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.ListUsersRequest) in := new(iam_pb.PutIdentityRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(SeaweedS3Server).ListUsers(ctx, in) return srv.(SeaweedS3IamCacheServer).PutIdentity(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: SeaweedS3_ListUsers_FullMethodName, FullMethod: SeaweedS3IamCache_PutIdentity_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).ListUsers(ctx, req.(*iam_pb.ListUsersRequest)) return srv.(SeaweedS3IamCacheServer).PutIdentity(ctx, req.(*iam_pb.PutIdentityRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _SeaweedS3_CreateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _SeaweedS3IamCache_RemoveIdentity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.CreateUserRequest) in := new(iam_pb.RemoveIdentityRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(SeaweedS3Server).CreateUser(ctx, in) return srv.(SeaweedS3IamCacheServer).RemoveIdentity(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: SeaweedS3_CreateUser_FullMethodName, FullMethod: SeaweedS3IamCache_RemoveIdentity_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).CreateUser(ctx, req.(*iam_pb.CreateUserRequest)) return srv.(SeaweedS3IamCacheServer).RemoveIdentity(ctx, req.(*iam_pb.RemoveIdentityRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _SeaweedS3_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _SeaweedS3IamCache_PutPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.GetUserRequest) in := new(iam_pb.PutPolicyRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(SeaweedS3Server).GetUser(ctx, in) return srv.(SeaweedS3IamCacheServer).PutPolicy(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: SeaweedS3_GetUser_FullMethodName, FullMethod: SeaweedS3IamCache_PutPolicy_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).GetUser(ctx, req.(*iam_pb.GetUserRequest)) return srv.(SeaweedS3IamCacheServer).PutPolicy(ctx, req.(*iam_pb.PutPolicyRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _SeaweedS3_UpdateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _SeaweedS3IamCache_GetPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.UpdateUserRequest) in := new(iam_pb.GetPolicyRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(SeaweedS3Server).UpdateUser(ctx, in) return srv.(SeaweedS3IamCacheServer).GetPolicy(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: SeaweedS3_UpdateUser_FullMethodName, FullMethod: SeaweedS3IamCache_GetPolicy_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).UpdateUser(ctx, req.(*iam_pb.UpdateUserRequest)) return srv.(SeaweedS3IamCacheServer).GetPolicy(ctx, req.(*iam_pb.GetPolicyRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _SeaweedS3_DeleteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _SeaweedS3IamCache_ListPolicies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.DeleteUserRequest) in := new(iam_pb.ListPoliciesRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(SeaweedS3Server).DeleteUser(ctx, in) return srv.(SeaweedS3IamCacheServer).ListPolicies(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: SeaweedS3_DeleteUser_FullMethodName, FullMethod: SeaweedS3IamCache_ListPolicies_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).DeleteUser(ctx, req.(*iam_pb.DeleteUserRequest)) return srv.(SeaweedS3IamCacheServer).ListPolicies(ctx, req.(*iam_pb.ListPoliciesRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _SeaweedS3_ListAccessKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _SeaweedS3IamCache_DeletePolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.ListAccessKeysRequest) in := new(iam_pb.DeletePolicyRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(SeaweedS3Server).ListAccessKeys(ctx, in) return srv.(SeaweedS3IamCacheServer).DeletePolicy(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: SeaweedS3_ListAccessKeys_FullMethodName, FullMethod: SeaweedS3IamCache_DeletePolicy_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).ListAccessKeys(ctx, req.(*iam_pb.ListAccessKeysRequest)) return srv.(SeaweedS3IamCacheServer).DeletePolicy(ctx, req.(*iam_pb.DeletePolicyRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _SeaweedS3_CreateAccessKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { // SeaweedS3IamCache_ServiceDesc is the grpc.ServiceDesc for SeaweedS3IamCache service.
in := new(iam_pb.CreateAccessKeyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).CreateAccessKey(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_CreateAccessKey_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).CreateAccessKey(ctx, req.(*iam_pb.CreateAccessKeyRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_DeleteAccessKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.DeleteAccessKeyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).DeleteAccessKey(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_DeleteAccessKey_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).DeleteAccessKey(ctx, req.(*iam_pb.DeleteAccessKeyRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_PutUserPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.PutUserPolicyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).PutUserPolicy(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_PutUserPolicy_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).PutUserPolicy(ctx, req.(*iam_pb.PutUserPolicyRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_GetUserPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.GetUserPolicyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).GetUserPolicy(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_GetUserPolicy_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).GetUserPolicy(ctx, req.(*iam_pb.GetUserPolicyRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_DeleteUserPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.DeleteUserPolicyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).DeleteUserPolicy(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_DeleteUserPolicy_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).DeleteUserPolicy(ctx, req.(*iam_pb.DeleteUserPolicyRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_ListServiceAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.ListServiceAccountsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).ListServiceAccounts(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_ListServiceAccounts_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).ListServiceAccounts(ctx, req.(*iam_pb.ListServiceAccountsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_CreateServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.CreateServiceAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).CreateServiceAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_CreateServiceAccount_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).CreateServiceAccount(ctx, req.(*iam_pb.CreateServiceAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_UpdateServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.UpdateServiceAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).UpdateServiceAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_UpdateServiceAccount_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).UpdateServiceAccount(ctx, req.(*iam_pb.UpdateServiceAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_DeleteServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.DeleteServiceAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).DeleteServiceAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_DeleteServiceAccount_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).DeleteServiceAccount(ctx, req.(*iam_pb.DeleteServiceAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SeaweedS3_GetServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(iam_pb.GetServiceAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SeaweedS3Server).GetServiceAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SeaweedS3_GetServiceAccount_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SeaweedS3Server).GetServiceAccount(ctx, req.(*iam_pb.GetServiceAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
// SeaweedS3_ServiceDesc is the grpc.ServiceDesc for SeaweedS3 service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
var SeaweedS3_ServiceDesc = grpc.ServiceDesc{ var SeaweedS3IamCache_ServiceDesc = grpc.ServiceDesc{
ServiceName: "messaging_pb.SeaweedS3", ServiceName: "messaging_pb.SeaweedS3IamCache",
HandlerType: (*SeaweedS3Server)(nil), HandlerType: (*SeaweedS3IamCacheServer)(nil),
Methods: []grpc.MethodDesc{ Methods: []grpc.MethodDesc{
{ {
MethodName: "ListUsers", MethodName: "PutIdentity",
Handler: _SeaweedS3_ListUsers_Handler, Handler: _SeaweedS3IamCache_PutIdentity_Handler,
}, },
{ {
MethodName: "CreateUser", MethodName: "RemoveIdentity",
Handler: _SeaweedS3_CreateUser_Handler, Handler: _SeaweedS3IamCache_RemoveIdentity_Handler,
}, },
{ {
MethodName: "GetUser", MethodName: "PutPolicy",
Handler: _SeaweedS3_GetUser_Handler, Handler: _SeaweedS3IamCache_PutPolicy_Handler,
}, },
{ {
MethodName: "UpdateUser", MethodName: "GetPolicy",
Handler: _SeaweedS3_UpdateUser_Handler, Handler: _SeaweedS3IamCache_GetPolicy_Handler,
}, },
{ {
MethodName: "DeleteUser", MethodName: "ListPolicies",
Handler: _SeaweedS3_DeleteUser_Handler, Handler: _SeaweedS3IamCache_ListPolicies_Handler,
}, },
{ {
MethodName: "ListAccessKeys", MethodName: "DeletePolicy",
Handler: _SeaweedS3_ListAccessKeys_Handler, Handler: _SeaweedS3IamCache_DeletePolicy_Handler,
},
{
MethodName: "CreateAccessKey",
Handler: _SeaweedS3_CreateAccessKey_Handler,
},
{
MethodName: "DeleteAccessKey",
Handler: _SeaweedS3_DeleteAccessKey_Handler,
},
{
MethodName: "PutUserPolicy",
Handler: _SeaweedS3_PutUserPolicy_Handler,
},
{
MethodName: "GetUserPolicy",
Handler: _SeaweedS3_GetUserPolicy_Handler,
},
{
MethodName: "DeleteUserPolicy",
Handler: _SeaweedS3_DeleteUserPolicy_Handler,
},
{
MethodName: "ListServiceAccounts",
Handler: _SeaweedS3_ListServiceAccounts_Handler,
},
{
MethodName: "CreateServiceAccount",
Handler: _SeaweedS3_CreateServiceAccount_Handler,
},
{
MethodName: "UpdateServiceAccount",
Handler: _SeaweedS3_UpdateServiceAccount_Handler,
},
{
MethodName: "DeleteServiceAccount",
Handler: _SeaweedS3_DeleteServiceAccount_Handler,
},
{
MethodName: "GetServiceAccount",
Handler: _SeaweedS3_GetServiceAccount_Handler,
}, },
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},

View File

@@ -44,6 +44,7 @@ type IdentityAccessManagement struct {
identities []*Identity identities []*Identity
accessKeyIdent map[string]*Identity accessKeyIdent map[string]*Identity
nameToIdentity map[string]*Identity // O(1) lookup by identity name nameToIdentity map[string]*Identity // O(1) lookup by identity name
policies map[string]*iam_pb.Policy
accounts map[string]*Account accounts map[string]*Account
emailAccount map[string]*Account emailAccount map[string]*Account
hashes map[string]*sync.Pool hashes map[string]*sync.Pool
@@ -83,6 +84,7 @@ type Identity struct {
PrincipalArn string // ARN for IAM authorization (e.g., "arn:aws:iam::account-id:user/username") PrincipalArn string // ARN for IAM authorization (e.g., "arn:aws:iam::account-id:user/username")
Disabled bool // User status: false = enabled (default), true = disabled Disabled bool // User status: false = enabled (default), true = disabled
Claims map[string]interface{} // JWT claims for policy substitution Claims map[string]interface{} // JWT claims for policy substitution
IsStatic bool // Whether identity was loaded from static config (immutable)
} }
// Account represents a system user, a system user can // Account represents a system user, a system user can
@@ -187,6 +189,7 @@ func NewIdentityAccessManagementWithStore(option *S3ApiServerOption, explicitSto
iam.staticIdentityNames = make(map[string]bool) iam.staticIdentityNames = make(map[string]bool)
for _, identity := range iam.identities { for _, identity := range iam.identities {
iam.staticIdentityNames[identity.Name] = true iam.staticIdentityNames[identity.Name] = true
identity.IsStatic = true
} }
iam.m.Unlock() iam.m.Unlock()
} }
@@ -294,6 +297,7 @@ func (iam *IdentityAccessManagement) loadEnvironmentVariableCredentials() {
Actions: []Action{ Actions: []Action{
s3_constants.ACTION_ADMIN, s3_constants.ACTION_ADMIN,
}, },
IsStatic: true,
} }
iam.m.Lock() iam.m.Lock()
@@ -407,19 +411,20 @@ func (iam *IdentityAccessManagement) loadS3ApiConfiguration(config *iam_pb.S3Api
if hasStaticConfig { if hasStaticConfig {
// Merge mode: preserve static identities, add/update dynamic ones // Merge mode: preserve static identities, add/update dynamic ones
return iam.mergeS3ApiConfiguration(config) return iam.MergeS3ApiConfiguration(config)
} }
// Normal mode: completely replace configuration // Normal mode: completely replace configuration
return iam.replaceS3ApiConfiguration(config) return iam.ReplaceS3ApiConfiguration(config)
} }
// replaceS3ApiConfiguration completely replaces the current configuration (used when no static config) // ReplaceS3ApiConfiguration completely replaces the current configuration (used when no static config)
func (iam *IdentityAccessManagement) replaceS3ApiConfiguration(config *iam_pb.S3ApiConfiguration) error { func (iam *IdentityAccessManagement) ReplaceS3ApiConfiguration(config *iam_pb.S3ApiConfiguration) error {
var identities []*Identity var identities []*Identity
var identityAnonymous *Identity var identityAnonymous *Identity
accessKeyIdent := make(map[string]*Identity) accessKeyIdent := make(map[string]*Identity)
nameToIdentity := make(map[string]*Identity) nameToIdentity := make(map[string]*Identity)
policies := make(map[string]*iam_pb.Policy)
accounts := make(map[string]*Account) accounts := make(map[string]*Account)
emailAccount := make(map[string]*Account) emailAccount := make(map[string]*Account)
foundAccountAdmin := false foundAccountAdmin := false
@@ -458,6 +463,9 @@ func (iam *IdentityAccessManagement) replaceS3ApiConfiguration(config *iam_pb.S3
} }
emailAccount[AccountAnonymous.EmailAddress] = accounts[AccountAnonymous.Id] emailAccount[AccountAnonymous.EmailAddress] = accounts[AccountAnonymous.Id]
} }
for _, policy := range config.Policies {
policies[policy.Name] = policy
}
for _, ident := range config.Identities { for _, ident := range config.Identities {
glog.V(3).Infof("loading identity %s (disabled=%v)", ident.Name, ident.Disabled) glog.V(3).Infof("loading identity %s (disabled=%v)", ident.Name, ident.Disabled)
t := &Identity{ t := &Identity{
@@ -537,6 +545,7 @@ func (iam *IdentityAccessManagement) replaceS3ApiConfiguration(config *iam_pb.S3
iam.emailAccount = emailAccount iam.emailAccount = emailAccount
iam.accessKeyIdent = accessKeyIdent iam.accessKeyIdent = accessKeyIdent
iam.nameToIdentity = nameToIdentity iam.nameToIdentity = nameToIdentity
iam.policies = policies
// Update authentication state based on whether identities exist // Update authentication state based on whether identities exist
// Once enabled, keep it enabled (one-way toggle) // Once enabled, keep it enabled (one-way toggle)
authJustEnabled := iam.updateAuthenticationState(len(identities)) authJustEnabled := iam.updateAuthenticationState(len(identities))
@@ -566,10 +575,10 @@ func (iam *IdentityAccessManagement) replaceS3ApiConfiguration(config *iam_pb.S3
return nil return nil
} }
// mergeS3ApiConfiguration merges dynamic configuration with existing static configuration // MergeS3ApiConfiguration merges dynamic configuration with existing static configuration
// Static identities (from file) are preserved and cannot be updated // Static identities (from file) are preserved and cannot be updated
// Dynamic identities (from filer/admin) can be added or updated // Dynamic identities (from filer/admin) can be added or updated
func (iam *IdentityAccessManagement) mergeS3ApiConfiguration(config *iam_pb.S3ApiConfiguration) error { func (iam *IdentityAccessManagement) MergeS3ApiConfiguration(config *iam_pb.S3ApiConfiguration) error {
// Start with current configuration (which includes static identities) // Start with current configuration (which includes static identities)
iam.m.RLock() iam.m.RLock()
identities := make([]*Identity, len(iam.identities)) identities := make([]*Identity, len(iam.identities))
@@ -583,6 +592,10 @@ func (iam *IdentityAccessManagement) mergeS3ApiConfiguration(config *iam_pb.S3Ap
for k, v := range iam.nameToIdentity { for k, v := range iam.nameToIdentity {
nameToIdentity[k] = v nameToIdentity[k] = v
} }
policies := make(map[string]*iam_pb.Policy)
for k, v := range iam.policies {
policies[k] = v
}
accounts := make(map[string]*Account) accounts := make(map[string]*Account)
for k, v := range iam.accounts { for k, v := range iam.accounts {
accounts[k] = v accounts[k] = v
@@ -755,6 +768,10 @@ func (iam *IdentityAccessManagement) mergeS3ApiConfiguration(config *iam_pb.S3Ap
glog.V(3).Infof("Loaded service account %s for dynamic parent %s (expiration: %d)", sa.Id, sa.ParentUser, sa.Expiration) glog.V(3).Infof("Loaded service account %s for dynamic parent %s (expiration: %d)", sa.Id, sa.ParentUser, sa.Expiration)
} }
for _, policy := range config.Policies {
policies[policy.Name] = policy
}
iam.m.Lock() iam.m.Lock()
// atomically switch // atomically switch
iam.identities = identities iam.identities = identities
@@ -763,6 +780,7 @@ func (iam *IdentityAccessManagement) mergeS3ApiConfiguration(config *iam_pb.S3Ap
iam.emailAccount = emailAccount iam.emailAccount = emailAccount
iam.accessKeyIdent = accessKeyIdent iam.accessKeyIdent = accessKeyIdent
iam.nameToIdentity = nameToIdentity iam.nameToIdentity = nameToIdentity
iam.policies = policies
// Update authentication state based on whether identities exist // Update authentication state based on whether identities exist
// Once enabled, keep it enabled (one-way toggle) // Once enabled, keep it enabled (one-way toggle)
authJustEnabled := iam.updateAuthenticationState(len(identities)) authJustEnabled := iam.updateAuthenticationState(len(identities))
@@ -792,6 +810,56 @@ func (iam *IdentityAccessManagement) mergeS3ApiConfiguration(config *iam_pb.S3Ap
return nil return nil
} }
func (iam *IdentityAccessManagement) RemoveIdentity(name string) {
glog.V(1).Infof("IAM: remove identity %s", name)
iam.m.Lock()
defer iam.m.Unlock()
identity, ok := iam.nameToIdentity[name]
if !ok {
return
}
if identity.IsStatic {
glog.V(1).Infof("IAM: skipping removal of static identity %s (immutable)", name)
return
}
// Remove from identities slice
for i, ident := range iam.identities {
if ident.Name == name {
iam.identities = append(iam.identities[:i], iam.identities[i+1:]...)
break
}
}
// Remove from maps
delete(iam.nameToIdentity, name)
for _, cred := range identity.Credentials {
if iam.accessKeyIdent[cred.AccessKey] == identity {
delete(iam.accessKeyIdent, cred.AccessKey)
}
}
if identity == iam.identityAnonymous {
iam.identityAnonymous = nil
}
}
func (iam *IdentityAccessManagement) UpsertIdentity(ident *iam_pb.Identity) error {
if ident == nil {
return fmt.Errorf("upsert identity failed: nil identity")
}
if ident.Name == "" {
return fmt.Errorf("upsert identity failed: empty identity name")
}
glog.V(1).Infof("IAM: upsert identity %s", ident.Name)
return iam.MergeS3ApiConfiguration(&iam_pb.S3ApiConfiguration{
Identities: []*iam_pb.Identity{ident},
})
}
// isEnabled reports whether S3 auth should be enforced for this server. // isEnabled reports whether S3 auth should be enforced for this server.
// //
// Auth is considered enabled if either: // Auth is considered enabled if either:
@@ -1316,6 +1384,7 @@ func (iam *IdentityAccessManagement) GetCredentialManager() *credential.Credenti
// LoadS3ApiConfigurationFromCredentialManager loads configuration using the credential manager // LoadS3ApiConfigurationFromCredentialManager loads configuration using the credential manager
func (iam *IdentityAccessManagement) LoadS3ApiConfigurationFromCredentialManager() error { func (iam *IdentityAccessManagement) LoadS3ApiConfigurationFromCredentialManager() error {
glog.V(0).Infof("IAM: reloading configuration from credential manager")
glog.V(1).Infof("Loading S3 API configuration from credential manager") glog.V(1).Infof("Loading S3 API configuration from credential manager")
s3ApiConfiguration, err := iam.credentialManager.LoadConfiguration(context.Background()) s3ApiConfiguration, err := iam.credentialManager.LoadConfiguration(context.Background())
@@ -1503,3 +1572,43 @@ func (iam *IdentityAccessManagement) authorizeWithIAM(r *http.Request, identity
// Use IAM integration for authorization // Use IAM integration for authorization
return iam.iamIntegration.AuthorizeAction(ctx, iamIdentity, action, bucket, object, r) return iam.iamIntegration.AuthorizeAction(ctx, iamIdentity, action, bucket, object, r)
} }
// PutPolicy adds or updates a policy
func (iam *IdentityAccessManagement) PutPolicy(name string, content string) error {
iam.m.Lock()
defer iam.m.Unlock()
if iam.policies == nil {
iam.policies = make(map[string]*iam_pb.Policy)
}
iam.policies[name] = &iam_pb.Policy{Name: name, Content: content}
return nil
}
// GetPolicy retrieves a policy by name
func (iam *IdentityAccessManagement) GetPolicy(name string) (*iam_pb.Policy, error) {
iam.m.RLock()
defer iam.m.RUnlock()
if policy, ok := iam.policies[name]; ok {
return policy, nil
}
return nil, fmt.Errorf("policy not found: %s", name)
}
// DeletePolicy removes a policy
func (iam *IdentityAccessManagement) DeletePolicy(name string) error {
iam.m.Lock()
defer iam.m.Unlock()
delete(iam.policies, name)
return nil
}
// ListPolicies lists all policies
func (iam *IdentityAccessManagement) ListPolicies() []*iam_pb.Policy {
iam.m.RLock()
defer iam.m.RUnlock()
var policies []*iam_pb.Policy
for _, p := range iam.policies {
policies = append(policies, p)
}
return policies
}

View File

@@ -13,6 +13,9 @@ import (
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
jsonpb "google.golang.org/protobuf/encoding/protojson" jsonpb "google.golang.org/protobuf/encoding/protojson"
_ "github.com/seaweedfs/seaweedfs/weed/credential/filer_etc"
_ "github.com/seaweedfs/seaweedfs/weed/credential/memory"
) )
func TestIdentityListFileFormat(t *testing.T) { func TestIdentityListFileFormat(t *testing.T) {
@@ -742,3 +745,48 @@ func TestSignatureVerificationDoesNotCheckPermissions(t *testing.T) {
t.Log("Signature verification no longer checks for Write permission") t.Log("Signature verification no longer checks for Write permission")
t.Log("This allows list-only and read-only users to authenticate via AWS Signature V4") t.Log("This allows list-only and read-only users to authenticate via AWS Signature V4")
} }
func TestStaticIdentityProtection(t *testing.T) {
iam := NewIdentityAccessManagement(&S3ApiServerOption{})
// Add a static identity
staticIdent := &Identity{
Name: "static-user",
IsStatic: true,
}
iam.m.Lock()
if iam.nameToIdentity == nil {
iam.nameToIdentity = make(map[string]*Identity)
}
iam.identities = append(iam.identities, staticIdent)
iam.nameToIdentity[staticIdent.Name] = staticIdent
iam.m.Unlock()
// Add a dynamic identity
dynamicIdent := &Identity{
Name: "dynamic-user",
IsStatic: false,
}
iam.m.Lock()
iam.identities = append(iam.identities, dynamicIdent)
iam.nameToIdentity[dynamicIdent.Name] = dynamicIdent
iam.m.Unlock()
// Try to remove static identity
iam.RemoveIdentity("static-user")
// Verify static identity still exists
iam.m.RLock()
_, ok := iam.nameToIdentity["static-user"]
iam.m.RUnlock()
assert.True(t, ok, "Static identity should not be removed")
// Try to remove dynamic identity
iam.RemoveIdentity("dynamic-user")
// Verify dynamic identity is removed
iam.m.RLock()
_, ok = iam.nameToIdentity["dynamic-user"]
iam.m.RUnlock()
assert.False(t, ok, "Dynamic identity should have been removed")
}

View File

@@ -83,6 +83,16 @@ func (bpe *BucketPolicyEngine) HasPolicyForBucket(bucket string) bool {
return bpe.engine.HasPolicyForBucket(bucket) return bpe.engine.HasPolicyForBucket(bucket)
} }
// GetBucketPolicy gets the policy for a bucket
func (bpe *BucketPolicyEngine) GetBucketPolicy(bucket string) (*policy_engine.PolicyDocument, error) {
return bpe.engine.GetBucketPolicy(bucket)
}
// ListBucketPolicies returns all buckets that have policies
func (bpe *BucketPolicyEngine) ListBucketPolicies() []string {
return bpe.engine.GetAllBucketsWithPolicies()
}
// EvaluatePolicy evaluates whether an action is allowed by bucket policy // EvaluatePolicy evaluates whether an action is allowed by bucket policy
// //
// Parameters: // Parameters:

View File

@@ -38,13 +38,15 @@ type EmbeddedIamApi struct {
getS3ApiConfigurationFunc func(*iam_pb.S3ApiConfiguration) error getS3ApiConfigurationFunc func(*iam_pb.S3ApiConfiguration) error
putS3ApiConfigurationFunc func(*iam_pb.S3ApiConfiguration) error putS3ApiConfigurationFunc func(*iam_pb.S3ApiConfiguration) error
reloadConfigurationFunc func() error reloadConfigurationFunc func() error
readOnly bool
} }
// NewEmbeddedIamApi creates a new embedded IAM API handler. // NewEmbeddedIamApi creates a new embedded IAM API handler.
func NewEmbeddedIamApi(credentialManager *credential.CredentialManager, iam *IdentityAccessManagement) *EmbeddedIamApi { func NewEmbeddedIamApi(credentialManager *credential.CredentialManager, iam *IdentityAccessManagement, readOnly bool) *EmbeddedIamApi {
return &EmbeddedIamApi{ return &EmbeddedIamApi{
credentialManager: credentialManager, credentialManager: credentialManager,
iam: iam, iam: iam,
readOnly: readOnly,
} }
} }
@@ -160,6 +162,8 @@ func (e *EmbeddedIamApi) writeIamErrorResponse(w http.ResponseWriter, r *http.Re
s3err.WriteXMLResponse(w, r, http.StatusConflict, errorResp) s3err.WriteXMLResponse(w, r, http.StatusConflict, errorResp)
case iam.ErrCodeMalformedPolicyDocumentException, iam.ErrCodeInvalidInputException: case iam.ErrCodeMalformedPolicyDocumentException, iam.ErrCodeInvalidInputException:
s3err.WriteXMLResponse(w, r, http.StatusBadRequest, errorResp) s3err.WriteXMLResponse(w, r, http.StatusBadRequest, errorResp)
case "AccessDenied", iam.ErrCodeLimitExceededException:
s3err.WriteXMLResponse(w, r, http.StatusForbidden, errorResp)
case iam.ErrCodeServiceFailureException: case iam.ErrCodeServiceFailureException:
s3err.WriteXMLResponse(w, r, http.StatusInternalServerError, internalErrorResponse) s3err.WriteXMLResponse(w, r, http.StatusInternalServerError, internalErrorResponse)
default: default:
@@ -190,6 +194,7 @@ func (e *EmbeddedIamApi) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration)
// ReloadConfiguration reloads the IAM configuration from the credential manager. // ReloadConfiguration reloads the IAM configuration from the credential manager.
func (e *EmbeddedIamApi) ReloadConfiguration() error { func (e *EmbeddedIamApi) ReloadConfiguration() error {
glog.V(4).Infof("IAM: reloading configuration via EmbeddedIamApi")
if e.reloadConfigurationFunc != nil { if e.reloadConfigurationFunc != nil {
return e.reloadConfigurationFunc() return e.reloadConfigurationFunc()
} }
@@ -1043,11 +1048,22 @@ func (e *EmbeddedIamApi) AuthIam(f http.HandlerFunc, _ Action) http.HandlerFunc
} }
// ExecuteAction executes an IAM action with the given values. // ExecuteAction executes an IAM action with the given values.
func (e *EmbeddedIamApi) ExecuteAction(values url.Values) (interface{}, *iamError) { // If skipPersist is true, the changed configuration is not saved to the persistent store.
func (e *EmbeddedIamApi) ExecuteAction(values url.Values, skipPersist bool) (interface{}, *iamError) {
// Lock to prevent concurrent read-modify-write race conditions // Lock to prevent concurrent read-modify-write race conditions
e.policyLock.Lock() e.policyLock.Lock()
defer e.policyLock.Unlock() defer e.policyLock.Unlock()
action := values.Get("Action")
if e.readOnly {
switch action {
case "ListUsers", "ListAccessKeys", "GetUser", "GetUserPolicy", "ListServiceAccounts", "GetServiceAccount":
// Allowed read-only actions
default:
return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrAccessDenied).Code, Error: fmt.Errorf("IAM write operations are disabled on this server")}
}
}
s3cfg := &iam_pb.S3ApiConfiguration{} s3cfg := &iam_pb.S3ApiConfiguration{}
if err := e.GetS3ApiConfiguration(s3cfg); err != nil && !errors.Is(err, filer_pb.ErrNotFound) { if err := e.GetS3ApiConfiguration(s3cfg); err != nil && !errors.Is(err, filer_pb.ErrNotFound) {
return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrInternalError).Code, Error: fmt.Errorf("failed to get s3 api configuration: %v", err)} return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrInternalError).Code, Error: fmt.Errorf("failed to get s3 api configuration: %v", err)}
@@ -1165,9 +1181,11 @@ func (e *EmbeddedIamApi) ExecuteAction(values url.Values) (interface{}, *iamErro
return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrNotImplemented).Code, Error: errors.New(s3err.GetAPIError(s3err.ErrNotImplemented).Description)} return nil, &iamError{Code: s3err.GetAPIError(s3err.ErrNotImplemented).Code, Error: errors.New(s3err.GetAPIError(s3err.ErrNotImplemented).Description)}
} }
if changed { if changed {
if err := e.PutS3ApiConfiguration(s3cfg); err != nil { if !skipPersist {
iamErr = &iamError{Code: iam.ErrCodeServiceFailureException, Error: err} if err := e.PutS3ApiConfiguration(s3cfg); err != nil {
return nil, iamErr iamErr = &iamError{Code: iam.ErrCodeServiceFailureException, Error: err}
return nil, iamErr
}
} }
// Reload in-memory identity maps so subsequent LookupByAccessKey calls // Reload in-memory identity maps so subsequent LookupByAccessKey calls
// can see newly created or deleted keys immediately // can see newly created or deleted keys immediately
@@ -1196,7 +1214,7 @@ func (e *EmbeddedIamApi) DoActions(w http.ResponseWriter, r *http.Request) {
values.Set("CreatedBy", createdBy) values.Set("CreatedBy", createdBy)
} }
response, iamErr := e.ExecuteAction(values) response, iamErr := e.ExecuteAction(values, false)
if iamErr != nil { if iamErr != nil {
e.writeIamErrorResponse(w, r, iamErr) e.writeIamErrorResponse(w, r, iamErr)
return return

View File

@@ -87,7 +87,19 @@ func (e *EmbeddedIamApiForTest) DoActions(w http.ResponseWriter, r *http.Request
var iamErr *iamError var iamErr *iamError
changed := true changed := true
switch r.Form.Get("Action") { action := r.Form.Get("Action")
if e.readOnly {
switch action {
case "ListUsers", "ListAccessKeys", "GetUser", "GetUserPolicy", "ListServiceAccounts", "GetServiceAccount":
// Allowed read-only actions
default:
e.writeIamErrorResponse(w, r, &iamError{Code: s3err.GetAPIError(s3err.ErrAccessDenied).Code, Error: fmt.Errorf("IAM write operations are disabled on this server")})
return
}
}
switch action {
case "ListUsers": case "ListUsers":
response = e.ListUsers(s3cfg, values) response = e.ListUsers(s3cfg, values)
changed = false changed = false
@@ -1691,7 +1703,7 @@ func TestEmbeddedIamExecuteAction(t *testing.T) {
vals.Set("Action", "CreateUser") vals.Set("Action", "CreateUser")
vals.Set("UserName", "ExecuteActionUser") vals.Set("UserName", "ExecuteActionUser")
resp, iamErr := api.ExecuteAction(vals) resp, iamErr := api.ExecuteAction(vals, false)
assert.Nil(t, iamErr) assert.Nil(t, iamErr)
// Verify response type // Verify response type
@@ -1703,3 +1715,33 @@ func TestEmbeddedIamExecuteAction(t *testing.T) {
assert.Len(t, api.mockConfig.Identities, 1) assert.Len(t, api.mockConfig.Identities, 1)
assert.Equal(t, "ExecuteActionUser", api.mockConfig.Identities[0].Name) assert.Equal(t, "ExecuteActionUser", api.mockConfig.Identities[0].Name)
} }
// TestEmbeddedIamReadOnly tests that write operations are blocked when readOnly is true
func TestEmbeddedIamReadOnly(t *testing.T) {
api := NewEmbeddedIamApiForTest()
api.readOnly = true
// Try CreateUser (Write)
userName := aws.String("ReadOnlyUser")
params := &iam.CreateUserInput{UserName: userName}
req, _ := iam.New(session.New()).CreateUserRequest(params)
_ = req.Build()
response, err := executeEmbeddedIamRequest(api, req.HTTPRequest, nil)
assert.NoError(t, err)
assert.Equal(t, http.StatusForbidden, response.Code)
code, msg := extractEmbeddedIamErrorCodeAndMessage(response)
assert.Equal(t, "AccessDenied", code)
assert.Contains(t, msg, "IAM write operations are disabled")
// Try ListUsers (Read) - Should succeed
paramsList := &iam.ListUsersInput{}
reqList, _ := iam.New(session.New()).ListUsersRequest(paramsList)
_ = reqList.Build()
outList := iamListUsersResponse{}
responseList, err := executeEmbeddedIamRequest(api, reqList.HTTPRequest, &outList)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, responseList.Code)
}

View File

@@ -52,11 +52,14 @@ type S3ApiServerOption struct {
ConcurrentUploadLimit int64 ConcurrentUploadLimit int64
ConcurrentFileUploadLimit int64 ConcurrentFileUploadLimit int64
EnableIam bool // Enable embedded IAM API on the same port EnableIam bool // Enable embedded IAM API on the same port
IamReadOnly bool // Disable IAM write operations on this server
Cipher bool // encrypt data on volume servers Cipher bool // encrypt data on volume servers
BindIp string
GrpcPort int
} }
type S3ApiServer struct { type S3ApiServer struct {
s3_pb.UnimplementedSeaweedS3Server s3_pb.UnimplementedSeaweedS3IamCacheServer
option *S3ApiServerOption option *S3ApiServerOption
iam *IdentityAccessManagement iam *IdentityAccessManagement
iamIntegration *S3IAMIntegration // Advanced IAM integration for JWT authentication iamIntegration *S3IAMIntegration // Advanced IAM integration for JWT authentication
@@ -114,13 +117,17 @@ func NewS3ApiServerWithStore(router *mux.Router, option *S3ApiServerOption, expl
// Uses the battle-tested vidMap with filer-based lookups // Uses the battle-tested vidMap with filer-based lookups
// Supports multiple filer addresses with automatic failover for high availability // Supports multiple filer addresses with automatic failover for high availability
var filerClient *wdclient.FilerClient var filerClient *wdclient.FilerClient
if len(option.Masters) > 0 && option.FilerGroup != "" { if len(option.Masters) > 0 {
// Enable filer discovery via master // Enable filer discovery via master
masterMap := make(map[string]pb.ServerAddress) masterMap := make(map[string]pb.ServerAddress)
for i, addr := range option.Masters { for i, addr := range option.Masters {
masterMap[fmt.Sprintf("master%d", i)] = addr masterMap[fmt.Sprintf("master%d", i)] = addr
} }
masterClient := wdclient.NewMasterClient(option.GrpcDialOption, option.FilerGroup, cluster.S3Type, "", "", "", *pb.NewServiceDiscoveryFromMap(masterMap)) clientHost := option.BindIp
if clientHost == "0.0.0.0" || clientHost == "" {
clientHost = util.DetectedHostAddress()
}
masterClient := wdclient.NewMasterClient(option.GrpcDialOption, option.FilerGroup, cluster.S3Type, pb.ServerAddress(util.JoinHostPort(clientHost, option.GrpcPort)), "", "", *pb.NewServiceDiscoveryFromMap(masterMap))
// Start the master client connection loop - required for GetMaster() to work // Start the master client connection loop - required for GetMaster() to work
go masterClient.KeepConnectedToMaster(context.Background()) go masterClient.KeepConnectedToMaster(context.Background())
@@ -203,8 +210,12 @@ func NewS3ApiServerWithStore(router *mux.Router, option *S3ApiServerOption, expl
// Initialize embedded IAM API if enabled // Initialize embedded IAM API if enabled
if option.EnableIam { if option.EnableIam {
s3ApiServer.embeddedIam = NewEmbeddedIamApi(s3ApiServer.credentialManager, iam) s3ApiServer.embeddedIam = NewEmbeddedIamApi(s3ApiServer.credentialManager, iam, option.IamReadOnly)
glog.V(1).Infof("Embedded IAM API initialized (use -iam=false to disable)") if option.IamReadOnly {
glog.V(1).Infof("Embedded IAM API initialized in read-only mode (use -s3.iam.readOnly=false to enable write operations)")
} else {
glog.V(1).Infof("Embedded IAM API initialized in writable mode (WARNING: updates will not be propagated to other S3 servers)")
}
} }
if option.Config != "" { if option.Config != "" {

View File

@@ -4,341 +4,95 @@ import (
"context" "context"
"fmt" "fmt"
"net/url"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb" "github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
) )
func (s3a *S3ApiServer) executeAction(values url.Values) (interface{}, error) { // SeaweedS3IamCacheServer Implementation
if s3a.embeddedIam == nil { // This interface is dedicated to UNIDIRECTIONAL updates from Filer to S3 Server.
return nil, fmt.Errorf("embedded iam is disabled") // S3 Server acts purely as a cache.
}
response, iamErr := s3a.embeddedIam.ExecuteAction(values)
if iamErr != nil {
return nil, fmt.Errorf("IAM error: %s - %v", iamErr.Code, iamErr.Error)
}
return response, nil
}
func (s3a *S3ApiServer) ListUsers(ctx context.Context, req *iam_pb.ListUsersRequest) (*iam_pb.ListUsersResponse, error) { func (s3a *S3ApiServer) PutIdentity(ctx context.Context, req *iam_pb.PutIdentityRequest) (*iam_pb.PutIdentityResponse, error) {
values := url.Values{} if req.Identity == nil {
values.Set("Action", "ListUsers") return nil, fmt.Errorf("identity is required")
resp, err := s3a.executeAction(values) }
if err != nil { // Direct in-memory cache update
glog.V(1).Infof("IAM: received identity update for %s", req.Identity.Name)
if err := s3a.iam.UpsertIdentity(req.Identity); err != nil {
glog.Errorf("failed to update identity cache for %s: %v", req.Identity.Name, err)
return nil, err return nil, err
} }
iamResp, ok := resp.(iamListUsersResponse) return &iam_pb.PutIdentityResponse{}, nil
if !ok {
return nil, fmt.Errorf("unexpected IAM ListUsers response type %T", resp)
}
var usernames []string
for _, user := range iamResp.ListUsersResult.Users {
if user != nil && user.UserName != nil {
usernames = append(usernames, *user.UserName)
}
}
return &iam_pb.ListUsersResponse{Usernames: usernames}, nil
} }
func (s3a *S3ApiServer) CreateUser(ctx context.Context, req *iam_pb.CreateUserRequest) (*iam_pb.CreateUserResponse, error) { func (s3a *S3ApiServer) RemoveIdentity(ctx context.Context, req *iam_pb.RemoveIdentityRequest) (*iam_pb.RemoveIdentityResponse, error) {
if req.Identity == nil || req.Identity.Name == "" {
return nil, fmt.Errorf("username name is required")
}
values := url.Values{}
values.Set("Action", "CreateUser")
values.Set("UserName", req.Identity.Name)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.CreateUserResponse{}, nil
}
func (s3a *S3ApiServer) GetUser(ctx context.Context, req *iam_pb.GetUserRequest) (*iam_pb.GetUserResponse, error) {
if req.Username == "" { if req.Username == "" {
return nil, fmt.Errorf("username is required") return nil, fmt.Errorf("username is required")
} }
values := url.Values{} // Direct in-memory cache update
values.Set("Action", "GetUser") glog.V(1).Infof("IAM: received identity removal for %s", req.Username)
values.Set("UserName", req.Username) s3a.iam.RemoveIdentity(req.Username)
resp, err := s3a.executeAction(values) return &iam_pb.RemoveIdentityResponse{}, nil
}
func (s3a *S3ApiServer) PutPolicy(ctx context.Context, req *iam_pb.PutPolicyRequest) (*iam_pb.PutPolicyResponse, error) {
if req.Name == "" {
return nil, fmt.Errorf("policy name is required")
}
// Update IAM policy cache
glog.V(1).Infof("IAM: received policy update for %s", req.Name)
if s3a.iam != nil {
if err := s3a.iam.PutPolicy(req.Name, req.Content); err != nil {
glog.Errorf("failed to update policy cache for %s: %v", req.Name, err)
return nil, err
}
}
return &iam_pb.PutPolicyResponse{}, nil
}
func (s3a *S3ApiServer) DeletePolicy(ctx context.Context, req *iam_pb.DeletePolicyRequest) (*iam_pb.DeletePolicyResponse, error) {
if req.Name == "" {
return nil, fmt.Errorf("policy name is required")
}
// Delete from IAM policy cache
glog.V(1).Infof("IAM: received policy removal for %s", req.Name)
if s3a.iam != nil {
if err := s3a.iam.DeletePolicy(req.Name); err != nil {
glog.Errorf("failed to delete policy cache for %s: %v", req.Name, err)
return nil, err
}
}
return &iam_pb.DeletePolicyResponse{}, nil
}
func (s3a *S3ApiServer) GetPolicy(ctx context.Context, req *iam_pb.GetPolicyRequest) (*iam_pb.GetPolicyResponse, error) {
if req.Name == "" {
return nil, fmt.Errorf("policy name is required")
}
if s3a.iam == nil {
return &iam_pb.GetPolicyResponse{}, nil
}
policy, err := s3a.iam.GetPolicy(req.Name)
if err != nil { if err != nil {
return nil, err return &iam_pb.GetPolicyResponse{}, nil // Not found is fine for cache
} }
iamResp, ok := resp.(iamGetUserResponse) return &iam_pb.GetPolicyResponse{
if !ok { Name: policy.Name,
return nil, fmt.Errorf("unexpected IAM GetUser response type %T", resp) Content: policy.Content,
}
var username string
if iamResp.GetUserResult.User.UserName != nil {
username = *iamResp.GetUserResult.User.UserName
}
return &iam_pb.GetUserResponse{
Identity: &iam_pb.Identity{
Name: username,
},
}, nil }, nil
} }
func (s3a *S3ApiServer) UpdateUser(ctx context.Context, req *iam_pb.UpdateUserRequest) (*iam_pb.UpdateUserResponse, error) { func (s3a *S3ApiServer) ListPolicies(ctx context.Context, req *iam_pb.ListPoliciesRequest) (*iam_pb.ListPoliciesResponse, error) {
if req.Username == "" { resp := &iam_pb.ListPoliciesResponse{}
return nil, fmt.Errorf("username is required") if s3a.iam == nil {
return resp, nil
} }
values := url.Values{} policies := s3a.iam.ListPolicies()
values.Set("Action", "UpdateUser") for _, policy := range policies {
values.Set("UserName", req.Username) resp.Policies = append(resp.Policies, policy)
// UpdateUser in DoActions expects "NewUserName" if renaming, but CreateUser just takes UserName.
// Looking at s3api_embedded_iam.go, UpdateUser uses "NewUserName" to change name.
if req.Identity != nil && req.Identity.Name != "" {
values.Set("NewUserName", req.Identity.Name)
} }
_, err := s3a.executeAction(values) return resp, nil
if err != nil {
return nil, err
}
return &iam_pb.UpdateUserResponse{}, nil
}
func (s3a *S3ApiServer) DeleteUser(ctx context.Context, req *iam_pb.DeleteUserRequest) (*iam_pb.DeleteUserResponse, error) {
if req.Username == "" {
return nil, fmt.Errorf("username is required")
}
values := url.Values{}
values.Set("Action", "DeleteUser")
values.Set("UserName", req.Username)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.DeleteUserResponse{}, nil
}
func (s3a *S3ApiServer) ListAccessKeys(ctx context.Context, req *iam_pb.ListAccessKeysRequest) (*iam_pb.ListAccessKeysResponse, error) {
if req.Username == "" {
return nil, fmt.Errorf("username is required")
}
values := url.Values{}
values.Set("Action", "ListAccessKeys")
values.Set("UserName", req.Username)
resp, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
iamResp, ok := resp.(iamListAccessKeysResponse)
if !ok {
return nil, fmt.Errorf("unexpected IAM ListAccessKeys response type %T", resp)
}
var accessKeys []*iam_pb.Credential
for _, meta := range iamResp.ListAccessKeysResult.AccessKeyMetadata {
if meta != nil && meta.AccessKeyId != nil && meta.Status != nil {
accessKeys = append(accessKeys, &iam_pb.Credential{
AccessKey: *meta.AccessKeyId,
Status: *meta.Status,
})
}
}
return &iam_pb.ListAccessKeysResponse{AccessKeys: accessKeys}, nil
}
func (s3a *S3ApiServer) CreateAccessKey(ctx context.Context, req *iam_pb.CreateAccessKeyRequest) (*iam_pb.CreateAccessKeyResponse, error) {
if req.Username == "" {
return nil, fmt.Errorf("username is required")
}
values := url.Values{}
values.Set("Action", "CreateAccessKey")
values.Set("UserName", req.Username)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.CreateAccessKeyResponse{}, nil
}
func (s3a *S3ApiServer) DeleteAccessKey(ctx context.Context, req *iam_pb.DeleteAccessKeyRequest) (*iam_pb.DeleteAccessKeyResponse, error) {
if req.Username == "" {
return nil, fmt.Errorf("username is required")
}
if req.AccessKey == "" {
return nil, fmt.Errorf("access key is required")
}
values := url.Values{}
values.Set("Action", "DeleteAccessKey")
values.Set("UserName", req.Username)
values.Set("AccessKeyId", req.AccessKey)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.DeleteAccessKeyResponse{}, nil
}
func (s3a *S3ApiServer) PutUserPolicy(ctx context.Context, req *iam_pb.PutUserPolicyRequest) (*iam_pb.PutUserPolicyResponse, error) {
if req.Username == "" {
return nil, fmt.Errorf("username is required")
}
if req.PolicyName == "" {
return nil, fmt.Errorf("policy name is required")
}
values := url.Values{}
values.Set("Action", "PutUserPolicy")
values.Set("UserName", req.Username)
values.Set("PolicyName", req.PolicyName)
values.Set("PolicyDocument", req.PolicyDocument)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.PutUserPolicyResponse{}, nil
}
func (s3a *S3ApiServer) GetUserPolicy(ctx context.Context, req *iam_pb.GetUserPolicyRequest) (*iam_pb.GetUserPolicyResponse, error) {
if req.Username == "" {
return nil, fmt.Errorf("username is required")
}
if req.PolicyName == "" {
return nil, fmt.Errorf("policy name is required")
}
values := url.Values{}
values.Set("Action", "GetUserPolicy")
values.Set("UserName", req.Username)
values.Set("PolicyName", req.PolicyName)
resp, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
iamResp, ok := resp.(iamGetUserPolicyResponse)
if !ok {
return nil, fmt.Errorf("unexpected IAM GetUserPolicy response type %T", resp)
}
return &iam_pb.GetUserPolicyResponse{
Username: iamResp.GetUserPolicyResult.UserName,
PolicyName: iamResp.GetUserPolicyResult.PolicyName,
PolicyDocument: iamResp.GetUserPolicyResult.PolicyDocument,
}, nil
}
func (s3a *S3ApiServer) DeleteUserPolicy(ctx context.Context, req *iam_pb.DeleteUserPolicyRequest) (*iam_pb.DeleteUserPolicyResponse, error) {
if req.Username == "" {
return nil, fmt.Errorf("username is required")
}
if req.PolicyName == "" {
return nil, fmt.Errorf("policy name is required")
}
values := url.Values{}
values.Set("Action", "DeleteUserPolicy")
values.Set("UserName", req.Username)
values.Set("PolicyName", req.PolicyName)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.DeleteUserPolicyResponse{}, nil
}
func (s3a *S3ApiServer) ListServiceAccounts(ctx context.Context, req *iam_pb.ListServiceAccountsRequest) (*iam_pb.ListServiceAccountsResponse, error) {
values := url.Values{}
values.Set("Action", "ListServiceAccounts")
resp, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
iamResp, ok := resp.(iamListServiceAccountsResponse)
if !ok {
return nil, fmt.Errorf("unexpected IAM ListServiceAccounts response type %T", resp)
}
var serviceAccounts []*iam_pb.ServiceAccount
for _, sa := range iamResp.ListServiceAccountsResult.ServiceAccounts {
if sa != nil {
serviceAccounts = append(serviceAccounts, &iam_pb.ServiceAccount{
Id: sa.ServiceAccountId,
ParentUser: sa.ParentUser,
Description: sa.Description,
Credential: &iam_pb.Credential{
AccessKey: sa.AccessKeyId,
Status: sa.Status,
},
})
}
}
return &iam_pb.ListServiceAccountsResponse{ServiceAccounts: serviceAccounts}, nil
}
func (s3a *S3ApiServer) CreateServiceAccount(ctx context.Context, req *iam_pb.CreateServiceAccountRequest) (*iam_pb.CreateServiceAccountResponse, error) {
if req.ServiceAccount == nil || req.ServiceAccount.CreatedBy == "" {
return nil, fmt.Errorf("service account owner is required")
}
values := url.Values{}
values.Set("Action", "CreateServiceAccount")
values.Set("CreatedBy", req.ServiceAccount.CreatedBy)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.CreateServiceAccountResponse{}, nil
}
func (s3a *S3ApiServer) UpdateServiceAccount(ctx context.Context, req *iam_pb.UpdateServiceAccountRequest) (*iam_pb.UpdateServiceAccountResponse, error) {
if req.Id == "" {
return nil, fmt.Errorf("service account id is required")
}
values := url.Values{}
values.Set("Action", "UpdateServiceAccount")
values.Set("ServiceAccountId", req.Id)
if req.ServiceAccount != nil && req.ServiceAccount.Disabled {
values.Set("Status", "Inactive")
}
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.UpdateServiceAccountResponse{}, nil
}
func (s3a *S3ApiServer) DeleteServiceAccount(ctx context.Context, req *iam_pb.DeleteServiceAccountRequest) (*iam_pb.DeleteServiceAccountResponse, error) {
if req.Id == "" {
return nil, fmt.Errorf("service account id is required")
}
values := url.Values{}
values.Set("Action", "DeleteServiceAccount")
values.Set("ServiceAccountId", req.Id)
_, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
return &iam_pb.DeleteServiceAccountResponse{}, nil
}
func (s3a *S3ApiServer) GetServiceAccount(ctx context.Context, req *iam_pb.GetServiceAccountRequest) (*iam_pb.GetServiceAccountResponse, error) {
if req.Id == "" {
return nil, fmt.Errorf("service account id is required")
}
values := url.Values{}
values.Set("Action", "GetServiceAccount")
values.Set("ServiceAccountId", req.Id)
resp, err := s3a.executeAction(values)
if err != nil {
return nil, err
}
iamResp, ok := resp.(iamGetServiceAccountResponse)
if !ok {
return nil, fmt.Errorf("unexpected IAM GetServiceAccount response type %T", resp)
}
var serviceAccount *iam_pb.ServiceAccount
sa := iamResp.GetServiceAccountResult.ServiceAccount
serviceAccount = &iam_pb.ServiceAccount{
Id: sa.ServiceAccountId,
ParentUser: sa.ParentUser,
Description: sa.Description,
Credential: &iam_pb.Credential{
AccessKey: sa.AccessKeyId,
Status: sa.Status,
},
}
return &iam_pb.GetServiceAccountResponse{
ServiceAccount: serviceAccount,
}, nil
} }

View File

@@ -31,7 +31,7 @@ func setupRoutingTestServer(t *testing.T) *S3ApiServer {
option: opt, option: opt,
iam: iam, iam: iam,
credentialManager: iam.credentialManager, credentialManager: iam.credentialManager,
embeddedIam: NewEmbeddedIamApi(iam.credentialManager, iam), embeddedIam: NewEmbeddedIamApi(iam.credentialManager, iam, false),
stsHandlers: &STSHandlers{}, stsHandlers: &STSHandlers{},
} }

View File

@@ -256,6 +256,10 @@ func NewFilerServer(defaultMux, readonlyMux *http.ServeMux, option *FilerOption)
fs.filer.Dlm.LockRing.SetTakeSnapshotCallback(fs.OnDlmChangeSnapshot) fs.filer.Dlm.LockRing.SetTakeSnapshotCallback(fs.OnDlmChangeSnapshot)
if fs.CredentialManager != nil {
fs.CredentialManager.SetMasterClient(fs.filer.MasterClient, fs.grpcDialOption)
}
return fs, nil return fs, nil
} }

View File

@@ -73,7 +73,7 @@ func (s *IamGrpcServer) CreateUser(ctx context.Context, req *iam_pb.CreateUserRe
if req == nil || req.Identity == nil { if req == nil || req.Identity == nil {
return nil, status.Errorf(codes.InvalidArgument, "identity is required") return nil, status.Errorf(codes.InvalidArgument, "identity is required")
} }
glog.V(4).Infof("CreateUser: %s", req.Identity.Name) glog.V(4).Infof("IAM: Filer.CreateUser %s", req.Identity.Name)
if s.credentialManager == nil { if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured") return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
@@ -113,10 +113,10 @@ func (s *IamGrpcServer) GetUser(ctx context.Context, req *iam_pb.GetUserRequest)
} }
func (s *IamGrpcServer) UpdateUser(ctx context.Context, req *iam_pb.UpdateUserRequest) (*iam_pb.UpdateUserResponse, error) { func (s *IamGrpcServer) UpdateUser(ctx context.Context, req *iam_pb.UpdateUserRequest) (*iam_pb.UpdateUserResponse, error) {
glog.V(4).Infof("UpdateUser: %s", req.Username)
if req == nil || req.Identity == nil { if req == nil || req.Identity == nil {
return nil, status.Errorf(codes.InvalidArgument, "identity is required") return nil, status.Errorf(codes.InvalidArgument, "identity is required")
} }
glog.V(4).Infof("IAM: Filer.UpdateUser %s", req.Username)
if s.credentialManager == nil { if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured") return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
@@ -135,7 +135,7 @@ func (s *IamGrpcServer) UpdateUser(ctx context.Context, req *iam_pb.UpdateUserRe
} }
func (s *IamGrpcServer) DeleteUser(ctx context.Context, req *iam_pb.DeleteUserRequest) (*iam_pb.DeleteUserResponse, error) { func (s *IamGrpcServer) DeleteUser(ctx context.Context, req *iam_pb.DeleteUserRequest) (*iam_pb.DeleteUserResponse, error) {
glog.V(4).Infof("DeleteUser: %s", req.Username) glog.V(4).Infof("IAM: Filer.DeleteUser %s", req.Username)
if s.credentialManager == nil { if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured") return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
@@ -243,7 +243,7 @@ func (s *IamGrpcServer) GetUserByAccessKey(ctx context.Context, req *iam_pb.GetU
// Policy Management // Policy Management
func (s *IamGrpcServer) PutPolicy(ctx context.Context, req *iam_pb.PutPolicyRequest) (*iam_pb.PutPolicyResponse, error) { func (s *IamGrpcServer) PutPolicy(ctx context.Context, req *iam_pb.PutPolicyRequest) (*iam_pb.PutPolicyResponse, error) {
glog.V(4).Infof("PutPolicy: %s", req.Name) glog.V(4).Infof("IAM: Filer.PutPolicy %s", req.Name)
if s.credentialManager == nil { if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured") return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")

View File

@@ -276,6 +276,7 @@ func (ms *MasterServer) KeepConnected(stream master_pb.Seaweed_KeepConnectedServ
clientName, messageChan := ms.addClient(req.FilerGroup, req.ClientType, peerAddress) clientName, messageChan := ms.addClient(req.FilerGroup, req.ClientType, peerAddress)
for _, update := range ms.Cluster.AddClusterNode(req.FilerGroup, req.ClientType, cluster.DataCenter(req.DataCenter), cluster.Rack(req.Rack), peerAddress, req.Version) { for _, update := range ms.Cluster.AddClusterNode(req.FilerGroup, req.ClientType, cluster.DataCenter(req.DataCenter), cluster.Rack(req.Rack), peerAddress, req.Version) {
glog.V(1).Infof("Cluster: %s node %s added to group '%s'", req.ClientType, peerAddress, req.FilerGroup)
ms.broadcastToClients(update) ms.broadcastToClients(update)
} }