server

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 20, 2023 License: GPL-3.0 Imports: 32 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (

	// ErrDirectory is an error related to directories used by the teamserver.
	ErrDirectory = errors.New("teamserver directory")

	// ErrDirectoryUnwritable is an error returned when the teamserver checked for write permissions
	// on a directory path it needs, and that the Go code of the teamserver has determined that the
	// file is really non-user writable. This error is NEVER returned "because the path does not exist".
	ErrDirectoryUnwritable = errors.New("The directory seems to be unwritable (to the app runtime)")

	// ErrLogging is an error related with the logging backend.
	// Some errors can be about writable files/directories.
	ErrLogging = errors.New("logging")

	// ErrSecureRandFailed indicates that the teamserver could not read from the system secure random source.
	ErrSecureRandFailed = errors.New("failed to read from secure rand")

	// ErrConfig is an error related to the teamserver configuration.
	ErrConfig = errors.New("teamserver config")

	// ErrDatabaseConfig is an error related to the database configuration.
	ErrDatabaseConfig = errors.New("teamserver database configuration")

	// ErrDatabase is an error raised by the database backend.
	ErrDatabase = errors.New("database")

	// ErrTeamServer is an error raised by the teamserver core code.
	ErrTeamServer = errors.New("teamserver")

	// ErrCertificate is an error related to the certificate infrastructure.
	ErrCertificate = errors.New("certificates")

	// ErrUserConfig is an error related to users (teamclients) configuration files.
	ErrUserConfig = errors.New("user configuration")

	// ErrUnauthenticated indicates that a client user could not authenticate itself,
	// whether at connection time, or when requesting server-side features/info.
	ErrUnauthenticated = errors.New("User authentication failure")

	// ErrNoListener indicates that the server could not find any listener/server
	// stack to run when one of its .Serve*() methods were invoked. If such an error
	// is raised, make sure you passed a server.Listener type with WithListener() option.
	ErrNoListener = errors.New("the teamserver has no listeners to start")

	// ErrListenerNotFound indicates that for a given ID, no running or persistent listener could be found.
	ErrListenerNotFound = errors.New("no listener exists with ID")

	// ErrListener indicates an error raised by a listener stack/implementation.
	ErrListener = errors.New("teamserver listener")
)

Functions

This section is empty.

Types

type Config

type Config struct {
	// When the teamserver command `app teamserver daemon` is executed
	// without --host/--port flags, the teamserver will use the config.
	DaemonMode struct {
		Host string `json:"host"`
		Port int    `json:"port"`
	} `json:"daemon_mode"`

	// Logging controls the file-based logging level, whether or not
	// to log TLS keys to file, and whether to log specific gRPC payloads.
	Log struct {
		Level              int  `json:"level"`
		GRPCUnaryPayloads  bool `json:"grpc_unary_payloads"`
		GRPCStreamPayloads bool `json:"grpc_stream_payloads"`
		TLSKeyLogger       bool `json:"tls_key_logger"`
	} `json:"log"`

	// Listeners is a list of persistent teamserver listeners.
	// They are started when the teamserver daemon command/mode is.
	Listeners []struct {
		Name string `json:"name"`
		Host string `json:"host"`
		Port uint16 `json:"port"`
		ID   string `json:"id"`
	} `json:"listeners"`
}

Config represents the configuration of a given application teamserver. It contains anonymous embedded structs as subsections, for logging, daemon mode bind addresses, and persistent teamserver listeners

Its default path is ~/.app/teamserver/configs/app.teamserver.cfg. It uses the following default values:

  • Daemon host: ""
  • Daemon port: 31416
  • logging file level: Info.

type Listener

