Skip to content

Commit

Permalink
Add AutoUpdate gRPC service implementation (#46544) (#46653)
Browse files Browse the repository at this point in the history
* Add gRPC service implementation

* CR changes

* Add auth for read operation
  • Loading branch information
vapopov authored Sep 18, 2024
1 parent 44e05f8 commit c94d3e5
Show file tree
Hide file tree
Showing 9 changed files with 594 additions and 19 deletions.
8 changes: 8 additions & 0 deletions lib/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) {
}
cfg.ClusterConfiguration = clusterConfig
}
if cfg.AutoUpdateService == nil {
cfg.AutoUpdateService, err = local.NewAutoUpdateService(cfg.Backend)
if err != nil {
return nil, trace.Wrap(err)
}
}
if cfg.Restrictions == nil {
cfg.Restrictions = local.NewRestrictionsService(cfg.Backend)
}
Expand Down Expand Up @@ -398,6 +404,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) {
Access: cfg.Access,
DynamicAccessExt: cfg.DynamicAccessExt,
ClusterConfiguration: cfg.ClusterConfiguration,
AutoUpdateService: cfg.AutoUpdateService,
Restrictions: cfg.Restrictions,
Apps: cfg.Apps,
Kubernetes: cfg.Kubernetes,
Expand Down Expand Up @@ -629,6 +636,7 @@ type Services struct {
services.SPIFFEFederations
services.AccessGraphSecretsGetter
services.DevicesGetter
services.AutoUpdateService
}

// GetWebSession returns existing web session described by req.
Expand Down
270 changes: 270 additions & 0 deletions lib/auth/autoupdate/autoupdatev1/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package autoupdatev1

import (
"context"

"github.com/gravitational/trace"
"google.golang.org/protobuf/types/known/emptypb"

"github.com/gravitational/teleport/api/gen/proto/go/teleport/autoupdate/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/authz"
"github.com/gravitational/teleport/lib/services"
)

// Cache defines only read-only service methods.
type Cache interface {
// GetAutoUpdateConfig gets the autoupdate configuration from the backend.
GetAutoUpdateConfig(ctx context.Context) (*autoupdate.AutoUpdateConfig, error)

// GetAutoUpdateVersion gets the autoupdate version from the backend.
GetAutoUpdateVersion(ctx context.Context) (*autoupdate.AutoUpdateVersion, error)
}

// ServiceConfig holds configuration options for the autoupdate gRPC service.
type ServiceConfig struct {
// Authorizer is the authorizer used to check access to resources.
Authorizer authz.Authorizer
// Backend is the backend used to store autoupdate resources.
Backend services.AutoUpdateService
// Cache is the cache used to store autoupdate resources.
Cache Cache
}

// Service implements the gRPC API layer for the Autoupdate.
type Service struct {
autoupdate.UnimplementedAutoUpdateServiceServer

authorizer authz.Authorizer
backend services.AutoUpdateService
cache Cache
}

// NewService returns a new Autoupdate API service using the given storage layer and authorizer.
func NewService(cfg ServiceConfig) (*Service, error) {
switch {
case cfg.Backend == nil:
return nil, trace.BadParameter("backend is required")
case cfg.Authorizer == nil:
return nil, trace.BadParameter("authorizer is required")
case cfg.Cache == nil:
return nil, trace.BadParameter("cache is required")
}
return &Service{
authorizer: cfg.Authorizer,
backend: cfg.Backend,
cache: cfg.Cache,
}, nil
}

// GetAutoUpdateConfig gets the current autoupdate config singleton.
func (s *Service) GetAutoUpdateConfig(ctx context.Context, req *autoupdate.GetAutoUpdateConfigRequest) (*autoupdate.AutoUpdateConfig, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateConfig, types.VerbRead); err != nil {
return nil, trace.Wrap(err)
}

config, err := s.cache.GetAutoUpdateConfig(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

return config, nil
}

// CreateAutoUpdateConfig creates autoupdate config singleton.
func (s *Service) CreateAutoUpdateConfig(ctx context.Context, req *autoupdate.CreateAutoUpdateConfigRequest) (*autoupdate.AutoUpdateConfig, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateConfig, types.VerbCreate); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

config, err := s.backend.CreateAutoUpdateConfig(ctx, req.Config)
return config, trace.Wrap(err)
}

