Files
teleport/lib/plugin/registry.go
T
Tiago Silva 3b9de7dbde Initialize usage reporting via plugin registry after auth server setup (#64265)
* Initialize usage reporting via plugin registry after auth server setup

Usage reporting was previously initialized in enterprise process
constructors (cloud.NewTeleport, pro.NewTeleport), which ran after the
OSS auth server completed initialization. This caused enterprise auth
extensions to miss the UsageReporter service because they were initialized
after the OSS auth server was created but before the usage reporting was set up.

To fix the ordering, add a callback mechanism to plugin.Registry:
- SetUsageReportingInitFunc registers a callback to be called once the
  auth server is ready.
- InitUsageReporting triggers that callback from initAuthService, after
  setLocalAuth makes the server available to callers.

Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>

* update comment

* handle review feedback

* remove dynamic function load

* fix another addition

---------

Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>
2026-03-26 11:46:12 +00:00

146 lines
4.6 KiB
Go

/*
* Teleport
* Copyright (C) 2023 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 plugin
import (
"context"
"crypto/tls"
"github.com/gravitational/trace"
)
type getCertFunc = func() (*tls.Certificate, error)
// 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 any) error
// RegisterAuthWebHandlers registers new methods with the Auth Web Handler
RegisterAuthWebHandlers(service any) error
// RegisterAuthServices registers new services on the AuthServer
RegisterAuthServices(ctx context.Context, server any, getClientCert getCertFunc) error
}
// Registry is the plugin registry
type Registry interface {
// IsRegistered returns whether a plugin with the give name exists.
IsRegistered(name string) bool
// Add adds plugin to the registry
Add(plugin Plugin) error
// RegisterProxyWebHandlers registers Teleport Proxy web handlers
RegisterProxyWebHandlers(handler any) error
// RegisterAuthWebHandlers registers Teleport Auth web handlers
RegisterAuthWebHandlers(handler any) error
// RegisterAuthServices registers Teleport AuthServer services
RegisterAuthServices(ctx context.Context, server any, getClientCert getCertFunc) error
// SetUsageReportingInitFunc stores a callback that will be called once the OSS auth server is
// fully initialized. The callback receives a *service.TeleportProcess and is responsible for
// starting all usage-reporting pipelines. It must be set before service.NewTeleport is called.
SetUsageReportingInitFunc(func(process any) error)
// InitUsageReporting invokes the callback registered with SetUsageReportingInitFunc. It is
// called by initAuthService after setLocalAuth, ensuring the UsageReporter is available to
// auth-server enterprise extensions. The function process parameter is a *service.TeleportProcess
// instance.
// A no-op if no callback was registered.
InitUsageReporting(process any) error
}
// NewRegistry creates an instance of the Registry
func NewRegistry() Registry {
return &registry{
plugins: make(map[string]Plugin),
}
}
type registry struct {
plugins map[string]Plugin
usageReportingInitFn func(process any) error
}
func (r *registry) SetUsageReportingInitFunc(f func(process any) error) {
r.usageReportingInitFn = f
}
func (r *registry) InitUsageReporting(process any) error {
if r.usageReportingInitFn != nil {
return r.usageReportingInitFn(process)
}
return nil
}
// IsRegistered returns whether a plugin with the give name exists.
func (r *registry) IsRegistered(name string) bool {
_, ok := r.plugins[name]
return ok
}
// 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")
}
if r.IsRegistered(name) {
return trace.AlreadyExists("plugin %v already exists", name)
}
r.plugins[name] = p
return nil
}
// RegisterProxyWebHandlers registers Teleport Proxy web handlers
func (r *registry) RegisterProxyWebHandlers(handler any) error {
for _, p := range r.plugins {
if err := p.RegisterProxyWebHandlers(handler); 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 any) 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
}
func (r *registry) RegisterAuthServices(ctx context.Context, server any, getClientCert getCertFunc) error {
for _, p := range r.plugins {
if err := p.RegisterAuthServices(ctx, server, getClientCert); err != nil {
return trace.Wrap(err, "plugin %v failed to register", p.GetName())
}
}
return nil
}