type Listener interface {
	// Name returns the name of the "listener/server/RPC" stack
	// of this listener, eg. "gRPC" for a gRPC listener, "myCustomHTTP"
	// for your quick-and-dirty custom stack, etc.
	// Note that this name is used as a key by the teamserver to store the
	// different listener stacks it may use, so this name should be unique
	// among all listener stacks registered to a given teamserver runtime.
	Name() string

	// Init is used by the listener to access the core teamserver, needed for:
	//   - Fetching server-side transport/session-level credentials.
	//   - Authenticating users connections/requests.
	//   - Using the builtin teamserver loggers, filesystem and other utilities.
	// Any non-nil error returned will abort the listener starting process.
	Init(s *Server) error

	// Listen is used to create and bind a network listener to some address
	// Implementations are free to handle incoming connections the way they
	// want, since they have had access to the server in Init() for anything
	// related they might need.
	// As an example, the gRPC default transport serves a gRPC server on this
	// listener, registers its RPC services, and returns the listener for the
	// teamserver to wrap it in job control.
	// This call MUST NOT block, just like the normal usage of net.Listeners.
	Listen(addr string) (ln net.Listener, err error)

	// Close should close the listener stack.
	// This can mean different things depending on use case, but some are not recommended.
	//   - It can simply close the "listener" layer without shutting down the "server/RPC" layer.
	//   - It can shutdown anything, thus in effect disconnecting all of its clients from server.
	Close() error
}

Listener represents a teamserver listener stack. Any type implementing this interface can be served and controlled by a team/server.Server core, and remote clients can connect to it with the appropriate/corresponding team/client.Dialer backend.

Errors: all errors returned by the listener interface methods are considered critical, (except the Close() error one), and thus will stop the listener start/server process when raised. Thus, you should only return errors that are critical to the operation of your listener. You can use the teamserver loggers to log/print non-critical ones.

type Options

type Options func(opts *opts)

Options are server options. With these you can set/reset or modify the behavior of a teamserver at various stages of its lifetime, or when performing some specific actions. Note that some options can only be used once, while others can be used multiple times. Examples of the former are log files and database backends, while the latter includes listeners/hooks. Each option will specify this in its description.

func WithContinueOnError

func WithContinueOnError(continueOnError bool) Options

WithContinueOnError sets the server behavior when starting persistent listeners (either automatically when calling teamserver.ServeDaemon(), or when using teamserver.StartPersistentListeners()). If true, an error raised by a listener will not prevent others to try starting, and errors will be joined into a single one, separated with newlines and logged by default. The teamserver has this set to false by default.

This option can be used multiple times.

func WithDatabase

func WithDatabase(db *gorm.DB) Options

WithDatabase sets the server database to an existing database. Note that it will run an automigration of the teamserver types (certificates and users).

This option can only be used once, and must be passed to server.New().

func WithDatabaseConfig

func WithDatabaseConfig(config *db.Config) Options

WithDatabaseConfig sets the server to use a database backend with a given configuration.

This option can only be used once, and must be passed to server.New().

func WithDefaultPort

func WithDefaultPort(port uint16) Options

WithDefaultPort sets the default port on which the teamserver should start listeners. This default is used in the default daemon configuration, and as command flags defaults. The default port set for teamserver applications is port 31416.

This option can only be used once, and must be passed to server.New().

func WithHomeDirectory

func WithHomeDirectory(path string) Options

WithHomeDirectory sets the default path (~/.app/) of the application directory. This path can still be overridden at the user-level with the env var APP_ROOT_DIR.

This option can only be used once, and must be passed to server.New().

func WithInMemory

func WithInMemory() Options

WithInMemory deactivates all interactions of the client with the filesystem. This applies to logging, but will also to any forward feature using files.

Implications on database backends: By default, all teamservers use sqlite3 as a backend, and thus will run a database in memory. All other databases are assumed to be unable to do so, and this option will thus trigger an error whenever the option is applied, whether it be at teamserver creation, or when it does start listeners.

This option can only be used once, and must be passed to server.New().

func WithListener

func WithListener(ln Listener) Options

WithListener registers a listener/server stack with the teamserver. The teamserver can then serve this listener stack for any number of bind addresses, which users can trigger through the various server.Serve*() methods.

It accepts an optional list of pre-serve hook functions: These should accept a generic object parameter which is none other than the serverConn returned by the listener.Serve(ln) method. These hooks will be very useful- if not necessary- for library users to manipulate their server. See the server.Listener type documentation for details.

This option can be used multiple times, either when using team/server.New() or with the different server.Serve*() methods.

func WithLogFile

func WithLogFile(filePath string) Options

WithLogFile sets the path to the file where teamserver logging should be done. The default path is ~/.app/teamserver/logs/app.teamserver.log.

This option can only be used once, and must be passed to server.New().

func WithLogger

func WithLogger(logger *logrus.Logger) Options

WithLogger sets the teamserver to use a specific logger for all logging, except the audit log which is indenpendent.

