fix(shell): attach admin JWT for filer IAM gRPC calls (#9536)

When jwt.filer_signing.key is set, the filer's IamGrpcServer requires
a Bearer token on every IAM RPC. The shell's s3.* IAM commands dialed
without that header and failed with Unauthenticated. Route them through
a small helper that mints a token from the same key viper-loaded from
security.toml and appends it as outgoing metadata, matching the credential
grpc_store pattern.
This commit is contained in:
Chris Lu authored and GitHub committed 2026-05-18 13:42:32 -07:00
1 parent 3d872a1416
commit 37e6263efe
33 files changed
+121 -284

No files matched your search

+2 -8
View File
@@ -5,12 +5,9 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/iam"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -69,10 +66,7 @@ func (c *commandS3AccessKeyCreate) Do(args []string, commandEnv *CommandEnv, wri
return fmt.Errorf("both -access_key and -secret_key must be provided together, or omit both to auto-generate")
}
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
_, err := client.CreateAccessKey(ctx, &iam_pb.CreateAccessKeyRequest{
Username: *user,
Credential: &iam_pb.Credential{
@@ -82,7 +76,7 @@ func (c *commandS3AccessKeyCreate) Do(args []string, commandEnv *CommandEnv, wri
},
})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -8
View File
@@ -5,11 +5,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -49,16 +46,13 @@ func (c *commandS3AccessKeyDelete) Do(args []string, commandEnv *CommandEnv, wri
return fmt.Errorf("-access_key is required")
}
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
_, err := client.DeleteAccessKey(ctx, &iam_pb.DeleteAccessKeyRequest{
Username: *user,
AccessKey: *accessKey,
})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"fmt"
"io"
"text/tabwriter"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -46,11 +43,7 @@ func (c *commandS3AccessKeyList) Do(args []string, commandEnv *CommandEnv, write
return fmt.Errorf("-user is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: *user})
if err != nil {
return err
@@ -71,5 +64,5 @@ func (c *commandS3AccessKeyList) Do(args []string, commandEnv *CommandEnv, write
fmt.Fprintf(tw, "%s\t%s\n", cred.AccessKey, st)
}
return tw.Flush()
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -5,12 +5,9 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/iam"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -62,11 +59,7 @@ func (c *commandS3AccessKeyRotate) Do(args []string, commandEnv *CommandEnv, wri
return fmt.Errorf("generate secret key: %v", err)
}
err = pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err = commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
// Create new key first so there's no gap without credentials
_, err := client.CreateAccessKey(ctx, &iam_pb.CreateAccessKeyRequest{
Username: *user,
@@ -90,7 +83,7 @@ func (c *commandS3AccessKeyRotate) Do(args []string, commandEnv *CommandEnv, wri
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -9
View File
@@ -7,11 +7,8 @@ import (
"io"
"sort"
"strings"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -49,11 +46,7 @@ func (c *commandS3AnonymousGet) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-bucket is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: anonymousUserName})
if err != nil {
st, ok := status.FromError(err)
@@ -85,5 +78,5 @@ func (c *commandS3AnonymousGet) Do(args []string, commandEnv *CommandEnv, writer
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -7,11 +7,8 @@ import (
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -39,11 +36,7 @@ func (c *commandS3AnonymousList) HasTag(CommandTag) bool {
}
func (c *commandS3AnonymousList) Do(args []string, commandEnv *CommandEnv, writer io.Writer) error {
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: anonymousUserName})
if err != nil {
st, ok := status.FromError(err)
@@ -87,5 +80,5 @@ func (c *commandS3AnonymousList) Do(args []string, commandEnv *CommandEnv, write
fmt.Fprintf(tw, "%s\t%s\n", b, strings.Join(actions, ", "))
}
return tw.Flush()
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"fmt"
"io"
"strings"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -61,11 +58,7 @@ func (c *commandS3AnonymousSet) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-access is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
// Get or create anonymous user
identity, isNew, err := getOrCreateAnonymousUser(ctx, client)
if err != nil {
@@ -120,7 +113,7 @@ func (c *commandS3AnonymousSet) Do(args []string, commandEnv *CommandEnv, writer
fmt.Fprintf(writer, "Set anonymous access on bucket %q to: %s\n", *bucket, *access)
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
func getOrCreateAnonymousUser(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) (*iam_pb.Identity, bool, error) {
+7 -10
View File
@@ -10,9 +10,7 @@ import (
"strings"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -98,11 +96,10 @@ func (c *commandS3BucketAccess) Do(args []string, commandEnv *CommandEnv, writer
accessStr = strings.Join(normalized, ",")
}
err = pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
err = commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
// Get or create user
identity, isNewUser, getErr := getOrCreateIdentity(client, *userName)
identity, isNewUser, getErr := getOrCreateIdentity(ctx, client, *userName)
if getErr != nil {
return getErr
}
@@ -123,24 +120,24 @@ func (c *commandS3BucketAccess) Do(args []string, commandEnv *CommandEnv, writer
// Save
if isNewUser {
if _, err := client.CreateUser(context.Background(), &iam_pb.CreateUserRequest{Identity: identity}); err != nil {
if _, err := client.CreateUser(ctx, &iam_pb.CreateUserRequest{Identity: identity}); err != nil {
return fmt.Errorf("failed to create user %s: %w", *userName, err)
}
fmt.Fprintf(writer, "Created user %q and set access on bucket %s.\n", *userName, *bucketName)
} else {
if _, err := client.UpdateUser(context.Background(), &iam_pb.UpdateUserRequest{Username: *userName, Identity: identity}); err != nil {
if _, err := client.UpdateUser(ctx, &iam_pb.UpdateUserRequest{Username: *userName, Identity: identity}); err != nil {
return fmt.Errorf("failed to update user %s: %w", *userName, err)
}
fmt.Fprintf(writer, "Updated access for user %q on bucket %s.\n", *userName, *bucketName)
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
return err
}
func getOrCreateIdentity(client iam_pb.SeaweedIdentityAccessManagementClient, userName string) (*iam_pb.Identity, bool, error) {
resp, getErr := client.GetUser(context.Background(), &iam_pb.GetUserRequest{
func getOrCreateIdentity(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient, userName string) (*iam_pb.Identity, bool, error) {
resp, getErr := client.GetUser(ctx, &iam_pb.GetUserRequest{
Username: userName,
})
if getErr == nil && resp.Identity != nil {
+2 -9
View File
@@ -5,11 +5,8 @@ import (
"fmt"
"io"
"text/tabwriter"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -38,11 +35,7 @@ func (c *commandS3ConfigShow) HasTag(CommandTag) bool {
}
func (c *commandS3ConfigShow) Do(args []string, commandEnv *CommandEnv, writer io.Writer) error {
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -112,5 +105,5 @@ func (c *commandS3ConfigShow) Do(args []string, commandEnv *CommandEnv, writer i
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+9 -13
View File
@@ -10,9 +10,7 @@ import (
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/iam"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -70,11 +68,10 @@ func (c *commandS3Configure) Do(args []string, commandEnv *CommandEnv, writer io
var identity *iam_pb.Identity
var isNewUser bool
err = pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
err = commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
// Try to get existing user
resp, getErr := client.GetUser(context.Background(), &iam_pb.GetUserRequest{
resp, getErr := client.GetUser(ctx, &iam_pb.GetUserRequest{
Username: *user,
})
@@ -119,27 +116,26 @@ func (c *commandS3Configure) Do(args []string, commandEnv *CommandEnv, writer io
// Apply changes
if *isDelete && *actions == "" && *accessKey == "" && *buckets == "" && *policies == "" {
// Delete User
_, err := client.DeleteUser(context.Background(), &iam_pb.DeleteUserRequest{Username: *user})
_, err := client.DeleteUser(ctx, &iam_pb.DeleteUserRequest{Username: *user})
return err
} else {
// Create or Update User
if isNewUser {
_, err := client.CreateUser(context.Background(), &iam_pb.CreateUserRequest{Identity: identity})
_, err := client.CreateUser(ctx, &iam_pb.CreateUserRequest{Identity: identity})
return err
} else {
_, err := client.UpdateUser(context.Background(), &iam_pb.UpdateUserRequest{Username: *user, Identity: identity})
_, err := client.UpdateUser(ctx, &iam_pb.UpdateUserRequest{Username: *user, Identity: identity})
return err
}
}
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
return err
}
func (c *commandS3Configure) listConfiguration(commandEnv *CommandEnv, writer io.Writer) error {
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
resp, err := client.GetConfiguration(context.Background(), &iam_pb.GetConfigurationRequest{})
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
}
@@ -148,7 +144,7 @@ func (c *commandS3Configure) listConfiguration(commandEnv *CommandEnv, writer io
fmt.Fprint(writer, buf.String())
fmt.Fprintln(writer)
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
func (c *commandS3Configure) applyChanges(identity *iam_pb.Identity, isNewUser bool, actions, buckets, accessKey, secretKey, policies *string, isDelete *bool, accountId, accountDisplayName, accountEmail *string) error {
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -49,11 +46,7 @@ func (c *commandS3GroupAddUser) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-user is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -91,5 +84,5 @@ func (c *commandS3GroupAddUser) Do(args []string, commandEnv *CommandEnv, writer
}
}
return fmt.Errorf("group %s not found", *group)
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -48,11 +45,7 @@ func (c *commandS3GroupCreate) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-name is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -75,5 +68,5 @@ func (c *commandS3GroupCreate) Do(args []string, commandEnv *CommandEnv, writer
}
return json.NewEncoder(writer).Encode(map[string]string{"group": *name})
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -47,11 +44,7 @@ func (c *commandS3GroupDelete) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-name is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -77,5 +70,5 @@ func (c *commandS3GroupDelete) Do(args []string, commandEnv *CommandEnv, writer
}
}
return fmt.Errorf("group %s not found", *name)
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -4,11 +4,8 @@ import (
"context"
"encoding/json"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -43,11 +40,7 @@ type s3GroupListEntry struct {
}
func (c *commandS3GroupList) Do(args []string, commandEnv *CommandEnv, writer io.Writer) error {
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -74,5 +67,5 @@ func (c *commandS3GroupList) Do(args []string, commandEnv *CommandEnv, writer io
result = []s3GroupListEntry{}
}
return json.NewEncoder(writer).Encode(result)
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -49,11 +46,7 @@ func (c *commandS3GroupRemoveUser) Do(args []string, commandEnv *CommandEnv, wri
return fmt.Errorf("-user is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -78,5 +71,5 @@ func (c *commandS3GroupRemoveUser) Do(args []string, commandEnv *CommandEnv, wri
}
}
return fmt.Errorf("group %s not found", *group)
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -54,11 +51,7 @@ func (c *commandS3GroupShow) Do(args []string, commandEnv *CommandEnv, writer io
return fmt.Errorf("-name is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -87,5 +80,5 @@ func (c *commandS3GroupShow) Do(args []string, commandEnv *CommandEnv, writer io
}
}
return fmt.Errorf("group %s not found", *name)
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+45
View File
@@ -0,0 +1,45 @@
package shell
import (
"context"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/security"
"github.com/seaweedfs/seaweedfs/weed/util"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
// iamRequestTimeout caps every shell-originated IAM gRPC call so the shell
// can't hang on an unresponsive filer.
const iamRequestTimeout = 30 * time.Second
// withIamClient invokes fn against the filer's IAM gRPC service. When
// jwt.filer_signing.key is configured in security.toml, a freshly minted admin
// Bearer token is attached to the outgoing context so the filer's
// IamGrpcServer.checkAdminAuth passes; with no key configured the filer
// accepts unauthenticated calls. The context already has the iamRequestTimeout
// applied — callers can derive child contexts but should not need their own
// timeout boilerplate.
func (ce *CommandEnv) withIamClient(fn func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error) error {
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
ctx, cancel := context.WithTimeout(iamAdminAuthContext(context.Background()), iamRequestTimeout)
defer cancel()
return fn(ctx, iam_pb.NewSeaweedIdentityAccessManagementClient(conn))
}, ce.option.FilerAddress.ToGrpcAddress(), false, ce.option.GrpcDialOption)
}
func iamAdminAuthContext(ctx context.Context) context.Context {
signingKey := util.GetViper().GetString("jwt.filer_signing.key")
if signingKey == "" {
return ctx
}
expiresAfterSec := util.GetViper().GetInt("jwt.filer_signing.expires_after_seconds")
token := security.GenJwtForFilerAdmin(security.SigningKey(signingKey), expiresAfterSec)
if token == "" {
return ctx
}
return metadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+string(token))
}
+2 -9
View File
@@ -6,13 +6,10 @@ import (
"fmt"
"io"
"os"
"time"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/util"
"google.golang.org/grpc"
)
func init() {
@@ -48,11 +45,7 @@ func (c *commandS3IAMExport) Do(args []string, commandEnv *CommandEnv, writer io
return err
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -78,5 +71,5 @@ func (c *commandS3IAMExport) Do(args []string, commandEnv *CommandEnv, writer io
fmt.Fprintf(writer, "Exported IAM configuration to %s\n", outputFile)
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -8
View File
@@ -6,13 +6,10 @@ import (
"fmt"
"io"
"os"
"time"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/util"
"google.golang.org/grpc"
)
func init() {
@@ -67,15 +64,12 @@ func (c *commandS3IAMImport) Do(args []string, commandEnv *CommandEnv, writer io
return fmt.Errorf("parse configuration: %w", err)
}
err = pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err = commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
_, err := client.PutConfiguration(ctx, &iam_pb.PutConfigurationRequest{
Configuration: config,
})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return fmt.Errorf("put IAM configuration: %w", err)
}
+2 -9
View File
@@ -7,13 +7,10 @@ import (
"fmt"
"io"
"os"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
"github.com/seaweedfs/seaweedfs/weed/util"
"google.golang.org/grpc"
)
func init() {
@@ -75,11 +72,7 @@ func (c *commandS3Policy) Do(args []string, commandEnv *CommandEnv, writer io.Wr
return fmt.Errorf("only one of -put, -get, -list, -delete can be specified")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
if *put {
if *name == "" {
return fmt.Errorf("-name is required")
@@ -146,6 +139,6 @@ func (c *commandS3Policy) Do(args []string, commandEnv *CommandEnv, writer io.Wr
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -52,11 +49,7 @@ func (c *commandS3PolicyAttach) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-user is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
// Verify the policy exists
_, err := client.GetPolicy(ctx, &iam_pb.GetPolicyRequest{Name: *policy})
if err != nil {
@@ -89,5 +82,5 @@ func (c *commandS3PolicyAttach) Do(args []string, commandEnv *CommandEnv, writer
}
return json.NewEncoder(writer).Encode(map[string]string{"policy": *policy, "user": *user})
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -50,11 +47,7 @@ func (c *commandS3PolicyDetach) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-user is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: *user})
if err != nil {
return fmt.Errorf("get user %q: %w", *user, err)
@@ -86,5 +79,5 @@ func (c *commandS3PolicyDetach) Do(args []string, commandEnv *CommandEnv, writer
}
return json.NewEncoder(writer).Encode(map[string]string{"policy": *policy, "user": *user})
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
@@ -11,9 +11,7 @@ import (
"time"
"github.com/seaweedfs/seaweedfs/weed/iam"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -115,15 +113,12 @@ func (c *commandS3ServiceAccountCreate) Do(args []string, commandEnv *CommandEnv
sa.Expiration = time.Now().Add(*expiry).Unix()
}
err = pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err = commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
_, err := client.CreateServiceAccount(ctx, &iam_pb.CreateServiceAccountRequest{
ServiceAccount: sa,
})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
@@ -5,11 +5,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -45,13 +42,10 @@ func (c *commandS3ServiceAccountDelete) Do(args []string, commandEnv *CommandEnv
return fmt.Errorf("-id is required")
}
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
_, err := client.DeleteServiceAccount(ctx, &iam_pb.DeleteServiceAccountRequest{Id: *id})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"fmt"
"io"
"text/tabwriter"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -45,11 +42,7 @@ func (c *commandS3ServiceAccountList) Do(args []string, commandEnv *CommandEnv,
return err
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.ListServiceAccounts(ctx, &iam_pb.ListServiceAccountsRequest{})
if err != nil {
return err
@@ -81,5 +74,5 @@ func (c *commandS3ServiceAccountList) Do(args []string, commandEnv *CommandEnv,
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", sa.Id, sa.ParentUser, st, desc)
}
return tw.Flush()
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -8
View File
@@ -8,9 +8,7 @@ import (
"strings"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -46,11 +44,7 @@ func (c *commandS3ServiceAccountShow) Do(args []string, commandEnv *CommandEnv,
return fmt.Errorf("-id is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetServiceAccount(ctx, &iam_pb.GetServiceAccountRequest{Id: *id})
if err != nil {
return err
@@ -89,5 +83,5 @@ func (c *commandS3ServiceAccountShow) Do(args []string, commandEnv *CommandEnv,
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
+2 -8
View File
@@ -7,12 +7,9 @@ import (
"fmt"
"io"
"os"
"time"
"github.com/seaweedfs/seaweedfs/weed/iam"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -88,13 +85,10 @@ func (c *commandS3UserCreate) Do(args []string, commandEnv *CommandEnv, writer i
},
}
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
_, err := client.CreateUser(ctx, &iam_pb.CreateUserRequest{Identity: identity})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -8
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -46,13 +43,10 @@ func (c *commandS3UserDelete) Do(args []string, commandEnv *CommandEnv, writer i
return fmt.Errorf("-name is required")
}
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
_, err := client.DeleteUser(ctx, &iam_pb.DeleteUserRequest{Username: *name})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -49,11 +46,7 @@ func (c *commandS3UserDisable) Do(args []string, commandEnv *CommandEnv, writer
return fmt.Errorf("-name is required")
}
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: *name})
if err != nil {
return fmt.Errorf("get user %q: %w", *name, err)
@@ -72,7 +65,7 @@ func (c *commandS3UserDisable) Do(args []string, commandEnv *CommandEnv, writer
Identity: resp.Identity,
})
return err
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -46,11 +43,7 @@ func (c *commandS3UserEnable) Do(args []string, commandEnv *CommandEnv, writer i
return fmt.Errorf("-name is required")
}
err := pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: *name})
if err != nil {
return fmt.Errorf("get user %q: %w", *name, err)
@@ -68,7 +61,7 @@ func (c *commandS3UserEnable) Do(args []string, commandEnv *CommandEnv, writer i
return err
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -9
View File
@@ -5,11 +5,8 @@ import (
"encoding/json"
"io"
"strings"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -44,11 +41,7 @@ type s3UserListEntry struct {
}
func (c *commandS3UserList) Do(args []string, commandEnv *CommandEnv, writer io.Writer) error {
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetConfiguration(ctx, &iam_pb.GetConfigurationRequest{})
if err != nil {
return err
@@ -75,7 +68,7 @@ func (c *commandS3UserList) Do(args []string, commandEnv *CommandEnv, writer io.
result = []s3UserListEntry{}
}
return json.NewEncoder(writer).Encode(result)
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}
// joinMax joins up to max strings with ", " and appends "..." if truncated.
+2 -9
View File
@@ -7,12 +7,9 @@ import (
"fmt"
"io"
"strings"
"time"
"github.com/seaweedfs/seaweedfs/weed/iam"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -113,11 +110,7 @@ func (c *commandS3UserProvision) Do(args []string, commandEnv *CommandEnv, write
var ak, sk string
var userCreated bool
err = pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err = commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
// Step 0: Check if user already exists
var existingIdentity *iam_pb.Identity
if resp, getErr := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: *name}); getErr == nil && resp.Identity != nil {
@@ -194,7 +187,7 @@ func (c *commandS3UserProvision) Do(args []string, commandEnv *CommandEnv, write
}
return nil
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
if err != nil {
return err
}
+2 -9
View File
@@ -6,11 +6,8 @@ import (
"flag"
"fmt"
"io"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"google.golang.org/grpc"
)
func init() {
@@ -70,11 +67,7 @@ func (c *commandS3UserShow) Do(args []string, commandEnv *CommandEnv, writer io.
return fmt.Errorf("-name is required")
}
return pb.WithGrpcClient(false, 0, func(conn *grpc.ClientConn) error {
client := iam_pb.NewSeaweedIdentityAccessManagementClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return commandEnv.withIamClient(func(ctx context.Context, client iam_pb.SeaweedIdentityAccessManagementClient) error {
resp, err := client.GetUser(ctx, &iam_pb.GetUserRequest{Username: *name})
if err != nil {
return err
@@ -133,5 +126,5 @@ func (c *commandS3UserShow) Do(args []string, commandEnv *CommandEnv, writer io.
}
return json.NewEncoder(writer).Encode(result)
}, commandEnv.option.FilerAddress.ToGrpcAddress(), false, commandEnv.option.GrpcDialOption)
})
}