Categorygithub.com/containerssh/sshserver/v2
modulepackage
2.0.0-alpha.1
Repository: https://github.com/containerssh/sshserver.git
Documentation: pkg.go.dev

# README

ContainerSSH - Launch Containers on Demand

ContainerSSH SSH Server Library

Go Report Card LGTM Alerts

This library provides an overlay for the built-in go SSH server library that makes it easier to handle.

⚠⚠⚠ Warning: This is a developer documentation. ⚠⚠⚠
The user documentation for ContainerSSH is located at containerssh.io.

Using this library

This library provides a friendlier way to handle SSH requests than with the built-in SSH library. the primary method of using this library is via the Lifecycle objects from the service library:

// Create the server. See the description below for parameters.
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,
    ),
)

The cfg variable will be a Config structure as described in config.go.

The handler variable must be an implementation of the Handler interface described in handler.go.

The logger variable needs to be an instance of the Logger interface from github.com/containerssh/log.

Implementing a handler

The handler interface consists of multiple parts:

  • The Handler is the main handler for the application providing several hooks for events. On new connections the OnNetworkConnection method is called, which must return a NetworkConnectionHandler
  • The NetworkConnectionHandler is a handler for network connections before the SSH handshake is complete. It is called to perform authentication and return an SSHConnectionHandler when the authentication is successful.
  • The SSHConnectionHandler is responsible for handling an individual SSH connection. Most importantly, it is responsible for providing a SessionChannelHandler when a new session channel is requested by the client.
  • The SessionChannelHandler is responsible for an individual session channel (single program execution). It provides several hooks for setting up and running the program. Once the program execution is complete the channel is closed. You must, however, keep handling requests (e.g. window size change) during program execution.

A sample implementation can be found in the test code at the bottom of the file.

About the connectionID

The connectionID parameter in the OnNetworkConnection() is a hexadecimal string uniquely identifying a connection. This ID can be used to track connection-related information across multiple subsystems (e.g. logs, audit logs, authentication and configuration requests, etc.)

Testing a backend

This library contains a testing toolkit for running Linux commands against a backend. The primary resource for these tests will be the conformance tests. To use these you must implement a set of factories that fulfill the following signature: func(logger log.Logger) (sshserver.NetworkConnectionHandler, error).

These factories can then be used as follows:

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)
}

The conformance tests will then attempt to execute a series of Linux interactions against the network connection handler and report features that have failed.

Alternatively, you can also use the components that make up the conformance tests separately.

Creating a test user

The first step of using the test utilities is creating a test user. This can be done using the following calls:

user := sshserver.NewTestUser(
    "test",
)

This use can then be configured with a random password using RandomPassword(), or set credentials using SetPassword() or GenerateKey(). These test users can then be passed to the test server or test client.

Creating a test client

The test SSH client offers functionality over the Golang SSH client that helps with testing. The test client can be created as follows:

sshclient := NewTestClient(
    serverIPAndPort,
    serverHostPrivateKey,
    user *TestUser,
    logger log.Logger,
)

Note that you must pass the servers private key in PEM format which will be used to extract the the public key for validation. This makes the client unsuitable for purposes other than testing.

The test client can then be used to interact with the server. The client is described in test_client.go and functions can be discovered using code completion in the IDE.

Creating a test server

We also provide a simplified test server that you can plug in any backend:

srv := NewTestServer(
    handler,
    logger,
)

You can then start the server in the background and subsequently stop it:

srv.Start()
defer srv.Stop(10 * time.Second)

Creating a simple authenticating handler

We also provide an authentication handler that can be used to authenticate using the test users:

handler := NewTestAuthenticationHandler(
    handler,
    user1,
    user2,
    user3,
)

# Functions

DefaultConfig returns the default configuration.
GenerateConnectionID generates a globally unique connection ID consisting of hexadecimal characters.
New creates a new SSH server ready to be run.
NewChannelRejection constructs a Message that rejects a channel.
NewTestAuthenticationHandler creates a new backend that authenticates a user based on the users variable and passes all further calls to the backend.
NewTestClient creates a new TestClient instance with the specified parameters - server is the host and IP pair of the server.
NewTestHandler creates a conformanceTestHandler that can be used for testing purposes.
NewTestServer is a simplified API to start and stop a test server.
NewTestUser creates a user that can be used with NewTestHandler and NewTestClient.
RunConformanceTests runs a suite of conformance tests against the provided backends supporting a standard Linux shell.goland:noinspection GoUnusedExportedFunction.

