auth: protect all maintainence APIs when auth is enabled

All maintenance APIs require admin privilege when auth is enabled,
otherwise, the request will be rejected. If auth isn't enabled,
then no such requirement any more.

Signed-off-by: Benjamin Wang <wachao@vmware.com>
This commit is contained in:
Benjamin Wang 2022-11-01 05:08:11 +08:00
parent 7ed4eda4c1
commit c967715d93
2 changed files with 39 additions and 21 deletions

View File

@ -18,6 +18,7 @@ import (
"context" "context"
pb "go.etcd.io/etcd/api/v3/etcdserverpb" pb "go.etcd.io/etcd/api/v3/etcdserverpb"
"go.etcd.io/etcd/server/v3/auth"
"go.etcd.io/etcd/server/v3/etcdserver" "go.etcd.io/etcd/server/v3/etcdserver"
) )
@ -164,3 +165,23 @@ func (as *AuthServer) UserChangePassword(ctx context.Context, r *pb.AuthUserChan
} }
return resp, nil return resp, nil
} }
type AuthGetter interface {
AuthInfoFromCtx(ctx context.Context) (*auth.AuthInfo, error)
AuthStore() auth.AuthStore
}
type AuthAdmin struct {
ag AuthGetter
}
// isPermitted verifies the user has admin privilege.
// Only users with "root" role are permitted.
func (aa *AuthAdmin) isPermitted(ctx context.Context) error {
authInfo, err := aa.ag.AuthInfoFromCtx(ctx)
if err != nil {
return err
}
return aa.ag.AuthStore().IsAdminPermitted(authInfo)
}

View File

