### Start and Use Kerberos Service for Testing Source: https://github.com/containerssh/containerssh/blob/main/internal/test/README.md Shows how to start a Kerberos service and authenticate using it with a generated configuration. The Kerberos server image may take time to build locally. It is recommended to configure tests to work without DNS lookups. ```go package your_test import ( "fmt" "testing" "github.com/containerssh/test" "github.com/containerssh/gokrb5/v8/client" "github.com/containerssh/gokrb5/v8/config" ) var krbConf = ` [libdefaults] dns_lookup_realm = false dns_lookup_kdc = false [realms] %s = { kdc = 127.0.0.1:88 } [domain_realm] ` func TestKerberos(t *testing.T) { krb := test.Kerberos(t) krbConfig, err := config.NewFromString(fmt.Sprintf(krbConf, krb.Realm())) if err != nil { t.Fatalf("invalid Kerberos config (%v)", err) } cli := client.NewWithPassword( krb.AdminUsername(), krb.Realm(), krb.AdminPassword(), krbConfig, ) if err := cli.Login(); err != nil { t.Fatalf("failed to login (%v)", err) } } ``` -------------------------------- ### Start and Use S3 Service for Testing Source: https://github.com/containerssh/containerssh/blob/main/internal/test/README.md Demonstrates how to start an S3 service using the test helper and configure an AWS client to use it. Ensure the Docker socket is exposed for the service to function. ```go package your_test import ( "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" "github.com/containerssh/test" ) func TestYourFunc(t *testing.T) { s3Service := test.S3(t) awsConfig := &aws.Config{ Credentials: credentials.NewCredentials( &credentials.StaticProvider{ Value: credentials.Value{ AccessKeyID: s3Service.AccessKey(), SecretAccessKey: s3Service.SecretKey(), }, }, ), Endpoint: aws.String(s3Service.URL()), Region: aws.String(s3Service.Region()), S3ForcePathStyle: aws.Bool(s3Service.PathStyle()), } sess, err := session.NewSession(awsConfig) if err != nil { t.Fatalf("failed to establish S3 session (%v)", err) } s3Connection := s3.New(sess) // ... } ``` -------------------------------- ### Start and Stop ContainerSSH Test Server Source: https://github.com/containerssh/containerssh/blob/main/internal/sshserver/README.md Demonstrates how to start the test server in the background and subsequently stop it with a specified timeout. ```go srv.Start() defer srv.Stop(10 * time.Second) ``` -------------------------------- ### Creating an Authentication Server Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md This example demonstrates how to create and run an authentication server using the `auth.NewServer` function and the `service.NewLifecycle` facility. ```APIDOC ## Creating an Authentication Server Use the `auth.NewServer` function to create a server instance with your custom handler. ### Server Creation and Lifecycle Management ```go import ( "context" "github.com/containerssh/containerssh/auth" "github.com/containerssh/containerssh/http" "github.com/containerssh/containerssh/log" "github.com/containerssh/containerssh/service" ) // Assume logger is initialized from log.New(...) var logger log.Logger // Assume myHandler is an implementation of the auth.Handler interface var handler *myHandler func main() { server := auth.NewServer( http.ServerConfiguration{ Listen: "127.0.0.1:8080", }, handler, logger, ) lifecycle := service.NewLifecycle(server) go func() { if err := lifecycle.Run(); err != nil { // Handle error logger.Criticalf("server failed to run: %v", err) } }() // To shut down the server: // lifecycle.Stop(context.Background()) } ``` **Note:** The server configuration can optionally include mutual TLS authentication. Refer to the [http library documentation](https://github.com/containerssh/containerssh/tree/main/http) for details. ``` -------------------------------- ### Create Configuration Webhook Server Source: https://github.com/containerssh/containerssh/blob/main/README.md Set up and run a dedicated web server for configuration webhook requests. This example includes signal handling for graceful shutdown. ```go package main import ( "signal" "context" "fmt" "os" "syscall" "time" "go.containerssh.io/containerssh/config" "go.containerssh.io/containerssh/config/webhook" "go.containerssh.io/containerssh/log" "go.containerssh.io/containerssh/service" ) func main() { logger := log.NewLogger(&config.LogConfig{ // Add logging configuration here }) // Create the webserver service srv, err := webhook.NewServer( config.HTTPServerConfiguration{ Listen: "0.0.0.0:8080", }, &myConfigReqHandler{}, logger, ) if err != nil { panic(err) } // Set up the lifecycle handler lifecycle := service.NewLifecycle(srv) // Launch the webserver in the background go func() { //Ignore error, handled later. _ = lifecycle.Run() }() // Handle signals and terminate webserver gracefully when needed. signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) go func() { if _, ok := <-signals; ok { // ok means the channel wasn't closed, let's trigger a shutdown. // The context given is the timeout for the shutdown. lifecycle.Stop( context.WithTimeout( context.Background(), 20 * time.Second, ), ) } }() // Wait for the service to terminate. lastError := lifecycle.Wait() // We are already shutting down, ignore further signals signal.Ignore(syscall.SIGINT, syscall.SIGTERM) // close signals channel so the signal handler gets terminated close(signals) if lastError != nil { // Exit with a non-zero signal fmt.Fprintf( os.Stderr, "an error happened while running the server (%v)", lastError, ) os.Exit(1) } os.Exit(0) } ``` -------------------------------- ### Run Configuration Server with Service Lifecycle Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Start the configuration server using the `service.NewLifecycle` and run it indefinitely. Implement signal handling for graceful shutdown. ```go lifecycle := service.NewLifecycle(srv) err := lifecycle.Run() ``` ```go srv, err := webhook.NewServer( http.ServerConfiguration{ Listen: "0.0.0.0:8080", }, &myConfigReqHandler{}, logger, ) if err != nil { // Handle error } lifecycle := service.NewLifecycle(srv) go func() { //Ignore error, handled later. _ = lifecycle.Run() }() signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) go func() { if _, ok := <-signals; ok { // ok means the channel wasn't closed, let's trigger a shutdown. lifecycle.Shutdown( context.WithTimeout( context.Background(), 20 * time.Second, ) ) } }() // Wait for the service to terminate. lastError := lifecycle.Wait() // We are already shutting down, ignore further signals signal.Ignore(syscall.SIGINT, syscall.SIGTERM) // close signals channel so the signal handler gets terminated close(signals) if err != nil { // Exit with a non-zero signal fmt.Fprintf( os.Stderr, "an error happened while running the server (%v)", err, ) os.Exit(1) } os.Exit(0) ``` -------------------------------- ### Start a Metrics HTTP Server Source: https://github.com/containerssh/containerssh/blob/main/internal/metrics/README.md Initialize and run a dedicated HTTP server for exposing metrics. This requires a service lifecycle and a logger. The server can be stopped gracefully. ```go server := metrics.NewServer( metrics.Config{ ServerConfiguration: http.ServerConfiguration{ Listen: "127.0.0.1:8080", }, Enable: true, Path: "/metrics", }, metricsCollector, logger, ) lifecycle := service.NewLifecycle(server) go func() { if err := lifecycle.Run(); err != nil { // Handle crash } t }() //Later: lifecycle.Stop(context.Background()) ``` -------------------------------- ### Implementing the Handler Interface Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md This example shows how to implement the `Handler` interface for creating a custom authentication server. It includes methods for handling password and public key authentication. ```APIDOC ## Implementing the Handler Interface To create a server, you need to implement the `Handler` interface. ### Interface Definition ```go type Handler interface { // OnPassword is called when a user tries to authenticate with a password. OnPassword(Username string, Password []byte, RemoteAddress string, ConnectionID string) (bool, error) // OnPubKey is called when a user tries to authenticate with a public key. OnPubKey(Username string, PublicKey string, RemoteAddress string, ConnectionID string) (bool, error) } ``` ### Example Implementation ```go type myHandler struct { } func (h *myHandler) OnPassword( Username string, Password []byte, RemoteAddress string, ConnectionID string, ) (bool, error) { if Username == "foo" && string(Password) == "bar" { return true, nil } if Username == "crash" { // Simulate a database failure return false, fmt.Errorf("database error") } return false, nil } func (h *myHandler) OnPubKey( Username string, // PublicKey is the public key in the authorized key format. PublicKey string, RemoteAddress string, ConnectionID string, ) (bool, error) { // Handle public key auth here return false, nil // Placeholder } ``` ``` -------------------------------- ### Add Starting Hook to ContainerSSH Lifecycle Source: https://github.com/containerssh/containerssh/blob/main/README.md Register a function to be executed when ContainerSSH starts. This must be done before calling `Run()`. ```go lifecycle.OnStarting( func(s service.Service, l service.Lifecycle) { print("ContainerSSH is starting...") }, ) ``` -------------------------------- ### Using the Authentication Handler with Go's HTTP Library Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md This example shows how to integrate the ContainerSSH authentication handler directly with Go's standard `net/http` library. ```APIDOC ## Using the Authentication Handler with Go's HTTP Library You can also use the `auth.NewHandler` function to create an `http.Handler` that can be used with Go's native HTTP server. ### Example Integration ```go import ( "net/http" "github.com/containerssh/containerssh/auth" "github.com/containerssh/containerssh/log" ) // Assume logger is initialized from log.New(...) var logger log.Logger // Assume myHandler is an implementation of the auth.Handler interface var handler *myHandler func main() { httpHandler := auth.NewHandler(handler, logger) http.Handle("/auth", httpHandler) err := http.ListenAndServe(":8090", nil) if err != nil { // Handle error logger.Criticalf("HTTP server failed: %v", err) } } ``` ``` -------------------------------- ### Create and Use a Service Lifecycle Source: https://github.com/containerssh/containerssh/blob/main/service/README.md Instantiate a `Lifecycle` object using `service.NewLifecycle()`, passing the associated service. Use the lifecycle to register state change hooks and then call `lifecycle.Run()` to start the service. ```go lifecycle := service.NewLifecycle(service) ``` ```go lifecycle.OnStateChange(func(s service.Service, l service.Lifecycle, newState service.State) { // do something }) lifecycle.OnStarting(func(s service.Service, l service.Lifecycle) { // do something }) lifecycle.OnRunning(func(s service.Service, l service.Lifecycle) { // do something }) lifecycle.OnStopping(func(s service.Service, l service.Lifecycle, shutdownContext context.Context) { // do something }) lifecycle.OnStopped(func(s service.Service, l service.Lifecycle) { // do something }) lifecycle.OnCrashed(func(s service.Service, l service.Lifecycle, err error) { // do something }) ``` ```go err := lifecycle.Run() ``` -------------------------------- ### Audit Logger Configuration Example Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlog/README.md Defines a sample configuration for the audit logger, specifying enablement, format, storage type, file directory, and interception settings for various data types. ```go config := auditlog.Config{ Enable: true, Format: "binary", Storage: "file", File: file.Config{ Directory: "/tmp/auditlog", }, Intercept: auditlog.InterceptConfig{ Stdin: true, Stdout: true, Stderr: true, Passwords: true, }, } ``` -------------------------------- ### Handle Shell Request Source: https://github.com/containerssh/containerssh/blob/main/internal/docker/README.md Handles a request to start a shell on an SSH session channel. This provides an interactive terminal experience. ```go var requestID uint64 = 0 var stdin io.Reader var stdout, stderr io.Writer err = session.OnShell( requestID, stdin, stdout, stderr, func(exitStatus ExitStatus) { // ... }, ) ``` -------------------------------- ### Run ContainerSSH Service Source: https://github.com/containerssh/containerssh/blob/main/README.md Start the ContainerSSH service pool. This call blocks execution until ContainerSSH stops. ```go err := lifecycle.Run() ``` -------------------------------- ### Start New Connection Audit Log Entry Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlog/README.md Records the initiation of a new connection in the audit log. This method returns a connection-specific logger for subsequent events. ```go connectionID := "0123456789ABCDEF" connection, err := auditLogger.OnConnect( []byte("asdf"), net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 2222, Zone: "", }, ) ``` -------------------------------- ### Implement Writable Storage Interface Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlog/README.md Implement the `io.WriteCloser` interface along with the `SetMetadata` function to provide custom writable storage for audit logs. The `SetMetadata` function allows setting connection start time, source IP, and username. ```go SetMetadata(startTime int64, sourceIp string, username *string) ``` -------------------------------- ### Create Audit Logger with Custom Pipeline Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlog/README.md Constructs an audit logger by providing custom implementations for interception, encoding, storage, and logging. This allows for a more flexible pipeline setup. ```go auditLogger := auditlog.NewLogger( intercept, encoder, storage, logger, ) ``` -------------------------------- ### Create SSH Session Channel Source: https://github.com/containerssh/containerssh/blob/main/internal/docker/README.md Creates a new SSH session channel for a given connection. This is used to execute commands or start shells within the container. ```go var channelID uint64 = 0 extraData := []byte{} session, err := ssh.OnSessionChannel(channelID, extraData) ``` -------------------------------- ### Embed Metrics Handler in an HTTP Server Source: https://github.com/containerssh/containerssh/blob/main/internal/metrics/README.md Create a metrics handler that can be embedded into any existing Go HTTP server. This avoids starting a separate HTTP server process. ```go handler := metrics.NewHandler( "/metrics", metricsCollector ) http.ListenAndServe("0.0.0.0:8080", handler) ``` -------------------------------- ### Set up HTTP Server Source: https://github.com/containerssh/containerssh/blob/main/http/README.md Configure and run an HTTP server with optional TLS and client certificate authentication. Integrates with a service lifecycle for graceful startup and shutdown. ```go server, err := http.NewServer( "service name", http.ServerConfiguration{ Listen: "127.0.0.1:8080", // You can also add TLS configuration // and certificates here: Key: "PEM-encoded key or file name to cert here.", Cert: "PEM-encoded certificate chain or file name here", // Authenticate clients with certificates: ClientCACert: "PEM-encoded client CA certificate or file name here", }, handler, logger, func (url string) { fmt.Printf("Server is now ready at %s", url) } ) if err != nil { // Handle configuration error } // Lifecycle from the github.com/containerssh/service package lifecycle := service.NewLifecycle(server) go func() { if err := lifecycle.Run(); err != nil { // Handle error } }() // Do something else, then shut down the server. // You can pass a context for the shutdown deadline. lifecycle.Shutdown(context.Background()) ``` -------------------------------- ### Create a New Configuration Server Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Instantiate a new configuration server using your custom handler and logger. The server listens on the specified address. ```go srv, err := configuration.NewServer( config.HTTPServerConfiguration{ Listen: "0.0.0.0:8080", }, &myConfigReqHandler{}, logger, ) ``` -------------------------------- ### Create Configuration Client Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Instantiate a new configuration client with provided HTTP client configuration, logger, and metrics collector. Ensure the logger and metricsCollector are properly initialized from their respective libraries. ```go client, err := configuration.NewClient( configuration.ClientConfig{ http.ClientConfiguration{ URL: "http://your-server/config-endpoint/" } }, logger, metricsCollector, ) ``` -------------------------------- ### Create and Run SSH Server Source: https://github.com/containerssh/containerssh/blob/main/internal/sshserver/README.md Instantiates a new SSH server, runs its lifecycle, and gracefully shuts it down after a delay. Ensure `cfg`, `handler`, and `logger` are properly initialized before use. ```go server, err := sshserver.New( cfg, handler, logger, ) if err != nil { // Handle configuration errors log.Fatalf("%v", err) } lifecycle := service.NewLifecycle(server) defer func() { // The Run method will run the server and return when the server is shut down. // We are running this in a goroutine so the shutdown below can proceed after a minute. if err := lifecycle.Run(); err != nil { // Handle errors while running the server } }() time.Sleep(60 * time.Second) // Shut down the server. Pass a context to indicate how long the server should wait // for existing connections to finish. This function will return when the server // has stopped. lifecycle.Stop( context.WithTimeout( context.Background(), 30 * time.Second, ), ) ``` -------------------------------- ### Initialize GeoIP Provider Source: https://github.com/containerssh/containerssh/blob/main/internal/geoip/README.md Instantiate a GeoIP provider with configuration. Supports 'dummy' or 'maxmind' providers. Ensure the GeoIP2File path is correct for the MaxMind provider. ```go provider, err := geoip.New(geoip.Config{ // Can be "dummy" or "maxmind". Provider: "maxmind", // MMDB2 file for the MaxMind provider. GeoIP2File: "/path/to/maxmind/file.mmdb2", }) if err != nil { // handle error } ``` -------------------------------- ### Create Authentication HTTP Client Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md Create an HTTP client for authentication servers. Configure the client with the server URL, supported authentication methods, and timeouts for requests and the overall process. ```go client := auth.NewHttpAuthClient( auth.ClientConfig{ URL: "http://localhost:8080" Password: true, PubKey: false, // This is the timeout for individual requests. Timeout: 2 * time.Second, // This is the overall timeout for the authentication process. AuthTimeout: 60 * time.Second, }, logger, ) ``` -------------------------------- ### Create Authentication Server with HTTP Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md Create a new authentication server using the http library and a custom handler. The server requires a logger and uses the service lifecycle for running and stopping. ```go server := auth.NewServer( http.ServerConfiguration{ Listen: "127.0.0.1:8080", }, &myHandler{}, logger, ) lifecycle := service.NewLifecycle(server) go func() { if err := lifecycle.Run(); err != nil { // Handle error } } // When done, shut down server with an optional context for the shutdown deadline lifecycle.Stop(context.Background()) ``` -------------------------------- ### Create HTTP Configuration Loader Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Initialize an HTTP loader to fetch configuration from the configuration server. This loader can be chained with other loaders. ```go httpLoader, err := configuration.NewHTTPLoader(clientConfig, logger) ``` -------------------------------- ### Create ContainerSSH Instance Source: https://github.com/containerssh/containerssh/blob/main/README.md Instantiate ContainerSSH with your configuration and a logger factory. Handles potential errors during initialization. ```go pool, lifecycle, err := containerssh.New(cfg, loggerFactory) if err != nil { return err } ``` -------------------------------- ### Creating a Logger Instance Source: https://github.com/containerssh/containerssh/blob/main/log/README.md Demonstrates how to create a new logger instance using `NewLogger` or `MustNewLogger`. ```APIDOC ## Creating a Logger Instance ### Description Provides methods to create a new logger instance. ### Methods - `NewLogger(config Config) (Logger, error)`: Creates a new logger instance. Returns an error if creation fails. - `MustNewLogger(config Config) Logger`: Creates a new logger instance. Panics if an error occurs during creation. ``` -------------------------------- ### Initializing the GeoIP Provider Source: https://github.com/containerssh/containerssh/blob/main/internal/geoip/README.md Demonstrates how to initialize the GeoIP provider with a configuration, specifying the provider type and the path to the GeoIP database file. ```APIDOC ## Initialize GeoIP Provider ### Description Initializes a GeoIP lookup provider. You can choose between different providers like "dummy" or "maxmind". For the "maxmind" provider, you need to specify the path to the GeoIP2 database file. ### Method Signature `geoip.New(config geoip.Config) (LookupProvider, error)` ### Parameters #### Request Body - **config** (geoip.Config) - Required - Configuration for the GeoIP provider. - **Provider** (string) - Required - The type of provider to use (e.g., "dummy", "maxmind"). - **GeoIP2File** (string) - Optional - Path to the MaxMind GeoIP2 database file (required if Provider is "maxmind"). ### Response #### Success Response (LookupProvider) - Returns an initialized `LookupProvider` interface. #### Error Response - Returns an `error` if initialization fails. ``` -------------------------------- ### Add ContainerSSH Configuration as Dependency Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Use go modules to fetch the configuration library as a dependency. ```bash go get github.com/containerssh/configuration ``` -------------------------------- ### Create Configuration Loader from File Source: https://github.com/containerssh/containerssh/blob/main/README.md Initialize a configuration loader to read settings from an `io.Reader`, such as a file. Supports formats like YAML. The loader can be chained with other loaders, like an HTTP loader. ```go file, err := os.Open("file.yaml") // ... loader, err := configuration.NewReaderLoader( file, logger, configuration.FormatYAML, ) ``` -------------------------------- ### Create and Use HTTP Client Source: https://github.com/containerssh/containerssh/blob/main/http/README.md Configure and use an HTTP client to send POST requests. Handles request marshaling and response filling. Includes error handling for connection issues and response status codes. ```go logger := standard.New() clientConfig := http.ClientConfiguration{ URL: "http://127.0.0.1:8080/", Timeout: 2 * time.Second, // You can add TLS configuration here: CaCert: "Add expected CA certificate(s) here.", // CaCert is required for https:// URLs on Windows due to golang#16736 // Optionally, for client authentication: ClientCert: "Client certificate in PEM format or file name", ClientKey: "Client key in PEM format or file name", // Optional: switch to www-urlencoded request body RequestEncoding: http.RequestEncodingWWWURLEncoded, } client, err := http.NewClient(clientConfig, logger) if err != nil { // Handle validation error } request := yourRequestStruct{} response := yourResponseStruct{} responseStatus, err := client.Post( context.TODO(), "/relative/path/from/base/url", &request, &response, ) if err != nil { // Handle connection error clientError := &http.ClientError{} if errors.As(err, clientError) { // Grab additional information here } else { // This should never happen } } if responseStatus > 399 { // Handle error } ``` -------------------------------- ### Implement SSH Conformance Tests Source: https://github.com/containerssh/containerssh/blob/main/internal/sshserver/README.md Sets up a map of factories for different authentication methods to run conformance tests against an SSH server implementation. Each factory should return a `NetworkConnectionHandler`. ```go func TestConformance(t *testing.T) { var factories = map[string]func() ( sshserver.NetworkConnectionHandler, error, ) { "some-method": func( logger log.Logger, ) (sshserver.NetworkConnectionHandler, error) { }, "some-other-method": func( logger log.Logger, ) (sshserver.NetworkConnectionHandler, error) { }, } sshserver.RunConformanceTests(t, factories) } ``` -------------------------------- ### Create Default Logger (Panic on Error) Source: https://github.com/containerssh/containerssh/blob/main/log/README.md Use this method to create the default logger implementation if you prefer to panic on error instead of handling it explicitly. Use with caution. ```go logger := log.MustNewLogger(config) ``` -------------------------------- ### Create Configuration Handler for Existing HTTP Server Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Generate a handler compatible with Go's `net/http` package or other MUXes by using `configuration.NewHandler` with your custom handler and logger. ```go handler, err := configuration.NewHandler(&myConfigReqHandler{}, logger) ``` -------------------------------- ### Create ContainerSSH Test Server Source: https://github.com/containerssh/containerssh/blob/main/internal/sshserver/README.md Instantiate a simplified test server that can be connected to any backend. This server is useful for testing purposes. ```go srv := NewTestServer( handler, logger, ) ``` -------------------------------- ### Create New Backend Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/backend/README.md Instantiate a new backend handler by providing configuration, loggers, and authentication behavior. This handler can then be passed to the sshserver or other overlays. ```go handler, err := backend.New( config, logger, loggerFactory, authBehavior, ) ``` -------------------------------- ### Load Configuration from File (YAML) Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Read and load application configuration from a YAML file using a configuration loader. Supports loading global and connection-specific configurations. ```go file, err := os.Open("file.yaml") // ... loader, err := configuration.NewReaderLoader( file, logger, configuration.FormatYAML, ) // Read global config appConfig := &configuration.AppConfig{} err := loader.Load(ctx, appConfig) // Read connection-specific config: err := loader.LoadConnection( ctx, "my-name-is-trinity", net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 2222, }, connectionID, appConfig, ) ``` -------------------------------- ### Fetch Client-Specific Configuration Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Retrieve configuration details for a specific client connection using the configuration client. Requires a context, client name, network address, and connection ID. ```go connectionID := "0123456789ABCDEF" appConfig, err := client.Get( ctx, "my-name-is-trinity", net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 2222, }, connectionID, ) (AppConfig, error) ``` -------------------------------- ### Initialize Readable Storage Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlog/README.md Creates a storage instance and casts it to a `ReadableStorage` interface. This is necessary for listing and opening audit log entries. This operation may fail if the storage type is 'none'. ```go storage, err := auditlog.NewStorage(config, logger) if err != nil { log.Fatalf("%v", err) } // This only works if the storage type is not "none" readableStorage := storage.(storage.ReadableStorage) ``` -------------------------------- ### Create Default Logger Implementation Source: https://github.com/containerssh/containerssh/blob/main/log/README.md Instantiate the default logger implementation using a configuration object. Ensure you handle the potential error returned. ```go logger, err := log.NewLogger(config) ``` -------------------------------- ### Create a new service pool Source: https://github.com/containerssh/containerssh/blob/main/service/README.md Instantiate a new service pool with a lifecycle factory and a logger. ```go pool := service.NewPool( service.NewLifecycleFactory(), logger, ) ``` -------------------------------- ### Load Global Configuration from Loader Source: https://github.com/containerssh/containerssh/blob/main/README.md Read global application configuration settings into an `AppConfig` struct using a previously created loader. Ensure the `ctx` is valid and the `appConfig` pointer is correctly initialized. ```go appConfig := &configuration.AppConfig{} err := loader.Load(ctx, appConfig) ``` -------------------------------- ### Create ContainerSSH Test Client Source: https://github.com/containerssh/containerssh/blob/main/internal/sshserver/README.md Use this to create a test client for interacting with the ContainerSSH server. The server's private key in PEM format is required to extract the public key for validation. ```go sshclient := NewTestClient( serverIPAndPort, serverHostPrivateKey, user *TestUser, logger log.Logger, ) ``` -------------------------------- ### Create Standard Logger Instance Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlog/README.md Initializes a standard logger instance using the `standard.New()` function. This logger can be passed to the audit logger. ```go logger := standard.New() ``` -------------------------------- ### Create ContainerSSH Configuration Source: https://github.com/containerssh/containerssh/blob/main/README.md Initialize and set default configuration for embedding ContainerSSH. This is the first step before creating a ContainerSSH instance. ```go cfg := config.AppConfig{} // Set the default configuration: cfg.Default() ``` -------------------------------- ### Creating an Authentication Client Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md This section details how to create and use the ContainerSSH HTTP client to authenticate with an authentication server. ```APIDOC ## Creating an Authentication Client The library provides an HTTP client for authentication servers. ### Client Configuration and Usage ```go import ( "time" "github.com/containerssh/containerssh/auth" "github.com/containerssh/containerssh/log" ) // Assume logger is initialized from log.New(...) var logger log.Logger func main() { client := auth.NewHttpAuthClient( auth.ClientConfig{ URL: "http://localhost:8080", Password: true, PubKey: false, // This is the timeout for individual requests. Timeout: 2 * time.Second, // This is the overall timeout for the authentication process. AuthTimeout: 60 * time.Second, }, logger, ) // Authenticate using password success, err := client.Password( "foo", []byte("bar"), "0123456789ABCDEF", // ConnectionID "192.168.1.1", // Remote Address (ip) ) if err != nil { // Handle error logger.Errorf("password authentication failed: %v", err) } if success { logger.Infof("Password authentication successful") } // Authenticate using public key success, err = client.PubKey( "foo", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD...", // PublicKey "0123456789ABCDEF", // ConnectionID "192.168.1.1", // Remote Address (ip) ) if err != nil { // Handle error logger.Errorf("public key authentication failed: %v", err) } if success { logger.Infof("Public key authentication successful") } } ``` ``` -------------------------------- ### Create Authenticating Handler with ContainerSSH Source: https://github.com/containerssh/containerssh/blob/main/internal/authintegration/README.md Use this to create a new handler that integrates authentication. Configure the auth client, backend handler, logger, and passthrough behavior. ```go handler := authintegration.New( auth.ClientConfig{ URL: "http://localhost:8080" Password: true, PubKey: false, }, otherHandler, logger, authintegration.BehaviorNoPassthrough, ) ``` -------------------------------- ### Define a Service with RunWithLifecycle Source: https://github.com/containerssh/containerssh/blob/main/service/README.md Implement the `Service` interface by defining a `String()` method and a `RunWithLifecycle()` method. The `RunWithLifecycle()` method must call lifecycle hooks like `Running()`, `ShouldStop()`, and `Stopping()` to manage the service's state. ```go type Service interface { // String returns the name of the service String() string RunWithLifecycle(lifecycle Lifecycle) error } ``` ```go func (s *myService) RunWithLifecycle(lifecycle Lifecycle) error { //Do initialization here lifecycle.Running() for { // Do something if err != nil { return err } if lifecycle.ShouldStop() { shutdownContext := lifecycle.Stopping() // Handle graceful shutdown. // If shutdownContext expires, shut down immediately. // Then exit out of the loop. break } } return nil } ``` -------------------------------- ### Instantiate Health Check Client Source: https://github.com/containerssh/containerssh/blob/main/internal/health/README.md Create a new health check client instance. The configuration must include the URL of the health check service to connect to. ```go client, err := health.NewClient( health.Config{ Enable: true, Client: http.ClientConfiguration{ URL: "http://0.0.0.0:23074", }, }, logger) ) if client.Run() { // Success } else { // Failed } ``` -------------------------------- ### Create Audit Logger with Configuration Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlog/README.md Instantiate the audit logger using a configuration object, a GeoIP lookup provider, and a logger instance. Ensure the logger is from the containerssh/log library. ```go auditLogger, err := auditlog.New(cfg, geoIPLookupProvider, logger) ``` -------------------------------- ### Perform Public Key Authentication with Client Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md Use the authentication client to perform public key-based authentication. Provide the username, public key, connection ID, and remote IP address. ```go success, err := client.PubKey( "foo", "ssh-rsa ...", "0123456789ABCDEF", ip ) (bool, error) ``` -------------------------------- ### Instantiate Metrics Integration Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/metricsintegration/README.md Use this method to create a new handler with metrics integration enabled. Pass configuration, a metrics collector, and the backend SSH server handler. ```go handler, err := metricsintegration.New( config, metricsCollector, backend, ) ``` -------------------------------- ### Add a service and attach a running hook Source: https://github.com/containerssh/containerssh/blob/main/service/README.md Add a subservice to the pool and chain a hook to execute when the service is running. The hook logs the service's string representation and its current state. ```go _ = pool. Add(myService1). OnRunning(func (s Service, l Lifecycle) { log.Printf("%s is now %s", s.String(), l.State()) }) ``` -------------------------------- ### Create Configuration Saver to Writer Source: https://github.com/containerssh/containerssh/blob/main/README.md Instantiate a configuration saver to write application configuration to an `io.Writer`, such as `os.Stdout`. Supports formats like YAML. ```go saver, err := configuration.NewWriterSaver( os.Stdout, logger, configuration.FormatYAML, ) ``` -------------------------------- ### Create Docker Backend Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/docker/README.md Instantiates a new Docker backend handler. Requires a client, connection ID, configuration, logger, and metrics counters. The logger should be from the ContainerSSH logger library. ```go var client net.TCPAddr connectionID := "0123456789ABCDEF" config := docker.Config{ //... } collector := metrics.New() dr, err := docker.New( client, connectionID, config, logger, collector.MustCreateCounter("backend_requests", "", ""), collector.MustCreateCounter("backend_failures", "", ""), ) if err != nil { // Handle error } ``` -------------------------------- ### Create Audit Logging Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/auditlogintegration/README.md Use this to create a new audit logging handler. You will need an audit logger and a backend handler. ```go handler := auditlogintegration.New( backend, auditLogger, ) ``` -------------------------------- ### Implement Configuration Request Handler Interface Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Define a struct and implement the `ConfigRequestHandler` interface to handle configuration requests. The `OnConfig` method should return an error only if it genuinely cannot serve the request, not for user rejection. ```go type ConfigRequestHandler interface { OnConfig(request configuration.ConfigRequest) (configuration.AppConfig, error) } ``` ```go type myConfigReqHandler struct { } func (m *myConfigReqHandler) OnConfig( request configuration.ConfigRequest, ) (config configuration.AppConfig, err error) { // We recommend using an IDE to discover the possible options here. if request.Username == "foo" { config.Docker.Config.ContainerConfig.Image = "yourcompany/yourimage" } return config, err } ``` -------------------------------- ### Instantiate kuberun Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/kubernetes/README.md Use this to create a new network connection handler for the kuberun backend. Ensure you provide all required parameters including client address, connection ID, configuration, logger, and metrics counters. ```go handler, err := kuberun.New( client, connectionID, config, logger, backendRequestsCounter, backendFailuresCounter, ) ``` -------------------------------- ### Compatibility Logging Methods Source: https://github.com/containerssh/containerssh/blob/main/log/README.md These compatibility methods log messages at the info level. They are useful for simple logging tasks. ```go logger.Log(v ...interface{}) logger.Logf(format string, v ...interface{}) ``` -------------------------------- ### Implement Configuration Request Handler Interface Source: https://github.com/containerssh/containerssh/blob/main/README.md Define a struct and implement the `ConfigRequestHandler` interface to handle configuration requests. The `OnConfig` method should return an error only if it cannot serve the request, not for rejection. ```go package main import ( "go.containerssh.io/containerssh/config" ) type ConfigRequestHandler interface { OnConfig(request config.Request) (config.AppConfig, error) } ``` ```go type myConfigReqHandler struct { } func (m *myConfigReqHandler) OnConfig( request configuration.ConfigRequest, ) (config configuration.AppConfig, err error) { // We recommend using an IDE to discover the possible options here. if request.Username == "foo" { config.Docker.Config.ContainerConfig.Image = "yourcompany/yourimage" } return config, err } ``` -------------------------------- ### Create ContainerSSH Test Authentication Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/sshserver/README.md Set up an authentication handler that authenticates using provided test users. This handler can be plugged into the test server. ```go handler := NewTestAuthenticationHandler( handler, user1, user2, user3, ) ``` -------------------------------- ### Load Connection-Specific Configuration from Loader Source: https://github.com/containerssh/containerssh/blob/main/README.md Load configuration specific to a particular connection using the loader. This method requires the client's name, network address, connection ID, and the `AppConfig` struct to populate. ```go err := loader.LoadConnection( ctx, "my-name-is-trinity", net.TCPAddr{ IP: net.ParseIP("127.0.0.1"), Port: 2222, }, connectionID, appConfig, ) ``` -------------------------------- ### Perform Password Authentication with Client Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md Use the authentication client to perform password-based authentication. Provide the username, password, connection ID, and remote IP address. ```go success, err := client.Password( "foo", []byte("bar"), "0123456789ABCDEF", ip ) (bool, error) ``` -------------------------------- ### Run Kerberos Service Locally with Docker Source: https://github.com/containerssh/containerssh/blob/main/internal/test/README.md Provides instructions to build and run a Kerberos service locally using Docker. This command maps the necessary ports and sets environment variables for the Kerberos server. ```bash docker build -t krb . docker run \ --rm \ -p 127.0.0.1:88:88 \ -p 127.0.0.1:88:88/udp \ -e KERBEROS_USERNAME=admin \ -e KERBEROS_PASSWORD=testing \ -ti \ krb ``` -------------------------------- ### Save Configuration using Saver Source: https://github.com/containerssh/containerssh/blob/main/README.md Write the current application configuration to the configured `io.Writer` using the saver. The `appConfig` should be populated before calling this method. ```go err := saver.Save(appConfig) ``` -------------------------------- ### Create SSH Proxy Backend Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/sshproxy/README.md Use the `New()` method to create a network connection handler for the SSH proxy backend. Ensure you provide a client address, connection ID, configuration, logger, and metrics collectors. ```go var client net.TCPAddr connectionID := "0123456789ABCDEF" config := sshproxy.Config{ //... } collector := metrics.New() proxy, err := sshproxy.New( client, connectionID, config, logger, collector.MustCreateCounter("backend_requests", "", ""), collector.MustCreateCounter("backend_failures", "", ""), ) if err != nil { // Handle error } ``` -------------------------------- ### Implement Authentication Handler Interface Source: https://github.com/containerssh/containerssh/blob/main/internal/auth/README.md Implement the Handler interface to define custom authentication logic for password and public key authentication. Handle potential errors like database failures. ```go type myHandler struct { } func (h *myHandler) OnPassword( Username string, Password []byte, RemoteAddress string, ConnectionID string, ) (bool, error) { if Username == "foo" && string(Password) == "bar" { return true, nil } if Username == "crash" { // Simulate a database failure return false, fmt.Errorf("database error") } return false, nil } func (h *myHandler) OnPubKey( Username string, // PublicKey is the public key in the authorized key format. PublicKey string, RemoteAddress string, ConnectionID string, ) (bool, error) { // Handle public key auth here } ``` -------------------------------- ### Create a Test User for SSH Source: https://github.com/containerssh/containerssh/blob/main/internal/sshserver/README.md Creates a new test user with a specified username. The user can then be configured with a password or SSH key for testing purposes. ```go user := sshserver.NewTestUser( "test", ) ``` -------------------------------- ### Launch the service pool Source: https://github.com/containerssh/containerssh/blob/main/service/README.md Create a lifecycle for the pool and run it in a separate goroutine. Handle any errors returned by the run function. The `Shutdown` method can be called to gracefully stop the pool. ```go lifecycle := service.NewLifecycle(pool) go func() { err := lifecycle.Run() // Handle errors here }() lifecycle.Shutdown(context.Background()) ``` -------------------------------- ### Create Security Handler with New() Source: https://github.com/containerssh/containerssh/blob/main/internal/security/README.md Use the New() function to create a network connection handler. The backend must implement the sshserver.NetworkConnectionHandler interface. Refer to config.go for configuration details. ```go security, err := security.New( config, backend ) ``` -------------------------------- ### Handle OS signals for graceful shutdown Source: https://github.com/containerssh/containerssh/blob/main/service/README.md Set up a channel to listen for SIGINT and SIGTERM signals. When a signal is received, initiate a graceful shutdown of the service pool with a timeout. After shutdown, wait for the pool to terminate and ignore further signals. ```go signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) go func() { if _, ok := <-signals; ok { // ok means the channel wasn't closed lifecycle.Shutdown( context.WithTimeout( context.Background(), 20 * time.Second, ) ) } }() // Wait for the pool to terminate. lifecycle.Wait() // We are already shutting down, ignore further signals signal.Ignore(syscall.SIGINT, syscall.SIGTERM) // close signals channel so the signal handler gets terminated close(signals) ``` -------------------------------- ### Instantiate Health Check Service Source: https://github.com/containerssh/containerssh/blob/main/internal/health/README.md Instantiate the health check service using the provided configuration and logger. Ensure the configuration includes server details like the listen address. ```go svc, err := health.New( health.Config{ Enable: true, ServerConfiguration: http.ServerConfiguration{ Listen: "0.0.0.0:23074", }, }, logger) if err != nil { // ... } ``` -------------------------------- ### Instantiate Handler Source: https://github.com/containerssh/containerssh/blob/main/internal/kubernetes/README.md Instantiate the kuberun handler using the kuberun.New() method. This handler is designed to be used exclusively with the sshserver library. ```APIDOC ## Instantiate Handler ### Description Instantiate the kuberun handler using the `kuberun.New()` method. This handler is designed to be used exclusively with the [sshserver library](https://github.com/containerssh/containerssh/tree/main/internal/sshserver). ### Method `kuberun.New()` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - `client` (*net.TCPAddr) - The TCP address of the client that connected. - `connectionID` (string) - An opaque ID for the connection. - `config` (*kuberun.Config) - Configuration struct for the kuberun library. - `logger` (log.Logger) - The logger instance from the log library. - `backendRequestsCounter` (metrics.Counter) - Counter for backend requests. - `backendFailuresCounter` (metrics.Counter) - Counter for backend failures. ### Response #### Success Response (handler, err) - `handler` (*kuberun.Handler) - The instantiated handler. - `err` (error) - An error if the handler could not be created. ### Request Example ```go handler, err := kuberun.New( client, connectionID, config, logger, backendRequestsCounter, backendFailuresCounter, ) ``` ``` -------------------------------- ### Save Configuration to Writer (YAML) Source: https://github.com/containerssh/containerssh/blob/main/config/webhook/README.md Write application configuration to an io.Writer in YAML format using a configuration saver. Useful for outputting configuration to stdout or files. ```go saver, err := configuration.NewWriterSaver( os.Stdout, logger, configuration.FormatYAML, ) err := saver.Save(appConfig) ``` -------------------------------- ### Create Simplified HTTP Handler Source: https://github.com/containerssh/containerssh/blob/main/http/README.md Create a simplified HTTP server handler that automatically decodes JSON requests and encodes JSON responses. Requires a controller that implements the RequestHandler interface. ```go handler := http.NewServerHandler(yourController, logger) ``` -------------------------------- ### Compatibility Logging Methods Source: https://github.com/containerssh/containerssh/blob/main/log/README.md These methods log messages at the info level and are provided for compatibility. ```APIDOC ## Compatibility Logging Methods ### Description Logs messages at the info level. ### Methods - `Log(v ...interface{}) - `Logf(format string, v ...interface{}) ``` -------------------------------- ### Performing a GeoIP Lookup Source: https://github.com/containerssh/containerssh/blob/main/internal/geoip/README.md Shows how to use the initialized GeoIP provider to perform a lookup for a given IP address and retrieve the country code. ```APIDOC ## Perform GeoIP Lookup ### Description Performs a lookup for the given IP address to determine its associated country code. ### Method Signature `provider.Lookup(remoteAddr string) (countryCode string)` ### Parameters #### Path Parameters - **remoteAddr** (string) - Required - The IP address to look up. ### Response #### Success Response (string) - Returns the two-letter country code (e.g., "US", "DE"). If the lookup fails, it returns "XX". ``` -------------------------------- ### Define TextMarshallable Interface Source: https://github.com/containerssh/containerssh/blob/main/http/README.md Implement this interface to enable marshalling objects to text format for content negotiation. ```go type TextMarshallable interface { MarshalText() string } ``` -------------------------------- ### Parse Command Line String Source: https://github.com/containerssh/containerssh/blob/main/internal/unixutils/README.md Parses a command line string into an execv-compatible slice of strings. Useful for preparing commands for execution. ```go args, err := unixutils.ParseCMD("/bin/sh -c 'echo \"Hello world!\"'") //args will be: ["/bin/sh", "-c", "echo \"Hello world!\""] ``` -------------------------------- ### Create and Increment a Counter Metric Source: https://github.com/containerssh/containerssh/blob/main/internal/metrics/README.md Instantiate a new metrics collector and create a counter metric. Use Increment() for single increments and IncrementBy() for multiple increments. ```go m := metrics.New(geoip) testCounter, err := m.CreateCounter( "test", // Name of the metric "MB", // Unit of the metric "This is a test", // Help text of the metric ) testCounter.Increment() testCounter.IncrementBy(5) ```