This option can only be used once, and must be passed to server.New().

func WithNoLogs

func WithNoLogs(noLogs bool) Options

WithNoLogs deactivates all logging normally done by the teamserver if noLogs is set to true, or keeps/reestablishes them if false.

This option can only be used once, and must be passed to server.New().

func WithTeamDirectory

func WithTeamDirectory(name string) Options

WithTeamDirectory sets the name (not a path) of the teamserver-specific subdirectory. For example, passing "my_server_dir" will make the teamserver use ~/.app/my_server_dir/ instead of ~/.app/teamserver/. If this function is called with an empty string, the teamserver will not use any subdirectory for its own outputs, thus using ~/.app as its teamserver directory.

This option can only be used once, and must be passed to server.New().

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the core driver of an application teamserver. It is the counterpart to and plays a similar role than that of the team/client.Client type, ie. that it provides tools to any application/program to become a teamserver of itself.

The server object can run on its own, without any teamclient attached or connected: it fulfills the reeflective/team.Client interface, and any teamserver can also be a client of itself, without configuration.

The core job of the Server is to, non-exhaustively:

  • Store and manage a list of users with a zero-trust identity system (ie. public-key based), with ways to import/export these lists.
  • Register, start and control teamserver listener/server stacks, for many application clients to connect and consume the teamserver app.
  • Offer version and user information to all teamclients.

Additionally and similarly to the team/client.Client, it gives:

  • Pre-configured loggers that listener stacks and server consumers can use at any step of their application.
  • Various options to configure its backends and behaviors.
  • A builtin, app-specific abstracted filesystem (in-memory or on-disk).
  • Additionally, an API to further register and control listeners.

Various combinations of teamclient/teamserver usage are possible. Please see the Go module example/ directory for a list of them.

func New

func New(application string, options ...Options) (*Server, error)

New creates a new teamserver for the provided application name. Only one such teamserver should be created an application of any given name. Since by default, any teamserver can have any number of runtime clients, you are not required to provide any specific server.Listener type to serve clients.

This call to create the server only creates the application default directory. No files, logs, connections or any interaction with the os/filesystem are made.

Errors:

  • All errors returned from this call are critical, in that the server could not run properly in its most basic state, which may happen if the teamclient cannot use and write to its on-disk directories/backends and log files. No server is returned if the error is not nil.
  • All methods of the teamserver core which return an error will always log this error to the various teamserver log files/output streams, so that all actions of teamserver can be recorded and watched out in various places.

func (*Server) AuditLogger

func (ts *Server) AuditLogger() (*logrus.Logger, error)

AuditLogger returns a special logger writing its event entries to an audit log file (default audit.json), distinct from other teamserver log files. Listener implementations will want to use this for logging various teamclient application requests, with this logger used somewhere in your listener middleware.

func (*Server) CertificatesDir

func (ts *Server) CertificatesDir() string

CertificatesDir returns the directory storing users CA PEM files as backup, (~/.app/teamserver/certs), either on-disk or in-memory if the teamserver is.

func (*Server) ConfigPath

func (ts *Server) ConfigPath() string

ConfigPath returns the path to the server config.json file, on disk or in-memory.

func (*Server) ConfigsDir

func (ts *Server) ConfigsDir() string

Configs returns the configs directory of the server (~/.app-server/logs), creating the directory if needed, or logging a fatal event if failing to create it.

func (*Server) Database

func (ts *Server) Database() *gorm.DB

Database returns a new teamserver database session, which may not be nil: if no custom database backend was passed to the server at creation time, this database will be an in-memory one. The default is a file-based Sqlite database in the teamserver directory, but it might be a specific database passed through options.

func (*Server) DatabaseConfig

func (ts *Server) DatabaseConfig() *db.Config

DatabaseConfig returns the server database backend configuration struct. If no configuration could be found on disk, the default Sqlite file-based database is returned, with app-corresponding file paths.

func (*Server) Filesystem

func (ts *Server) Filesystem() *assets.FS

Filesystem returns an abstract filesystem used by the teamserver. This filesystem can be either of two things:

  • By default, the on-disk filesystem, without any specific bounds.
  • If the teamserver was created with the InMemory() option, a full in-memory filesystem (with root `.app/`).

