From e52f713f879862a928e914a6e41b44117f3433ed Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Sat, 20 Feb 2021 15:05:29 -0500 Subject: [PATCH 01/14] tmp --- api/types/constants.go | 3 +++ lib/auth/grpcserver.go | 23 ++++++++++++++++++++--- lib/auth/plugin.go | 2 ++ lib/httplib/httpheaders.go | 3 ++- lib/services/types.go | 1 + lib/web/apiserver.go | 10 ++++++++++ 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/api/types/constants.go b/api/types/constants.go index c8fc3d94484bc..060cb056186d5 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -190,6 +190,9 @@ const ( // KindMFADevice is an MFA device for a user. KindMFADevice = "mfa_device" + // KindBillingInformation represents access to cloud billing features + KindBillingInformation = "billing_information" + // V3 is the third version of resources. V3 = "v3" diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 5df896c8f8393..2e6610f962cfa 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -57,6 +57,15 @@ type GRPCServer struct { server *grpc.Server } +// GetServer returns an underlining instance of grpc server +func (g *GRPCServer) GetServer() (*grpc.Server, error) { + if g.server == nil { + return nil, trace.BadParameter("grpc server has not been initialized") + } + + return g.server, nil +} + // EmitAuditEvent emits audit event func (g *GRPCServer) EmitAuditEvent(ctx context.Context, req *events.OneOf) (*empty.Empty, error) { auth, err := g.authenticate(ctx) @@ -1777,13 +1786,21 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { ), } server := grpc.NewServer(opts...) - authServer := &GRPCServer{ + authGRPCServer := &GRPCServer{ APIConfig: cfg.APIConfig, Entry: logrus.WithFields(logrus.Fields{ trace.Component: teleport.Component(teleport.ComponentAuth, teleport.ComponentGRPC), }), server: server, } - proto.RegisterAuthServiceServer(authServer.server, authServer) - return authServer, nil + proto.RegisterAuthServiceServer(authGRPCServer.server, authGRPCServer) + + if plugin := GetPlugin(); plugin != nil { + err := plugin.RegisterGRPCService(authGRPCServer) + if err != nil { + return nil, trace.Wrap(err) + } + } + + return authGRPCServer, nil } diff --git a/lib/auth/plugin.go b/lib/auth/plugin.go index b2d460dda5cf8..d19f4fbfbcbc9 100644 --- a/lib/auth/plugin.go +++ b/lib/auth/plugin.go @@ -41,4 +41,6 @@ func SetPlugin(p Plugin) { type Plugin interface { // AddHandlers adds handlers to the auth API server AddHandlers(srv *APIServer) + // RegisterGRPCService extends GRPCService APIs + RegisterGRPCService(server *GRPCServer) error } diff --git a/lib/httplib/httpheaders.go b/lib/httplib/httpheaders.go index f5dfc41afe65f..4b82d93cb1e60 100644 --- a/lib/httplib/httpheaders.go +++ b/lib/httplib/httpheaders.go @@ -63,7 +63,8 @@ func SetIndexHTMLHeaders(h http.Header) { // Set content policy flags var cspValue = strings.Join([]string{ - "script-src 'self'", + // enterprise version uses stripe.com to update billing information + "script-src 'self' https://js.stripe.com", // 'unsafe-inline' needed for reactjs inline styles "style-src 'self' 'unsafe-inline'", "object-src 'none'", diff --git a/lib/services/types.go b/lib/services/types.go index fd6bbbb7979cb..7037b4b4aab15 100644 --- a/lib/services/types.go +++ b/lib/services/types.go @@ -484,6 +484,7 @@ const ( KindClusterAuthPreference = types.KindClusterAuthPreference MetaNameClusterAuthPreference = types.MetaNameClusterAuthPreference KindClusterConfig = types.KindClusterConfig + KindBillingInformation = types.KindBillingInformation KindSemaphore = types.KindSemaphore MetaNameClusterConfig = types.MetaNameClusterConfig KindClusterName = types.KindClusterName diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index 079a56389053b..a2559a9f18e18 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -79,6 +79,16 @@ type Handler struct { sshPort string } +// GetConfig returns handler configuration which is primarily used by plugin +func (h *Handler) GetConfig() Config { + return h.cfg +} + +// GetLogger returns handler logger which is primarily used by plugin +func (h *Handler) GetLogger() logrus.FieldLogger { + return h.log +} + // HandlerOption is a functional argument - an option that can be passed // to NewHandler function type HandlerOption func(h *Handler) error From 853cd6d6019667fae55dc50340d5e6cf0294bfda Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Sun, 21 Feb 2021 02:51:20 -0500 Subject: [PATCH 02/14] tmp --- lib/web/ui/usercontext.go | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/web/ui/usercontext.go b/lib/web/ui/usercontext.go index 1c9d7d339ef01..07974ce2896c9 100644 --- a/lib/web/ui/usercontext.go +++ b/lib/web/ui/usercontext.go @@ -56,12 +56,14 @@ type userACL struct { Tokens access `json:"tokens"` // Nodes defines access to nodes. Nodes access `json:"nodes"` - // AppServers defines access to application servers. + // AppServers defines access to application servers AppServers access `json:"appServers"` // SSH defines access to servers SSHLogins []string `json:"sshLogins"` - // AccessRequests defines access to access requests. + // AccessRequests defines access to access requests AccessRequests access `json:"accessRequests"` + // BillingInformation defines access to billing information + BillingInformation access `json:"billingInformation"` } type authType string @@ -71,7 +73,7 @@ const ( authSSO authType = "sso" ) -// UserContext describes a users settings to various resources. +// UserContext describes user settings and access to various resources. type UserContext struct { // AuthType is auth method of this user. AuthType authType `json:"authType"` @@ -168,22 +170,24 @@ func NewUserContext(user services.User, userRoles services.RoleSet) (*UserContex nodeAccess := newAccess(userRoles, ctx, services.KindNode) appServerAccess := newAccess(userRoles, ctx, services.KindAppServer) requestAccess := newAccess(userRoles, ctx, services.KindAccessRequest) + billingInfoAccess := newAccess(userRoles, ctx, services.KindBillingInformation) logins := getLogins(userRoles) accessStrategy := getAccessStrategy(userRoles) acl := userACL{ - AccessRequests: requestAccess, - AppServers: appServerAccess, - AuthConnectors: authConnectors, - TrustedClusters: trustedClusterAccess, - Sessions: sessionAccess, - Roles: roleAccess, - Events: eventAccess, - SSHLogins: logins, - Users: userAccess, - Tokens: tokenAccess, - Nodes: nodeAccess, + AccessRequests: requestAccess, + AppServers: appServerAccess, + AuthConnectors: authConnectors, + TrustedClusters: trustedClusterAccess, + Sessions: sessionAccess, + Roles: roleAccess, + Events: eventAccess, + SSHLogins: logins, + Users: userAccess, + Tokens: tokenAccess, + Nodes: nodeAccess, + BillingInformation: billingInfoAccess, } // local user From 8eaeae09962fe8b340fa6a4e4cdd5d50d9b23c1f Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Mon, 22 Feb 2021 23:32:52 -0500 Subject: [PATCH 03/14] Update E-ref --- e | 2 +- lib/auth/grpcserver.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e b/e index f8bf84cc52f15..e4ccb249707e6 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit f8bf84cc52f159eaf2ff6a59f3626f95faeef98b +Subproject commit e4ccb249707e6d38a7ca2e3e2a646d97859c0d05 diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 2e6610f962cfa..2775037bcce2a 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -57,7 +57,7 @@ type GRPCServer struct { server *grpc.Server } -// GetServer returns an underlining instance of grpc server +// GetServer returns an instance of grpc server func (g *GRPCServer) GetServer() (*grpc.Server, error) { if g.server == nil { return nil, trace.BadParameter("grpc server has not been initialized") From 810c3d09c0429dca4ddb3ce30a688303fd34bcb6 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Wed, 24 Feb 2021 22:07:14 -0500 Subject: [PATCH 04/14] Address CR comments --- api/types/constants.go | 4 ++-- lib/services/types.go | 2 +- lib/web/ui/usercontext.go | 30 +++++++++++++++--------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/api/types/constants.go b/api/types/constants.go index 060cb056186d5..7b4fe5c5ff690 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -190,8 +190,8 @@ const ( // KindMFADevice is an MFA device for a user. KindMFADevice = "mfa_device" - // KindBillingInformation represents access to cloud billing features - KindBillingInformation = "billing_information" + // KindBilling represents access to cloud billing features + KindBilling = "billing" // V3 is the third version of resources. V3 = "v3" diff --git a/lib/services/types.go b/lib/services/types.go index 7037b4b4aab15..37a36c02bdd6c 100644 --- a/lib/services/types.go +++ b/lib/services/types.go @@ -484,7 +484,7 @@ const ( KindClusterAuthPreference = types.KindClusterAuthPreference MetaNameClusterAuthPreference = types.MetaNameClusterAuthPreference KindClusterConfig = types.KindClusterConfig - KindBillingInformation = types.KindBillingInformation + KindBilling = types.KindBilling KindSemaphore = types.KindSemaphore MetaNameClusterConfig = types.MetaNameClusterConfig KindClusterName = types.KindClusterName diff --git a/lib/web/ui/usercontext.go b/lib/web/ui/usercontext.go index 07974ce2896c9..431823d291ac4 100644 --- a/lib/web/ui/usercontext.go +++ b/lib/web/ui/usercontext.go @@ -62,8 +62,8 @@ type userACL struct { SSHLogins []string `json:"sshLogins"` // AccessRequests defines access to access requests AccessRequests access `json:"accessRequests"` - // BillingInformation defines access to billing information - BillingInformation access `json:"billingInformation"` + // Billing defines access to billing information + Billing access `json:"billing"` } type authType string @@ -170,24 +170,24 @@ func NewUserContext(user services.User, userRoles services.RoleSet) (*UserContex nodeAccess := newAccess(userRoles, ctx, services.KindNode) appServerAccess := newAccess(userRoles, ctx, services.KindAppServer) requestAccess := newAccess(userRoles, ctx, services.KindAccessRequest) - billingInfoAccess := newAccess(userRoles, ctx, services.KindBillingInformation) + billingAccess := newAccess(userRoles, ctx, services.KindBilling) logins := getLogins(userRoles) accessStrategy := getAccessStrategy(userRoles) acl := userACL{ - AccessRequests: requestAccess, - AppServers: appServerAccess, - AuthConnectors: authConnectors, - TrustedClusters: trustedClusterAccess, - Sessions: sessionAccess, - Roles: roleAccess, - Events: eventAccess, - SSHLogins: logins, - Users: userAccess, - Tokens: tokenAccess, - Nodes: nodeAccess, - BillingInformation: billingInfoAccess, + AccessRequests: requestAccess, + AppServers: appServerAccess, + AuthConnectors: authConnectors, + TrustedClusters: trustedClusterAccess, + Sessions: sessionAccess, + Roles: roleAccess, + Events: eventAccess, + SSHLogins: logins, + Users: userAccess, + Tokens: tokenAccess, + Nodes: nodeAccess, + Billing: billingAccess, } // local user From fedbabc4896d14ccc1058a3102a2c1feb54f1bc5 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Wed, 24 Feb 2021 22:43:15 -0500 Subject: [PATCH 05/14] Expose GRPC client connection to plugins --- api/client/client.go | 4 ++++ lib/web/sessions.go | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/api/client/client.go b/api/client/client.go index d649fb6b80466..a78908547ee32 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -118,6 +118,10 @@ func (c *Client) grpcDialer() grpcDialer { } } +func (c *Client) GetConnection() *grpc.ClientConn { + return c.conn +} + func (c *Client) connect(ctx context.Context) error { // Loop over credentials and use first successful one. var err error diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 1638298594d10..7e11ff1a2cd43 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -56,7 +56,7 @@ import ( type SessionContext struct { log logrus.FieldLogger user string - clt auth.ClientI + clt *auth.Client parent *sessionCache // resources is persistent resource store this context is bound to. // The store maintains a list of resources between session renewals @@ -79,6 +79,14 @@ func (c *SessionContext) String() string { ) } +// GetAuthClient returns auth client +func (c *SessionContext) GetAuthClient() (*auth.Client, error) { + if c.clt == nil { + return nil, trace.BadParameter("SessionContext is missing clt instance") + } + return c.clt, nil +} + // AddClosers adds the specified closers to this context func (c *SessionContext) AddClosers(closers ...io.Closer) { c.resources.addClosers(closers...) @@ -725,6 +733,10 @@ func (s *sessionCache) newSessionContext(user, sessionID string) (*SessionContex return s.newSessionContextFromSession(session) } +func (s *sessionCache) GetUserClient() *auth.Client { + return s.GetUserClient() +} + func (s *sessionCache) newSessionContextFromSession(session services.WebSession) (*SessionContext, error) { tlsConfig, err := s.tlsConfig(session.GetTLSCert(), session.GetPriv()) if err != nil { @@ -737,6 +749,7 @@ func (s *sessionCache) newSessionContextFromSession(session services.WebSession) if err != nil { return nil, trace.Wrap(err) } + ctx := &SessionContext{ clt: userClient, remoteClt: make(map[string]auth.ClientI), @@ -757,6 +770,7 @@ func (s *sessionCache) newSessionContextFromSession(session services.WebSession) // close our extra context and return ctx.Close() } + return ctx, nil } From de8b938238494962ddd8fb4a57e61515b8c2ffd1 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Wed, 24 Feb 2021 22:56:50 -0500 Subject: [PATCH 06/14] Address CR comments --- api/client/client.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/client/client.go b/api/client/client.go index a78908547ee32..ea798d3ff1f18 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -83,6 +83,11 @@ func New(ctx context.Context, cfg Config) (*Client, error) { return c, nil } +// GetConnection returns GRPC connection +func (c *Client) GetConnection() *grpc.ClientConn { + return c.conn +} + // getDialer builds a grpc dialer for the client from a ContextDialer. // The ContextDialer is chosen from available options, preferring one from // credentials, then from configuration, and lastly from addresses. @@ -118,10 +123,6 @@ func (c *Client) grpcDialer() grpcDialer { } } -func (c *Client) GetConnection() *grpc.ClientConn { - return c.conn -} - func (c *Client) connect(ctx context.Context) error { // Loop over credentials and use first successful one. var err error From f22da14e72fbe5888481e4d1b7ded0265d39e2d7 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Wed, 24 Feb 2021 22:59:08 -0500 Subject: [PATCH 07/14] Cleanup --- lib/web/sessions.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 7e11ff1a2cd43..5fd03a8f0c124 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -733,10 +733,6 @@ func (s *sessionCache) newSessionContext(user, sessionID string) (*SessionContex return s.newSessionContextFromSession(session) } -func (s *sessionCache) GetUserClient() *auth.Client { - return s.GetUserClient() -} - func (s *sessionCache) newSessionContextFromSession(session services.WebSession) (*SessionContext, error) { tlsConfig, err := s.tlsConfig(session.GetTLSCert(), session.GetPriv()) if err != nil { From 0c124776bc056557cad6581d84fd76258f50f2a6 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Wed, 24 Feb 2021 23:19:22 -0500 Subject: [PATCH 08/14] Update E-ref --- e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e b/e index e4ccb249707e6..8630aa26e31b6 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit e4ccb249707e6d38a7ca2e3e2a646d97859c0d05 +Subproject commit 8630aa26e31b6b09ae7135f390a3822c5b296813 From 3f747d0618746aa59e62fbb88e498f22ece48a1f Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Thu, 25 Feb 2021 12:53:10 -0500 Subject: [PATCH 09/14] Address CR comments --- lib/web/sessions.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 5fd03a8f0c124..864b29476c162 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -79,14 +79,6 @@ func (c *SessionContext) String() string { ) } -// GetAuthClient returns auth client -func (c *SessionContext) GetAuthClient() (*auth.Client, error) { - if c.clt == nil { - return nil, trace.BadParameter("SessionContext is missing clt instance") - } - return c.clt, nil -} - // AddClosers adds the specified closers to this context func (c *SessionContext) AddClosers(closers ...io.Closer) { c.resources.addClosers(closers...) @@ -125,7 +117,7 @@ func (c *SessionContext) getRemoteClient(siteName string) (auth.ClientI, bool) { } // GetClient returns the client connected to the auth server -func (c *SessionContext) GetClient() (auth.ClientI, error) { +func (c *SessionContext) GetClient() (*auth.Client, error) { return c.clt, nil } From 030b072b9c21247db6cd6308b58020f024a59c74 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Thu, 25 Feb 2021 12:54:34 -0500 Subject: [PATCH 10/14] Update e-ref --- e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e b/e index 8630aa26e31b6..a6baf5a128ab5 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit 8630aa26e31b6b09ae7135f390a3822c5b296813 +Subproject commit a6baf5a128ab512a547bf7612908225ad6df2b60 From 68c4fa04084ad3a4751c3424378c24a842bd95cc Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Thu, 25 Feb 2021 22:29:41 -0500 Subject: [PATCH 11/14] Address CR comments --- lib/service/db.go | 2 +- lib/service/kubernetes.go | 2 +- lib/service/service.go | 24 ++++++++++++------------ lib/web/sessions.go | 8 +++++++- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/service/db.go b/lib/service/db.go index c81183518f6d6..541d592f87b56 100644 --- a/lib/service/db.go +++ b/lib/service/db.go @@ -187,7 +187,7 @@ func (process *TeleportProcess) initDatabaseService() (retErr error) { }() // Execute this when the process running database proxy service exits. - process.onExit("db.stop", func(payload interface{}) { + process.OnExit("db.stop", func(payload interface{}) { log.Info("Shutting down.") if dbService != nil { warnOnErr(dbService.Close(), process.log) diff --git a/lib/service/kubernetes.go b/lib/service/kubernetes.go index 2e8baaa0e6c77..744e30cf270e1 100644 --- a/lib/service/kubernetes.go +++ b/lib/service/kubernetes.go @@ -265,7 +265,7 @@ func (process *TeleportProcess) initKubernetesService(log *logrus.Entry, conn *C }) // Cleanup, when process is exiting. - process.onExit("kube.shutdown", func(payload interface{}) { + process.OnExit("kube.shutdown", func(payload interface{}) { if asyncEmitter != nil { warnOnErr(asyncEmitter.Close(), log) } diff --git a/lib/service/service.go b/lib/service/service.go index 4176ba474e7da..fbd24d3ef33d6 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -1271,7 +1271,7 @@ func (process *TeleportProcess) initAuthService() error { } // External integrations rely on this event: process.BroadcastEvent(Event{Name: AuthIdentityEvent, Payload: connector}) - process.onExit("auth.broadcast", func(payload interface{}) { + process.OnExit("auth.broadcast", func(payload interface{}) { connector.Close() }) return nil @@ -1354,7 +1354,7 @@ func (process *TeleportProcess) initAuthService() error { } process.RegisterFunc("auth.heartbeat", heartbeat.Run) // execute this when process is asked to exit: - process.onExit("auth.shutdown", func(payload interface{}) { + process.OnExit("auth.shutdown", func(payload interface{}) { // The listeners have to be closed here, because if shutdown // was called before the start of the http server, // the http server would have not started tracking the listeners @@ -1390,10 +1390,10 @@ func payloadContext(payload interface{}, log logrus.FieldLogger) context.Context return context.TODO() } -// onExit allows individual services to register a callback function which will be +// OnExit allows individual services to register a callback function which will be // called when Teleport Process is asked to exit. Usually services terminate themselves // when the callback is called -func (process *TeleportProcess) onExit(serviceName string, callback func(interface{})) { +func (process *TeleportProcess) OnExit(serviceName string, callback func(interface{})) { process.RegisterFunc(serviceName, func() error { eventC := make(chan Event) process.WaitForEvent(context.TODO(), TeleportExitEvent, eventC) @@ -1810,7 +1810,7 @@ func (process *TeleportProcess) initSSH() error { }) // Execute this when process is asked to exit. - process.onExit("ssh.shutdown", func(payload interface{}) { + process.OnExit("ssh.shutdown", func(payload interface{}) { if payload == nil { log.Infof("Shutting down immediately.") if s != nil { @@ -1851,7 +1851,7 @@ func (process *TeleportProcess) registerWithAuthServer(role teleport.Role, event if err != nil { return trace.Wrap(err) } - process.onExit(fmt.Sprintf("auth.client.%v", serviceName), func(interface{}) { + process.OnExit(fmt.Sprintf("auth.client.%v", serviceName), func(interface{}) { process.log.Debugf("Closed client for %v.", role) err := connector.Client.Close() if err != nil { @@ -1923,7 +1923,7 @@ func (process *TeleportProcess) initUploaderService(accessPoint auth.AccessPoint return nil }) - process.onExit("uploader.shutdown", func(payload interface{}) { + process.OnExit("uploader.shutdown", func(payload interface{}) { log.Infof("Shutting down.") warnOnErr(uploader.Stop(), log) log.Infof("Exited.") @@ -1949,7 +1949,7 @@ func (process *TeleportProcess) initUploaderService(accessPoint auth.AccessPoint return nil }) - process.onExit("fileuploader.shutdown", func(payload interface{}) { + process.OnExit("fileuploader.shutdown", func(payload interface{}) { log.Infof("File uploader is shutting down.") warnOnErr(fileUploader.Close(), log) log.Infof("File uploader has shut down.") @@ -2048,7 +2048,7 @@ func (process *TeleportProcess) initDiagnosticService() error { return nil }) - process.onExit("diagnostic.shutdown", func(payload interface{}) { + process.OnExit("diagnostic.shutdown", func(payload interface{}) { if payload == nil { log.Infof("Shutting down immediately.") warnOnErr(server.Close(), log) @@ -2756,7 +2756,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { } // execute this when process is asked to exit: - process.onExit("proxy.shutdown", func(payload interface{}) { + process.OnExit("proxy.shutdown", func(payload interface{}) { rcWatcher.Close() defer listeners.Close() // Need to shut down this listener first, because @@ -3045,7 +3045,7 @@ func (process *TeleportProcess) initApps() { }) // Execute this when process is asked to exit. - process.onExit("apps.stop", func(payload interface{}) { + process.OnExit("apps.stop", func(payload interface{}) { log.Infof("Shutting down.") if appServer != nil { warnOnErr(appServer.Close(), log) @@ -3260,7 +3260,7 @@ func (process *TeleportProcess) initDebugApp() { process.BroadcastEvent(Event{Name: DebugAppReady, Payload: server}) return nil }) - process.onExit("debug.app.shutdown", func(payload interface{}) { + process.OnExit("debug.app.shutdown", func(payload interface{}) { if server != nil { server.Close() } diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 864b29476c162..5676bc9f52294 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -47,6 +47,7 @@ import ( "github.com/jonboulle/clockwork" "github.com/sirupsen/logrus" + "google.golang.org/grpc" ) // SessionContext is a context associated with a user's @@ -117,10 +118,15 @@ func (c *SessionContext) getRemoteClient(siteName string) (auth.ClientI, bool) { } // GetClient returns the client connected to the auth server -func (c *SessionContext) GetClient() (*auth.Client, error) { +func (c *SessionContext) GetClient() (auth.ClientI, error) { return c.clt, nil } +// GetClientConnection returns a connection to Auth Service +func (c *SessionContext) GetClientConnection() *grpc.ClientConn { + return c.clt.GetConnection() +} + // GetUserClient will return an auth.ClientI with the role of the user at // the requested site. If the site is local a client with the users local role // is returned. If the site is remote a client with the users remote role is From cf30564db51723379dff48fb9f091ef4b6d20f66 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Thu, 25 Feb 2021 22:29:56 -0500 Subject: [PATCH 12/14] E ref --- e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e b/e index a6baf5a128ab5..5a666e7af9cbe 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit a6baf5a128ab512a547bf7612908225ad6df2b60 +Subproject commit 5a666e7af9cbed40e4566bbcc1e3b1d796a2c0bb From a62977740a61700e8ad169536823ff6a58b21238 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Sat, 27 Feb 2021 15:20:51 -0500 Subject: [PATCH 13/14] refactor plugins --- e | 2 +- lib/auth/apiserver.go | 14 ++++-- lib/auth/grpcserver.go | 16 ++---- lib/auth/middleware.go | 16 +++++- lib/auth/plugin.go | 46 ------------------ lib/plugin/registry.go | 108 +++++++++++++++++++++++++++++++++++++++++ lib/service/cfg.go | 6 ++- lib/service/service.go | 41 ++++++++++------ lib/web/apiserver.go | 21 +++----- lib/web/plugin.go | 45 ----------------- 10 files changed, 175 insertions(+), 140 deletions(-) delete mode 100644 lib/auth/plugin.go create mode 100644 lib/plugin/registry.go delete mode 100644 lib/web/plugin.go diff --git a/e b/e index 5a666e7af9cbe..f39fcc2ee94aa 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit 5a666e7af9cbed40e4566bbcc1e3b1d796a2c0bb +Subproject commit f39fcc2ee94aa0c259ae4d96c89ae2bb274cdd69 diff --git a/lib/auth/apiserver.go b/lib/auth/apiserver.go index 9c847ba222339..badb6d3f8ae17 100644 --- a/lib/auth/apiserver.go +++ b/lib/auth/apiserver.go @@ -1,5 +1,5 @@ /* -Copyright 2015-2019 Gravitational, Inc. +Copyright 2015-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/httplib" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/utils" @@ -46,6 +47,7 @@ import ( ) type APIConfig struct { + PluginRegistry plugin.Registry AuthServer *Server SessionService session.Service AuditLog events.IAuditLog @@ -80,7 +82,7 @@ type APIServer struct { } // NewAPIServer returns a new instance of APIServer HTTP handler -func NewAPIServer(config *APIConfig) http.Handler { +func NewAPIServer(config *APIConfig) (http.Handler, error) { srv := APIServer{ APIConfig: *config, Clock: clockwork.NewRealClock(), @@ -246,15 +248,17 @@ func NewAPIServer(config *APIConfig) http.Handler { srv.GET("/:version/events", srv.withAuth(srv.searchEvents)) srv.GET("/:version/events/session", srv.withAuth(srv.searchSessionEvents)) - if plugin := GetPlugin(); plugin != nil { - plugin.AddHandlers(&srv) + if config.PluginRegistry != nil { + if err := config.PluginRegistry.RegisterAuthWebHandlers(&srv); err != nil { + return nil, trace.Wrap(err) + } } return httplib.RewritePaths(&srv.Router, httplib.Rewrite("/v1/nodes", "/v1/namespaces/default/nodes"), httplib.Rewrite("/v1/sessions", "/v1/namespaces/default/sessions"), httplib.Rewrite("/v1/sessions/([^/]+)/(.*)", "/v1/namespaces/default/sessions/$1/$2"), - ) + ), nil } // HandlerWithAuthFunc is http handler with passed auth context diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 2775037bcce2a..ac45672df3095 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -1,5 +1,5 @@ /* -Copyright 2018-2020 Gravitational, Inc. +Copyright 2018-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -1786,21 +1786,13 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { ), } server := grpc.NewServer(opts...) - authGRPCServer := &GRPCServer{ + authServer := &GRPCServer{ APIConfig: cfg.APIConfig, Entry: logrus.WithFields(logrus.Fields{ trace.Component: teleport.Component(teleport.ComponentAuth, teleport.ComponentGRPC), }), server: server, } - proto.RegisterAuthServiceServer(authGRPCServer.server, authGRPCServer) - - if plugin := GetPlugin(); plugin != nil { - err := plugin.RegisterGRPCService(authGRPCServer) - if err != nil { - return nil, trace.Wrap(err) - } - } - - return authGRPCServer, nil + proto.RegisterAuthServiceServer(authServer.server, authServer) + return authServer, nil } diff --git a/lib/auth/middleware.go b/lib/auth/middleware.go index c15c9b691000f..511909f3b732c 100644 --- a/lib/auth/middleware.go +++ b/lib/auth/middleware.go @@ -1,5 +1,5 @@ /* -Copyright 2017-2020 Gravitational, Inc. +Copyright 2017-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -126,7 +126,13 @@ func NewTLSServer(cfg TLSServerConfig) (*TLSServer, error) { AcceptedUsage: cfg.AcceptedUsage, Limiter: limiter, } - authMiddleware.Wrap(NewAPIServer(&cfg.APIConfig)) + + apiServer, err := NewAPIServer(&cfg.APIConfig) + if err != nil { + return nil, trace.Wrap(err) + } + + authMiddleware.Wrap(apiServer) // Wrap sets the next middleware in chain to the authMiddleware limiter.WrapHandle(authMiddleware) // force client auth if given @@ -163,6 +169,12 @@ func NewTLSServer(cfg TLSServerConfig) (*TLSServer, error) { return nil, trace.Wrap(err) } + if cfg.PluginRegistry != nil { + if err := cfg.PluginRegistry.RegisterAuthServices(server.grpcServer); err != nil { + return nil, trace.Wrap(err) + } + } + return server, nil } diff --git a/lib/auth/plugin.go b/lib/auth/plugin.go deleted file mode 100644 index d19f4fbfbcbc9..0000000000000 --- a/lib/auth/plugin.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2017 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package auth - -import ( - "sync" -) - -var pluginMutex = &sync.Mutex{} -var plugin Plugin - -// GetPlugin returns auth API server plugin that allows injecting handlers -func GetPlugin() Plugin { - pluginMutex.Lock() - defer pluginMutex.Unlock() - return plugin -} - -// SetPlugin sets plugin for the auth API server -func SetPlugin(p Plugin) { - pluginMutex.Lock() - defer pluginMutex.Unlock() - plugin = p -} - -// Plugin is auth API server extension setter -type Plugin interface { - // AddHandlers adds handlers to the auth API server - AddHandlers(srv *APIServer) - // RegisterGRPCService extends GRPCService APIs - RegisterGRPCService(server *GRPCServer) error -} diff --git a/lib/plugin/registry.go b/lib/plugin/registry.go new file mode 100644 index 0000000000000..9d8090cdd8457 --- /dev/null +++ b/lib/plugin/registry.go @@ -0,0 +1,108 @@ +/* +Copyright 2015-2021 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugin + +import "github.com/gravitational/trace" + +// Plugin describes interfaces of the teleport core plugin +type Plugin interface { + // GetName returns plugin name + GetName() string + // RegisterProxyWebHandlers registers new methods with the ProxyWebHandler + RegisterProxyWebHandlers(handler interface{}) error + // RegisterAuthWebHandlers registers new methods with the Auth Web Handler + RegisterAuthWebHandlers(service interface{}) error + // RegisterAuthServices registers new services on the AuthServer + RegisterAuthServices(server interface{}) error +} + +// Registry is the plugin registry +type Registry interface { + // Add adds plugin to the registry + Add(plugin Plugin) error + // RegisterProxyWebHandlers registers Teleport Proxy web handlers + RegisterProxyWebHandlers(hander interface{}) error + // RegisterAuthWebHandlers registers Teleport Auth web handlers + RegisterAuthWebHandlers(handler interface{}) error + // RegisterAuthServices registerse Teleport AuthServer services + RegisterAuthServices(server interface{}) error +} + +// NewRegistry creates an instance of the Registry +func NewRegistry() Registry { + return ®istry{ + plugins: make(map[string]Plugin), + } +} + +type registry struct { + plugins map[string]Plugin +} + +// Add adds plugin to the plugin registry +func (r *registry) Add(p Plugin) error { + if p == nil { + return trace.BadParameter("missing plugin") + } + + name := p.GetName() + if name == "" { + return trace.BadParameter("missing plugin name") + } + + _, exists := r.plugins[name] + if exists { + return trace.AlreadyExists("plugin %v already exists", name) + } + + r.plugins[name] = p + + return nil +} + +// RegisterProxyWebHandlers registers Teleport Proxy web handlers +func (r *registry) RegisterProxyWebHandlers(hander interface{}) error { + for _, p := range r.plugins { + if err := p.RegisterProxyWebHandlers(hander); err != nil { + return trace.Wrap(err, "plugin %v failed to register", p.GetName()) + } + } + + return nil +} + +// RegisterAuthWebHandlers registers Teleport Auth web handlers +func (r *registry) RegisterAuthWebHandlers(handler interface{}) error { + for _, p := range r.plugins { + if err := p.RegisterAuthWebHandlers(handler); err != nil { + return trace.Wrap(err, "plugin %v failed to register", p.GetName()) + } + } + + return nil +} + +// RegisterAuthServices registerse Teleport AuthServer services +func (r *registry) RegisterAuthServices(server interface{}) error { + for _, p := range r.plugins { + if err := p.RegisterAuthServices(server); err != nil { + return trace.Wrap(err, "plugin %v failed to register", p.GetName()) + } + } + + return nil +} diff --git a/lib/service/cfg.go b/lib/service/cfg.go index 662f91f07f739..f38f41d1414e4 100644 --- a/lib/service/cfg.go +++ b/lib/service/cfg.go @@ -1,5 +1,5 @@ /* -Copyright 2015-2020 Gravitational, Inc. +Copyright 2015-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ import ( "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/pam" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/sshca" "github.com/gravitational/teleport/lib/tlsca" @@ -200,6 +201,9 @@ type Config struct { // Log optionally specifies the logger Log utils.Logger + + // PluginRegistry allows adding enterprise logic to Teleport services + PluginRegistry plugin.Registry } // ApplyToken assigns a given token to all internal services but only if token diff --git a/lib/service/service.go b/lib/service/service.go index fbd24d3ef33d6..8f9e3e7001b7b 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -1,5 +1,5 @@ /* -Copyright 2015-2020 Gravitational, Inc. +Copyright 2015-2021 Gravitational, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -69,6 +69,7 @@ import ( "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/multiplexer" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/session" @@ -241,6 +242,9 @@ type TeleportProcess struct { Supervisor Config *Config + // PluginsRegistry handles plugin registrations with Teleport services + PluginRegistry plugin.Registry + // localAuth has local auth server listed in case if this process // has started with auth server role enabled localAuth *auth.Server @@ -627,7 +631,12 @@ func NewTeleport(cfg *Config) (*TeleportProcess, error) { cfg.Clock = clockwork.NewRealClock() } + if cfg.PluginRegistry == nil { + cfg.PluginRegistry = plugin.NewRegistry() + } + process := &TeleportProcess{ + PluginRegistry: cfg.PluginRegistry, Clock: cfg.Clock, Supervisor: supervisor, Config: cfg, @@ -1180,6 +1189,7 @@ func (process *TeleportProcess) initAuthService() error { SessionService: sessionService, Authorizer: authorizer, AuditLog: process.auditLog, + PluginRegistry: process.PluginRegistry, Emitter: checkingEmitter, MetadataGetter: uploadHandler, } @@ -2501,20 +2511,21 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { } webHandler, err = web.NewHandler( web.Config{ - Proxy: tsrv, - AuthServers: cfg.AuthServers[0], - DomainName: cfg.Hostname, - ProxyClient: conn.Client, - ProxySSHAddr: proxySSHAddr, - ProxyWebAddr: cfg.Proxy.WebAddr, - ProxySettings: proxySettings, - CipherSuites: cfg.CipherSuites, - FIPS: cfg.FIPS, - AccessPoint: accessPoint, - Emitter: streamEmitter, - HostUUID: process.Config.HostUUID, - Context: process.ExitContext(), - StaticFS: fs, + Proxy: tsrv, + AuthServers: cfg.AuthServers[0], + DomainName: cfg.Hostname, + ProxyClient: conn.Client, + ProxySSHAddr: proxySSHAddr, + ProxyWebAddr: cfg.Proxy.WebAddr, + ProxySettings: proxySettings, + CipherSuites: cfg.CipherSuites, + FIPS: cfg.FIPS, + AccessPoint: accessPoint, + Emitter: streamEmitter, + PluginRegistry: process.PluginRegistry, + HostUUID: process.Config.HostUUID, + Context: process.ExitContext(), + StaticFS: fs, }) if err != nil { return trace.Wrap(err) diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index a2559a9f18e18..6376d45906df4 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -46,6 +46,7 @@ import ( "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/httplib/csrf" "github.com/gravitational/teleport/lib/jwt" + "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/secret" "github.com/gravitational/teleport/lib/services" @@ -79,16 +80,6 @@ type Handler struct { sshPort string } -// GetConfig returns handler configuration which is primarily used by plugin -func (h *Handler) GetConfig() Config { - return h.cfg -} - -// GetLogger returns handler logger which is primarily used by plugin -func (h *Handler) GetLogger() logrus.FieldLogger { - return h.log -} - // HandlerOption is a functional argument - an option that can be passed // to NewHandler function type HandlerOption func(h *Handler) error @@ -114,6 +105,8 @@ func SetClock(clock clockwork.Clock) HandlerOption { // Config represents web handler configuration parameters type Config struct { + // PluginRegistry handles plugin registration + PluginRegistry plugin.Registry // Proxy is a reverse tunnel proxy that handles connections // to local cluster or remote clusters using unified interface Proxy reversetunnel.Tunnel @@ -433,9 +426,11 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*RewritingHandler, error) { }) h.NotFound = routingHandler - plugin := GetPlugin() - if plugin != nil { - plugin.AddHandlers(h) + + if cfg.PluginRegistry != nil { + if err := cfg.PluginRegistry.RegisterProxyWebHandlers(h); err != nil { + return nil, trace.Wrap(err) + } } // Create application specific handler. This handler handles sessions and diff --git a/lib/web/plugin.go b/lib/web/plugin.go deleted file mode 100644 index 7b768ac8e9621..0000000000000 --- a/lib/web/plugin.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2017 Gravitational, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package web - -import ( - "sync" -) - -var pluginMutex = &sync.Mutex{} -var plugin Plugin - -// GetPlugin returns web API plugin that -func GetPlugin() Plugin { - pluginMutex.Lock() - defer pluginMutex.Unlock() - return plugin -} - -// SetPlugin sets plugin for the web handler -func SetPlugin(p Plugin) { - pluginMutex.Lock() - defer pluginMutex.Unlock() - plugin = p -} - -// Plugin is API Server extension setter -// if set, it will add handler methods during web handler initialization -type Plugin interface { - // AddHandlers adds handlers to the web API handler - AddHandlers(h *Handler) -} From b9070d3b53eeed75ce7407218b66cd9e4d1ff743 Mon Sep 17 00:00:00 2001 From: Alexey Kontsevoy Date: Mon, 1 Mar 2021 21:39:30 -0500 Subject: [PATCH 14/14] Update e-ref --- e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e b/e index f39fcc2ee94aa..0e18de867919f 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit f39fcc2ee94aa0c259ae4d96c89ae2bb274cdd69 +Subproject commit 0e18de867919f93284174a54ca82505fce15a4e2