# Constants

AuthResponseFailure indicates that the authentication failed for invalid credentials.
AuthResponseSuccess indicates that the authentication was successful.
AuthResponseUnavailable indicates that the authentication could not be performed because a backend system failed to respond.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
Cipher is the SSH cipher.
The SSH server is already running and has been started again.
The user has provided invalid credentials.
The user has provided valid credentials and is now authenticated.
The user has requested an authentication method that is currently unavailable.
The backend has rejected the connecting user after successful authentication.
ContainerSSH failed to decode something from the user.
ContainerSSH failed to obtain and send the exit code of the program to the user.
The connecting party failed to establish a secure SSH connection.
ContainerSSH failed to close the listen socket.
This message indicates that a feature is not implemented in the backend.
ContainerSSH couldn't send the reply to a request to the user.
ContainerSSH failed to set the socket to reuse.
ContainerSSH failed to start the SSH service.
The user requested a channel type that ContainerSSH doesn't support (e.g.
The users client has send a global request ContainerSSH does not support.
Kex are the SSH key exchange algorithms.
Kex are the SSH key exchange algorithms.
Kex are the SSH key exchange algorithms.
Kex are the SSH key exchange algorithms.
Kex are the SSH key exchange algorithms.
Kex are the SSH key exchange algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
KeyAlgo are supported key algorithms.
MAC are the SSH mac algorithms.
MAC are the SSH mac algorithms.
MAC are the SSH mac algorithms.
MAC are the SSH mac algorithms.
The user has send a new channel-specific request.
ContainerSSH couldn't fulfil the channel-specific request.
ContainerSSH has successfully processed the channel-specific request.
A user has connected over SSH.
An SSH connection has been severed.
ContainerSSH is sending the exit code of the program to the user.
ContainerSSH is sending the exit signal from an abnormally exited program to the user.
The user has provided valid credentials and has now established an SSH connection.
A user has established a new SSH channel.
The user has requested a new channel to be opened, but was rejected.
The SSH service is now online and ready for service.

# Variables

ErrAuthenticationFailed is the error that is returned from TestClient.Connect when the authentication failed.

# Structs

AbstractHandler is the abstract implementation of the Handler interface that can be embedded to get a partial implementation.
AbstractNetworkConnectionHandler is an empty implementation for the NetworkConnectionHandler interface.
AbstractSessionChannelHandler is an abstract implementation of SessionChannelHandler providing default implementations.
AbstractSSHConnectionHandler is an empty implementation of the SSHConnectionHandler providing default methods.
Config is the base configuration structure of the SSH server.
KeyboardInteractiveAnswers is a set of answer to a keyboard-interactive challenge.
KeyboardInteractiveQuestion contains a question issued to a user as part of the keyboard-interactive exchange.
TestUser is a container for a username, a password and public keys.

# Interfaces

ChannelRejection is an error type that also contains a Message and a Reason.
Handler is the basic conformanceTestHandler for SSH connections.
NetworkConnectionHandler is an object that is used to represent the underlying network connection and the SSH handshake.
Server is the main SSH server interface, compatible with the Service library.
SessionChannel contains a set of calls to manipulate the session channel.
SessionChannelHandler is a channel of the "session" type used for interactive and non-interactive sessions.
SSHConnectionHandler represents an established SSH connection that is ready to receive requests.
TestClient is an SSH client intended solely for testing purposes.
TestClientConnection is an individual established connection to the server.
TestClientSession is a representation of a session channel inside a test client connection.
TestServer describes.

# Type aliases

AuthResponse is the result of the authentication process.
Cipher is the SSH cipher.
CipherList is a list of supported ciphers.
ConformanceTestBackendFactory is a method to creating a network connection conformanceTestHandler for testing purposes.
ExitStatus contains the status code with which the program exited.
Kex are the SSH key exchange algorithms.
KexList is a list of key exchange algorithms.
KeyAlgo are supported key algorithms.
KeyAlgoList is a list of key algorithms.
KeyboardInteractiveQuestions is a list of questions for keyboard-interactive authentication.
MAC are the SSH mac algorithms.
MACList is a list of MAC algorithms.
ServerVersion is a string that is issued to the client when connecting.