Files
seaweedfs/weed/server/filer_server_handlers_iam_grpc.go
T
0742d316aa fix(s3): accept fresh admin tokens when context carries stale authorization (#12390) (#12397)
* fix(s3): accept fresh admin tokens when context carries stale authorization (#12390)

Signed-off-by: Mohd Quamar Tyagi <104281681+Tyagiquamar@users.noreply.github.com>

* security: share the admin Bearer check between S3 and admin-plane peers

Move the authorization scan into security.CheckGrpcAdminToken, built on
IsFilerAdminToken, and call it from CheckGrpcAdminPeer and the S3 IAM cache
check. Both now accept a valid admin token in any authorization value
instead of S3 re-implementing the decode and claim checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* filer: accept a fresh admin token after a stale one on IAM gRPC

The S3 IAM cache check is meant to mirror the filer's, so route the filer's
checkAdminAuth through security.CheckGrpcAdminToken too. IamGrpcStore appends
its token to the caller's context, so a forwarded older token would otherwise
still shadow it here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* security: parse at most four authorization values per admin call

Scanning every value let one request repeat a junk Bearer token (cheap over
HPACK) tens of thousands of times and burn about half a second of JWT parsing
on an unauthenticated port. Real callers send their own token plus at most one
forwarded from their context.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* credential: match the other WithS3InternalAdminAuth replace fix

The plugin worker fix makes the same set-instead-of-append change to
WithS3InternalAdminAuth with different code and a different test at the same
spot, so whichever lands second would conflict. Use the identical code and
test so the two merge cleanly in either order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* security: test an expired admin token ahead of a fresh one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* security: test that a same-key session token is not an admin token

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* filer: test IAM gRPC with only invalid authorization values

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Signed-off-by: Mohd Quamar Tyagi <104281681+Tyagiquamar@users.noreply.github.com>
Co-authored-by: Chris Lu <chrislusf@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 09:42:25 -08:00

637 lines
21 KiB
Go

package weed_server
import (
"context"
"encoding/json"
"github.com/seaweedfs/seaweedfs/weed/credential"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/iam/integration"
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
"github.com/seaweedfs/seaweedfs/weed/security"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// IamGrpcServer implements the IAM gRPC service on the filer.
// When jwt.filer_signing.key is set, every RPC requires a Bearer token signed
// with it; otherwise RPCs run unauthenticated, except the OIDC provider and
// role RPCs, which are refused. The key gates only this service: the filer RPCs
// on the same port can still read and write the IAM store under /etc/iam.
// Protect a filer gRPC port reachable by untrusted clients with [grpc.filer] mTLS.
type IamGrpcServer struct {
iam_pb.UnimplementedSeaweedIdentityAccessManagementServer
credentialManager *credential.CredentialManager
adminSigningKey security.SigningKey
oidcProviderStore integration.OIDCProviderStore
roleStore integration.RoleStore
}
// NewIamGrpcServer creates a new IAM gRPC server. If adminSigningKey is empty
// the service runs unauthenticated; otherwise every RPC requires a Bearer
// token signed with the key.
func NewIamGrpcServer(credentialManager *credential.CredentialManager, adminSigningKey security.SigningKey) *IamGrpcServer {
return &IamGrpcServer{
credentialManager: credentialManager,
adminSigningKey: adminSigningKey,
}
}
// checkAdminAuth verifies the caller presented a Bearer token signed by the
// filer's write-signing key. It is invoked at the top of every IAM RPC.
// When no signing key is configured the service runs unauthenticated and this
// check is a no-op.
func (s *IamGrpcServer) checkAdminAuth(ctx context.Context) error {
if len(s.adminSigningKey) == 0 {
return nil
}
return security.CheckGrpcAdminToken(ctx, s.adminSigningKey)
}
//////////////////////////////////////////////////
// Configuration Management
func (s *IamGrpcServer) GetConfiguration(ctx context.Context, req *iam_pb.GetConfigurationRequest) (*iam_pb.GetConfigurationResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("GetConfiguration")
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
config, err := s.credentialManager.LoadConfiguration(ctx)
if err != nil {
glog.Errorf("Failed to load configuration: %v", err)
return nil, err
}
return &iam_pb.GetConfigurationResponse{
Configuration: config,
}, nil
}
func (s *IamGrpcServer) PutConfiguration(ctx context.Context, req *iam_pb.PutConfigurationRequest) (*iam_pb.PutConfigurationResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("PutConfiguration")
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
if req.Configuration == nil {
return nil, status.Errorf(codes.InvalidArgument, "configuration is nil")
}
err := s.credentialManager.SaveConfiguration(ctx, req.Configuration)
if err != nil {
glog.Errorf("Failed to save configuration: %v", err)
return nil, err
}
return &iam_pb.PutConfigurationResponse{}, nil
}
//////////////////////////////////////////////////
// User Management
func (s *IamGrpcServer) CreateUser(ctx context.Context, req *iam_pb.CreateUserRequest) (*iam_pb.CreateUserResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil || req.Identity == nil {
return nil, status.Errorf(codes.InvalidArgument, "identity is required")
}
glog.V(4).Infof("IAM: Filer.CreateUser %s", req.Identity.Name)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.CreateUser(ctx, req.Identity)
if err != nil {
if err == credential.ErrUserAlreadyExists {
return nil, status.Errorf(codes.AlreadyExists, "user %s already exists", req.Identity.Name)
}
glog.Errorf("Failed to create user %s: %v", req.Identity.Name, err)
return nil, status.Errorf(codes.Internal, "failed to create user: %v", err)
}
return &iam_pb.CreateUserResponse{}, nil
}
func (s *IamGrpcServer) GetUser(ctx context.Context, req *iam_pb.GetUserRequest) (*iam_pb.GetUserResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("GetUser: %s", req.Username)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
identity, err := s.credentialManager.GetUser(ctx, req.Username)
if err != nil {
if err == credential.ErrUserNotFound {
// Fall back to static identities (loaded from -s3.config file)
if si := s.credentialManager.GetStaticIdentity(req.Username); si != nil {
return &iam_pb.GetUserResponse{Identity: si}, nil
}
return nil, status.Errorf(codes.NotFound, "user %s not found", req.Username)
}
glog.Errorf("Failed to get user %s: %v", req.Username, err)
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
return &iam_pb.GetUserResponse{
Identity: identity,
}, nil
}
func (s *IamGrpcServer) UpdateUser(ctx context.Context, req *iam_pb.UpdateUserRequest) (*iam_pb.UpdateUserResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil || req.Identity == nil {
return nil, status.Errorf(codes.InvalidArgument, "identity is required")
}
glog.V(4).Infof("IAM: Filer.UpdateUser %s", req.Username)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.UpdateUser(ctx, req.Username, req.Identity)
if err != nil {
if err == credential.ErrUserNotFound {
return nil, status.Errorf(codes.NotFound, "user %s not found", req.Username)
}
glog.Errorf("Failed to update user %s: %v", req.Username, err)
return nil, status.Errorf(codes.Internal, "failed to update user: %v", err)
}
return &iam_pb.UpdateUserResponse{}, nil
}
func (s *IamGrpcServer) DeleteUser(ctx context.Context, req *iam_pb.DeleteUserRequest) (*iam_pb.DeleteUserResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("IAM: Filer.DeleteUser %s", req.Username)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.DeleteUser(ctx, req.Username)
if err != nil {
if err == credential.ErrUserNotFound {
return nil, status.Errorf(codes.NotFound, "user %s not found", req.Username)
}
glog.Errorf("Failed to delete user %s: %v", req.Username, err)
return nil, status.Errorf(codes.Internal, "failed to delete user: %v", err)
}
return &iam_pb.DeleteUserResponse{}, nil
}
func (s *IamGrpcServer) ListUsers(ctx context.Context, req *iam_pb.ListUsersRequest) (*iam_pb.ListUsersResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("ListUsers")
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
usernames, err := s.credentialManager.ListUsers(ctx)
if err != nil {
glog.Errorf("Failed to list users: %v", err)
return nil, err
}
// Merge static identities (from -s3.config file) into the result
staticNames := s.credentialManager.GetStaticUsernames()
if len(staticNames) > 0 {
dynamicSet := make(map[string]bool, len(usernames))
for _, name := range usernames {
dynamicSet[name] = true
}
for _, name := range staticNames {
if !dynamicSet[name] {
usernames = append(usernames, name)
}
}
}
return &iam_pb.ListUsersResponse{
Usernames: usernames,
}, nil
}
//////////////////////////////////////////////////
// Access Key Management
func (s *IamGrpcServer) CreateAccessKey(ctx context.Context, req *iam_pb.CreateAccessKeyRequest) (*iam_pb.CreateAccessKeyResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil || req.Credential == nil {
return nil, status.Errorf(codes.InvalidArgument, "credential is required")
}
glog.V(4).Infof("CreateAccessKey for user: %s", req.Username)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.CreateAccessKey(ctx, req.Username, req.Credential)
if err != nil {
if err == credential.ErrUserNotFound {
return nil, status.Errorf(codes.NotFound, "user %s not found", req.Username)
}
glog.Errorf("Failed to create access key for user %s: %v", req.Username, err)
return nil, status.Errorf(codes.Internal, "failed to create access key: %v", err)
}
return &iam_pb.CreateAccessKeyResponse{}, nil
}
func (s *IamGrpcServer) DeleteAccessKey(ctx context.Context, req *iam_pb.DeleteAccessKeyRequest) (*iam_pb.DeleteAccessKeyResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("DeleteAccessKey: %s for user: %s", req.AccessKey, req.Username)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.DeleteAccessKey(ctx, req.Username, req.AccessKey)
if err != nil {
if err == credential.ErrUserNotFound {
return nil, status.Errorf(codes.NotFound, "user %s not found", req.Username)
}
if err == credential.ErrAccessKeyNotFound {
return nil, status.Errorf(codes.NotFound, "access key %s not found", req.AccessKey)
}
glog.Errorf("Failed to delete access key %s for user %s: %v", req.AccessKey, req.Username, err)
return nil, status.Errorf(codes.Internal, "failed to delete access key: %v", err)
}
return &iam_pb.DeleteAccessKeyResponse{}, nil
}
func (s *IamGrpcServer) GetUserByAccessKey(ctx context.Context, req *iam_pb.GetUserByAccessKeyRequest) (*iam_pb.GetUserByAccessKeyResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("GetUserByAccessKey: %s", req.AccessKey)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
identity, err := s.credentialManager.GetUserByAccessKey(ctx, req.AccessKey)
if err != nil {
if err == credential.ErrAccessKeyNotFound {
return nil, status.Errorf(codes.NotFound, "access key %s not found", req.AccessKey)
}
glog.Errorf("Failed to get user by access key %s: %v", req.AccessKey, err)
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
return &iam_pb.GetUserByAccessKeyResponse{
Identity: identity,
}, nil
}
//////////////////////////////////////////////////
// Policy Management
func (s *IamGrpcServer) PutPolicy(ctx context.Context, req *iam_pb.PutPolicyRequest) (*iam_pb.PutPolicyResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("IAM: Filer.PutPolicy %s", req.Name)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
if req.Name == "" {
return nil, status.Errorf(codes.InvalidArgument, "policy name is required")
}
if err := credential.ValidatePolicyName(req.Name); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "%v", err)
}
if req.Content == "" {
return nil, status.Errorf(codes.InvalidArgument, "policy content is required")
}
var policy policy_engine.PolicyDocument
if err := json.Unmarshal([]byte(req.Content), &policy); err != nil {
glog.Errorf("Failed to unmarshal policy %s: %v", req.Name, err)
return nil, err
}
err := s.credentialManager.PutPolicy(ctx, req.Name, policy)
if err != nil {
glog.Errorf("Failed to put policy %s: %v", req.Name, err)
return nil, err
}
return &iam_pb.PutPolicyResponse{}, nil
}
func (s *IamGrpcServer) GetPolicy(ctx context.Context, req *iam_pb.GetPolicyRequest) (*iam_pb.GetPolicyResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("GetPolicy: %s", req.Name)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
policy, err := s.credentialManager.GetPolicy(ctx, req.Name)
if err != nil {
glog.Errorf("Failed to get policy %s: %v", req.Name, err)
return nil, err
}
if policy == nil {
return nil, status.Errorf(codes.NotFound, "policy %s not found", req.Name)
}
jsonBytes, err := json.Marshal(policy)
if err != nil {
glog.Errorf("Failed to marshal policy %s: %v", req.Name, err)
return nil, err
}
return &iam_pb.GetPolicyResponse{
Name: req.Name,
Content: string(jsonBytes),
}, nil
}
func (s *IamGrpcServer) ListPolicies(ctx context.Context, req *iam_pb.ListPoliciesRequest) (*iam_pb.ListPoliciesResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("ListPolicies")
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
policiesData, err := s.credentialManager.GetPolicies(ctx)
if err != nil {
glog.Errorf("Failed to list policies: %v", err)
return nil, err
}
var policies []*iam_pb.Policy
for name, policy := range policiesData {
jsonBytes, err := json.Marshal(policy)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to marshal policy %s: %v", name, err)
}
policies = append(policies, &iam_pb.Policy{
Name: name,
Content: string(jsonBytes),
})
}
return &iam_pb.ListPoliciesResponse{
Policies: policies,
}, nil
}
func (s *IamGrpcServer) DeletePolicy(ctx context.Context, req *iam_pb.DeletePolicyRequest) (*iam_pb.DeletePolicyResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("DeletePolicy: %s", req.Name)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
// Roles attach policies by name; deleting one still attached would let a
// policy created later under that name take effect on the role.
if s.roleStore != nil {
roles, err := integration.RolesAttachingPolicy(ctx, s.roleStore, req.Name)
if err != nil {
return nil, status.Errorf(codes.Unavailable, "check role attachments: %v", err)
}
if len(roles) > 0 {
return nil, status.Errorf(codes.FailedPrecondition, "policy %s is attached to role %s", req.Name, roles[0])
}
}
err := s.credentialManager.DeletePolicy(ctx, req.Name)
if err != nil {
glog.Errorf("Failed to delete policy %s: %v", req.Name, err)
return nil, err
}
return &iam_pb.DeletePolicyResponse{}, nil
}
//////////////////////////////////////////////////
// Service Account Management
func (s *IamGrpcServer) CreateServiceAccount(ctx context.Context, req *iam_pb.CreateServiceAccountRequest) (*iam_pb.CreateServiceAccountResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil || req.ServiceAccount == nil {
return nil, status.Errorf(codes.InvalidArgument, "service account is required")
}
if err := credential.ValidateServiceAccountId(req.ServiceAccount.Id); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "%v", err)
}
glog.V(4).Infof("CreateServiceAccount: %s", req.ServiceAccount.Id)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.CreateServiceAccount(ctx, req.ServiceAccount)
if err != nil {
glog.Errorf("Failed to create service account %s: %v", req.ServiceAccount.Id, err)
return nil, status.Errorf(codes.Internal, "failed to create service account: %v", err)
}
return &iam_pb.CreateServiceAccountResponse{}, nil
}
func (s *IamGrpcServer) UpdateServiceAccount(ctx context.Context, req *iam_pb.UpdateServiceAccountRequest) (*iam_pb.UpdateServiceAccountResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil || req.ServiceAccount == nil {
return nil, status.Errorf(codes.InvalidArgument, "service account is required")
}
glog.V(4).Infof("UpdateServiceAccount: %s", req.Id)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.UpdateServiceAccount(ctx, req.Id, req.ServiceAccount)
if err != nil {
glog.Errorf("Failed to update service account %s: %v", req.Id, err)
return nil, status.Errorf(codes.Internal, "failed to update service account: %v", err)
}
return &iam_pb.UpdateServiceAccountResponse{}, nil
}
func (s *IamGrpcServer) DeleteServiceAccount(ctx context.Context, req *iam_pb.DeleteServiceAccountRequest) (*iam_pb.DeleteServiceAccountResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("DeleteServiceAccount: %s", req.Id)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
err := s.credentialManager.DeleteServiceAccount(ctx, req.Id)
if err != nil {
if err == credential.ErrServiceAccountNotFound {
return nil, status.Errorf(codes.NotFound, "service account %s not found", req.Id)
}
glog.Errorf("Failed to delete service account %s: %v", req.Id, err)
return nil, status.Errorf(codes.Internal, "failed to delete service account: %v", err)
}
return &iam_pb.DeleteServiceAccountResponse{}, nil
}
func (s *IamGrpcServer) GetServiceAccount(ctx context.Context, req *iam_pb.GetServiceAccountRequest) (*iam_pb.GetServiceAccountResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("GetServiceAccount: %s", req.Id)
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
sa, err := s.credentialManager.GetServiceAccount(ctx, req.Id)
if err != nil {
glog.Errorf("Failed to get service account %s: %v", req.Id, err)
return nil, status.Errorf(codes.Internal, "failed to get service account: %v", err)
}
if sa == nil {
return nil, status.Errorf(codes.NotFound, "service account %s not found", req.Id)
}
return &iam_pb.GetServiceAccountResponse{
ServiceAccount: sa,
}, nil
}
func (s *IamGrpcServer) ListServiceAccounts(ctx context.Context, req *iam_pb.ListServiceAccountsRequest) (*iam_pb.ListServiceAccountsResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("ListServiceAccounts")
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
accounts, err := s.credentialManager.ListServiceAccounts(ctx)
if err != nil {
glog.Errorf("Failed to list service accounts: %v", err)
return nil, status.Errorf(codes.Internal, "failed to list service accounts: %v", err)
}
return &iam_pb.ListServiceAccountsResponse{
ServiceAccounts: accounts,
}, nil
}
func (s *IamGrpcServer) GetServiceAccountByAccessKey(ctx context.Context, req *iam_pb.GetServiceAccountByAccessKeyRequest) (*iam_pb.GetServiceAccountByAccessKeyResponse, error) {
if err := s.checkAdminAuth(ctx); err != nil {
return nil, err
}
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "request is required")
}
glog.V(4).Infof("GetServiceAccountByAccessKey: %s", req.AccessKey)
if req.AccessKey == "" {
return nil, status.Errorf(codes.InvalidArgument, "access key is required")
}
if s.credentialManager == nil {
return nil, status.Errorf(codes.FailedPrecondition, "credential manager is not configured")
}
sa, err := s.credentialManager.GetStore().GetServiceAccountByAccessKey(ctx, req.AccessKey)
if err != nil {
if err == credential.ErrAccessKeyNotFound {
return nil, status.Errorf(codes.NotFound, "access key %s not found", req.AccessKey)
}
glog.Errorf("Failed to get service account by access key %s: %v", req.AccessKey, err)
return nil, status.Errorf(codes.Internal, "failed to get service account: %v", err)
}
return &iam_pb.GetServiceAccountByAccessKeyResponse{
ServiceAccount: sa,
}, nil
}