// UpdateAutoUpdateConfig updates autoupdate config singleton.
func (s *Service) UpdateAutoUpdateConfig(ctx context.Context, req *autoupdate.UpdateAutoUpdateConfigRequest) (*autoupdate.AutoUpdateConfig, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateConfig, types.VerbUpdate); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

config, err := s.backend.UpdateAutoUpdateConfig(ctx, req.Config)
return config, trace.Wrap(err)
}

// UpsertAutoUpdateConfig updates or creates autoupdate config singleton.
func (s *Service) UpsertAutoUpdateConfig(ctx context.Context, req *autoupdate.UpsertAutoUpdateConfigRequest) (*autoupdate.AutoUpdateConfig, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateConfig, types.VerbCreate, types.VerbUpdate); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

config, err := s.backend.UpsertAutoUpdateConfig(ctx, req.Config)
return config, trace.Wrap(err)
}

// DeleteAutoUpdateConfig deletes autoupdate config singleton.
func (s *Service) DeleteAutoUpdateConfig(ctx context.Context, req *autoupdate.DeleteAutoUpdateConfigRequest) (*emptypb.Empty, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateConfig, types.VerbDelete); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminAction(); err != nil {
return nil, trace.Wrap(err)
}

if err := s.backend.DeleteAutoUpdateConfig(ctx); err != nil {
return nil, trace.Wrap(err)
}
return &emptypb.Empty{}, nil
}

// GetAutoUpdateVersion gets the current autoupdate version singleton.
func (s *Service) GetAutoUpdateVersion(ctx context.Context, req *autoupdate.GetAutoUpdateVersionRequest) (*autoupdate.AutoUpdateVersion, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateVersion, types.VerbRead); err != nil {
return nil, trace.Wrap(err)
}

version, err := s.cache.GetAutoUpdateVersion(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

return version, nil
}

// CreateAutoUpdateVersion creates autoupdate version singleton.
func (s *Service) CreateAutoUpdateVersion(ctx context.Context, req *autoupdate.CreateAutoUpdateVersionRequest) (*autoupdate.AutoUpdateVersion, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateVersion, types.VerbCreate); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

autoupdateVersion, err := s.backend.CreateAutoUpdateVersion(ctx, req.Version)
return autoupdateVersion, trace.Wrap(err)
}

// UpdateAutoUpdateVersion updates autoupdate version singleton.
func (s *Service) UpdateAutoUpdateVersion(ctx context.Context, req *autoupdate.UpdateAutoUpdateVersionRequest) (*autoupdate.AutoUpdateVersion, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateVersion, types.VerbUpdate); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

autoupdateVersion, err := s.backend.UpdateAutoUpdateVersion(ctx, req.Version)
return autoupdateVersion, trace.Wrap(err)
}

// UpsertAutoUpdateVersion updates or creates autoupdate version singleton.
func (s *Service) UpsertAutoUpdateVersion(ctx context.Context, req *autoupdate.UpsertAutoUpdateVersionRequest) (*autoupdate.AutoUpdateVersion, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateVersion, types.VerbCreate, types.VerbUpdate); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil {
return nil, trace.Wrap(err)
}

autoupdateVersion, err := s.backend.UpsertAutoUpdateVersion(ctx, req.Version)
return autoupdateVersion, trace.Wrap(err)
}

// DeleteAutoUpdateVersion deletes autoupdate version singleton.
func (s *Service) DeleteAutoUpdateVersion(ctx context.Context, req *autoupdate.DeleteAutoUpdateVersionRequest) (*emptypb.Empty, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.CheckAccessToKind(types.KindAutoUpdateVersion, types.VerbDelete); err != nil {
return nil, trace.Wrap(err)
}

if err := authCtx.AuthorizeAdminAction(); err != nil {
return nil, trace.Wrap(err)
}

if err := s.backend.DeleteAutoUpdateVersion(ctx); err != nil {
return nil, trace.Wrap(err)
}
return &emptypb.Empty{}, nil
}
Loading

0 comments on commit c94d3e5

Please sign in to comment.