Use cases for this filesystem might include:

  • The wish to have a fully abstracted filesystem to work for testing
  • Ensuring that the filesystem code in your application remains the same regardless of the underlying, actual filesystem.

The type returned is currently an internal type because it wraps some os.Filesystem methods for working more transparently: this may change in the future if the Go stdlib offers write support to its new io/fs.FS.

SERVER note: Runtime clients can run with the client.InMemory() option, without any impact on the teamserver filesystem and its behavior.

func (*Server) GetConfig

func (ts *Server) GetConfig() *Config

GetConfig returns the team server configuration as a struct. If no server configuration file is found on disk, the default one is used.

func (*Server) Handlers

func (ts *Server) Handlers() map[string]Listener

Handlers returns a copy of its teamserver listeners map. This can be useful if you want to start them with the server ServeListener() method. Or -but this is not recommended by this library- to use those listeners without the teamserver driving the init/start/serve/stop process.

func (*Server) HomeDir

func (ts *Server) HomeDir() string

HomeDir returns the root application directory (~/.app/ by default). This directory can be set with the environment variable <APP>_ROOT_DIR. This directory is not to be confused with the ~/.app/teamserver directory returned by the server.TeamDir(), which is specific to the app teamserver.

func (*Server) ListenerAdd

func (ts *Server) ListenerAdd(name, host string, port uint16) error

ListenerAdd adds a teamserver listener job to the teamserver configuration. This function does not start the given listener, and you must call the server ServeAddr(name, host, port) function for this.

func (*Server) ListenerClose

func (ts *Server) ListenerClose(id string) error

ListenerClose closes/stops an active teamserver listener by ID. This function can only return an ErrListenerNotFound if the ID is invalid: all listener-specific options are logged instead.

func (*Server) ListenerRemove

func (ts *Server) ListenerRemove(listenerID string)

ListenerRemove removes a server listener job from the configuration. This function does not stop any running listener for the given ID: you must call server.CloseListener(id) for this.

func (*Server) ListenerStartPersistents

func (ts *Server) ListenerStartPersistents() error

ListenerStartPersistents attempts to start all listeners saved in the teamserver configuration file, looking up the listener stacks in its map and starting them for each bind target. If the teamserver has been passed the WithContinueOnError() option at some point, it will log all errors raised by listener stacks will still try to start them all.

func (*Server) Listeners

func (ts *Server) Listeners() []*job

Listeners returns a list of all running listener jobs. If you also want the list of the non-running, persistent ones, use the teamserver Config().

func (*Server) LogsDir

func (ts *Server) LogsDir() string

LogsDir returns the log directory of the server (~/.app-server/logs), creating the directory if needed, or logging a fatal event if failing to create it.

func (*Server) Name

func (ts *Server) Name() string

Name returns the name of the application handled by the teamserver. Since you can embed multiple teamservers (one for each application) into a single binary, this is different from the program binary name running this teamserver.

func (*Server) NamedLogger

func (ts *Server) NamedLogger(pkg, stream string) *logrus.Entry

NamedLogger returns a new logging "thread" with two fields (optional) to indicate the package/general domain, and a more precise flow/stream. The events are logged according to the teamclient logging backend setup.

func (*Server) SaveConfig

func (ts *Server) SaveConfig(cfg *Config) error

SaveConfig saves config file to disk. This uses the on-disk filesystem even if the teamclient is in memory mode.

func (*Server) Self

func (ts *Server) Self(opts ...client.Options) *client.Client

Self returns a new application team/client.Client (with the same app name), using any provided options for client behavior.

This teamclient implements by default the root team/Teamclient interface (directly through the server), but passing user-specific dialer stack options to this function and by providing the corresponding server options for your pair, you can use in-memory clients which will use the complete RPC stack of the application using this teamserver. See the server.Listener and client.Dialer types documentation for more.

func (*Server) Serve

func (ts *Server) Serve(cli *client.Client, opts ...Options) error

Serve attempts the default listener of the teamserver (which is either the first one to have been registered, or the only one registered at all). It the responsibility of any teamclients produced by the teamserver.Self() method to call their Connect() method: the server will answer.

func (*Server) ServeAddr

func (ts *Server) ServeAddr(name string, host string, port uint16, opts ...Options) (id string, err error)

