mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
server/auth: protect rangePermCache with a RW lock
Signed-off-by: Hitoshi Mitake <h.mitake@gmail.com>
This commit is contained in:
@@ -208,7 +208,14 @@ type authStore struct {
|
||||
enabled bool
|
||||
enabledMu sync.RWMutex
|
||||
|
||||
rangePermCache map[string]*unifiedRangePermissions // username -> unifiedRangePermissions
|
||||
// rangePermCache needs to be protected by rangePermCacheMu
|
||||
// rangePermCacheMu needs to be write locked only in initialization phase or configuration changes
|
||||
// Hot paths like Range(), needs to acquire read lock for improving performance
|
||||
//
|
||||
// Note that BatchTx and ReadTx cannot be a mutex for rangePermCache because they are independent resources
|
||||
// see also: https://github.com/etcd-io/etcd/pull/13920#discussion_r849114855
|
||||
rangePermCache map[string]*unifiedRangePermissions // username -> unifiedRangePermissions
|
||||
rangePermCacheMu sync.RWMutex
|
||||
|
||||
tokenProvider TokenProvider
|
||||
bcryptCost int // the algorithm cost / strength for hashing auth passwords
|
||||
@@ -243,7 +250,7 @@ func (as *authStore) AuthEnable() error {
|
||||
as.enabled = true
|
||||
as.tokenProvider.enable()
|
||||
|
||||
as.rangePermCache = make(map[string]*unifiedRangePermissions)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.setRevision(getRevision(tx))
|
||||
|
||||
@@ -422,6 +429,7 @@ func (as *authStore) UserAdd(r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse,
|
||||
putUser(as.lg, tx, newUser)
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.lg.Info("added a user", zap.String("user-name", r.Name))
|
||||
return &pb.AuthUserAddResponse{}, nil
|
||||
@@ -445,8 +453,8 @@ func (as *authStore) UserDelete(r *pb.AuthUserDeleteRequest) (*pb.AuthUserDelete
|
||||
delUser(tx, r.Name)
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.invalidateCachedPerm(r.Name)
|
||||
as.tokenProvider.invalidateUser(r.Name)
|
||||
|
||||
as.lg.Info(
|
||||
@@ -487,8 +495,8 @@ func (as *authStore) UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*p
|
||||
putUser(as.lg, tx, updatedUser)
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.invalidateCachedPerm(r.Name)
|
||||
as.tokenProvider.invalidateUser(r.Name)
|
||||
|
||||
as.lg.Info(
|
||||
@@ -532,9 +540,8 @@ func (as *authStore) UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUser
|
||||
|
||||
putUser(as.lg, tx, user)
|
||||
|
||||
as.invalidateCachedPerm(r.User)
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.lg.Info(
|
||||
"granted a role to a user",
|
||||
@@ -610,9 +617,8 @@ func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUs
|
||||
|
||||
putUser(as.lg, tx, updatedUser)
|
||||
|
||||
as.invalidateCachedPerm(r.Name)
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.lg.Info(
|
||||
"revoked a role from a user",
|
||||
@@ -678,11 +684,8 @@ func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest)
|
||||
|
||||
putRole(as.lg, tx, updatedRole)
|
||||
|
||||
// TODO(mitake): currently single role update invalidates every cache
|
||||
// It should be optimized.
|
||||
as.clearCachedPerm()
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.lg.Info(
|
||||
"revoked a permission on range",
|
||||
@@ -730,10 +733,10 @@ func (as *authStore) RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDelete
|
||||
|
||||
putUser(as.lg, tx, updatedUser)
|
||||
|
||||
as.invalidateCachedPerm(string(user.Name))
|
||||
}
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.lg.Info("deleted a role", zap.String("role-name", r.Role))
|
||||
return &pb.AuthRoleDeleteResponse{}, nil
|
||||
@@ -818,11 +821,8 @@ func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (
|
||||
|
||||
putRole(as.lg, tx, role)
|
||||
|
||||
// TODO(mitake): currently single role update invalidates every cache
|
||||
// It should be optimized.
|
||||
as.clearCachedPerm()
|
||||
|
||||
as.commitRevision(tx)
|
||||
as.refreshRangePermCache(tx)
|
||||
|
||||
as.lg.Info(
|
||||
"granted/updated a permission to a user",
|
||||
@@ -867,7 +867,7 @@ func (as *authStore) isOpPermitted(userName string, revision uint64, key, rangeE
|
||||
return nil
|
||||
}
|
||||
|
||||
if as.isRangeOpPermitted(tx, userName, key, rangeEnd, permTyp) {
|
||||
if as.isRangeOpPermitted(userName, key, rangeEnd, permTyp) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -929,7 +929,15 @@ func getUser(lg *zap.Logger, tx backend.ReadTx, username string) *authpb.User {
|
||||
}
|
||||
|
||||
func getAllUsers(lg *zap.Logger, tx backend.ReadTx) []*authpb.User {
|
||||
_, vs := tx.UnsafeRange(buckets.AuthUsers, []byte{0}, []byte{0xff}, -1)
|
||||
var vs [][]byte
|
||||
err := tx.UnsafeForEach(buckets.AuthUsers, func(k []byte, v []byte) error {
|
||||
vs = append(vs, v)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
lg.Panic("failed to get users",
|
||||
zap.Error(err))
|
||||
}
|
||||
if len(vs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user