@ -25,7 +25,6 @@ import (
"go.etcd.io/etcd/api/v3/v3rpc/rpctypes" "go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
"go.etcd.io/etcd/api/v3/version" "go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/raft/v3" "go.etcd.io/etcd/raft/v3"
"go.etcd.io/etcd/server/v3/auth"
"go.etcd.io/etcd/server/v3/etcdserver" "go.etcd.io/etcd/server/v3/etcdserver"
"go.etcd.io/etcd/server/v3/etcdserver/apply" "go.etcd.io/etcd/server/v3/etcdserver/apply"
"go.etcd.io/etcd/server/v3/etcdserver/errors" "go.etcd.io/etcd/server/v3/etcdserver/errors"
@ -60,11 +59,6 @@ type LeaderTransferrer interface {
MoveLeader(ctx context.Context, lead, target uint64) error MoveLeader(ctx context.Context, lead, target uint64) error
} }
type AuthGetter interface {
AuthInfoFromCtx(ctx context.Context) (*auth.AuthInfo, error)
AuthStore() auth.AuthStore
}
type ClusterStatusGetter interface { type ClusterStatusGetter interface {
IsLearner() bool IsLearner() bool
} }
@ -87,7 +81,7 @@ func NewMaintenanceServer(s *etcdserver.EtcdServer) pb.MaintenanceServer {
if srv.lg == nil { if srv.lg == nil {
srv.lg = zap.NewNop() srv.lg = zap.NewNop()
} }
return &authMaintenanceServer{srv, s} return &authMaintenanceServer{srv, &AuthAdmin{s}}
} }
func (ms *maintenanceServer) Defragment(ctx context.Context, sr *pb.DefragmentRequest) (*pb.DefragmentResponse, error) { func (ms *maintenanceServer) Defragment(ctx context.Context, sr *pb.DefragmentRequest) (*pb.DefragmentResponse, error) {
@ -274,20 +268,11 @@ func (ms *maintenanceServer) Downgrade(ctx context.Context, r *pb.DowngradeReque
type authMaintenanceServer struct { type authMaintenanceServer struct {
*maintenanceServer *maintenanceServer
ag AuthGetter *AuthAdmin
}
func (ams *authMaintenanceServer) isAuthenticated(ctx context.Context) error {
authInfo, err := ams.ag.AuthInfoFromCtx(ctx)
if err != nil {
return err
}
return ams.ag.AuthStore().IsAdminPermitted(authInfo)
} }
func (ams *authMaintenanceServer) Defragment(ctx context.Context, sr *pb.DefragmentRequest) (*pb.DefragmentResponse, error) { func (ams *authMaintenanceServer) Defragment(ctx context.Context, sr *pb.DefragmentRequest) (*pb.DefragmentResponse, error) {
if err := ams.isAuthenticated(ctx); err != nil { if err := ams.isPermitted(ctx); err != nil {
return nil, err return nil, err
} }
@ -295,7 +280,7 @@ func (ams *authMaintenanceServer) Defragment(ctx context.Context, sr *pb.Defragm
} }
func (ams *authMaintenanceServer) Snapshot(sr *pb.SnapshotRequest, srv pb.Maintenance_SnapshotServer) error { func (ams *authMaintenanceServer) Snapshot(sr *pb.SnapshotRequest, srv pb.Maintenance_SnapshotServer) error {
if err := ams.isAuthenticated(srv.Context()); err != nil { if err := ams.isPermitted(srv.Context()); err != nil {
return err return err
} }
@ -303,7 +288,7 @@ func (ams *authMaintenanceServer) Snapshot(sr *pb.SnapshotRequest, srv pb.Mainte
} }
func (ams *authMaintenanceServer) Hash(ctx context.Context, r *pb.HashRequest) (*pb.HashResponse, error) { func (ams *authMaintenanceServer) Hash(ctx context.Context, r *pb.HashRequest) (*pb.HashResponse, error) {
if err := ams.isAuthenticated(ctx); err != nil { if err := ams.isPermitted(ctx); err != nil {
return nil, err return nil, err
} }
@ -311,20 +296,32 @@ func (ams *authMaintenanceServer) Hash(ctx context.Context, r *pb.HashRequest) (
} }
func (ams *authMaintenanceServer) HashKV(ctx context.Context, r *pb.HashKVRequest) (*pb.HashKVResponse, error) { func (ams *authMaintenanceServer) HashKV(ctx context.Context, r *pb.HashKVRequest) (*pb.HashKVResponse, error) {
if err := ams.isAuthenticated(ctx); err != nil { if err := ams.isPermitted(ctx); err != nil {
return nil, err return nil, err
} }
return ams.maintenanceServer.HashKV(ctx, r) return ams.maintenanceServer.HashKV(ctx, r)
} }
func (ams *authMaintenanceServer) Status(ctx context.Context, ar *pb.StatusRequest) (*pb.StatusResponse, error) { func (ams *authMaintenanceServer) Status(ctx context.Context, ar *pb.StatusRequest) (*pb.StatusResponse, error) {
if err := ams.isPermitted(ctx); err != nil {
return nil, err
}
return ams.maintenanceServer.Status(ctx, ar) return ams.maintenanceServer.Status(ctx, ar)
} }
func (ams *authMaintenanceServer) MoveLeader(ctx context.Context, tr *pb.MoveLeaderRequest) (*pb.MoveLeaderResponse, error) { func (ams *authMaintenanceServer) MoveLeader(ctx context.Context, tr *pb.MoveLeaderRequest) (*pb.MoveLeaderResponse, error) {
if err := ams.isPermitted(ctx); err != nil {
return nil, err
}
return ams.maintenanceServer.MoveLeader(ctx, tr) return ams.maintenanceServer.MoveLeader(ctx, tr)
} }
func (ams *authMaintenanceServer) Downgrade(ctx context.Context, r *pb.DowngradeRequest) (*pb.DowngradeResponse, error) { func (ams *authMaintenanceServer) Downgrade(ctx context.Context, r *pb.DowngradeRequest) (*pb.DowngradeResponse, error) {
if err := ams.isPermitted(ctx); err != nil {
return nil, err
}
return ams.maintenanceServer.Downgrade(ctx, r) return ams.maintenanceServer.Downgrade(ctx, r)
} }