ServeAddr attempts to serve a listener stack identified by "name" (the listener should be registered with the teamserver with WithListener() option), on a given host:port address, with any provided option. If returns either a critical error raised by the listener, or the ID of the listener job, for control. The call is non-blocking, contrarily to the server.ServeDaemon() method.

func (*Server) ServeDaemon

func (ts *Server) ServeDaemon(host string, port uint16, opts ...Options) (err error)

ServeDaemon is a blocking call which starts the teamserver as daemon process, using either the provided host:port arguments, or the ones found in the teamserver config. This function will also (and is the only one to) start all persistent team listeners.

It blocks by waiting for a syscal.SIGTERM (eg. CtrlC on Linux) signal. Upon receival, the teamserver will close the main listener (the daemon one), but not persistent ones.

Errors raised by closing the listener are wrapped in an ErrListener, logged and returned.

func (*Server) SetLogLevel

func (ts *Server) SetLogLevel(level int)

SetLogLevel sets the logging level of teamserver loggers (excluding audit ones).

func (*Server) TeamDir

func (ts *Server) TeamDir() string

TeamDir returns the teamserver directory of the app (named ~/.<app>/teamserver/), creating the directory if needed, or logging an error event if failing to create it. This directory is used to store teamserver certificates, database, logs, and configs.

func (*Server) UserAuthenticate

func (ts *Server) UserAuthenticate(rawToken string) (name string, authorized bool, err error)

UserAuthenticate accepts a raw 128-bits long API Authentication token belonging to the user of a connected/connecting teamclient. The token is hashed and checked against the teamserver users database for the matching user. This function shall alternatively return:

  • The name of the authenticated user, true for authenticated and no error.
  • No name, false for authenticated, and an ErrUnauthenticated error.
  • No name, false for authenticated, and a database error, if was ignited now.

This call updates the last time the user has been seen by the server.

func (*Server) UserCreate

func (ts *Server) UserCreate(name string, lhost string, lport uint16) (*client.Config, error)

UserCreate creates a new teamserver user, with all cryptographic material and server remote endpoints needed by this user to connect to us.

Certificate files and the API authentication token are saved into the teamserver database, conformingly to its configured backend/filesystem (can be in-memory or on filesystem).

func (*Server) UserDelete

func (ts *Server) UserDelete(name string) error

UserDelete deletes a user and its cryptographic materials from the teamserver database, clearing the API auth tokens cache.

WARN: This function has two very precise effects/consequences:

  1. The server-side Mutual TLS configuration obtained with server.GetUserTLSConfig() will refuse all connections using the deleted user TLS credentials, returning an authentication failure.
  2. The server.AuthenticateUser(token) method will always return an ErrUnauthenticated error from the call, because the delete user is not in the database anymore.

Thus, it is up to the users of this library to use the builting teamserver TLS configurations in their teamserver listener / teamclient dialer implementations.

Certificate files, API authentication token are deleted from the teamserver database, conformingly to its configured backend/filesystem (can be in-memory or on filesystem).

func (*Server) Users

func (ts *Server) Users() ([]team.User, error)

Users returns the list of users in the teamserver database, and their information. Any error raised during querying the database is returned, along with all users.

func (*Server) UsersGetCA

func (ts *Server) UsersGetCA() ([]byte, []byte, error)

UsersGetCA returns the bytes of a PEM-encoded certificate authority, which contains certificates of all users of this teamserver.

func (*Server) UsersSaveCA

func (ts *Server) UsersSaveCA(cert, key []byte)

UsersSaveCA accepts the public and private parts of a Certificate Authority containing one or more users to add to the teamserver.

func (*Server) UsersTLSConfig

func (ts *Server) UsersTLSConfig() (*tls.Config, error)

UsersTLSConfig returns a server-side Mutual TLS configuration struct, ready to run. The configuration performs all and every verifications that the teamserver should do, and peer TLS clients (teamclient.Config) are not allowed to choose any TLS parameters.

This should be used by team/server.Listeners at the net.Listener/net.Conn level. As for all errors of the teamserver API, any error returned here is defered-logged.

func (*Server) VersionClient

func (ts *Server) VersionClient() (team.Version, error)

VersionClient implements team.Client.VersionClient() interface method, so that the teamserver can be a teamclient of itself. This simply returns the server.VersionServer() output.

func (*Server) VersionServer

func (ts *Server) VersionServer() (team.Version, error)

VersionServe returns the teamserver binary version information.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL