Documentation
¶
Index ¶
- Variables
- func DirectTCPIPHandler(ctx context.Context, mux *SSHSMux, srv *SSHMesh, newChan ssh.NewChannel)
- func KeysEqual(ak, bk ssh.PublicKey) bool
- type Command
- type ContextDialer
- type Exec
- type KV
- type Pty
- type RemoteExec
- type SSHCMux
- func (sshc *SSHCMux) ClientSession()
- func (sc *SSHCMux) Dial(ctx context.Context, addr string) error
- func (sc *SSHCMux) DialConn(ctx context.Context, tcon net.Conn, addr string) error
- func (ssht *SSHCMux) Exec(cmd string, env map[string]string) (*RemoteExec, error)
- func (sc *SSHCMux) Init(ctx context.Context)
- func (c *SSHCMux) ListenTCP(domain string, port uint32) (uint32, error)
- func (c *SSHCMux) OpenStream(n string, data []byte) (*Stream, error)
- func (sc *SSHCMux) Proxy(ch io.ReadWriteCloser, dstp string, s string)
- func (sshc *SSHCMux) StayConnected()
- type SSHMesh
- func (sshMesh *SSHMesh) AddAuthorizedFile(auth []byte)
- func (sshMesh *SSHMesh) CertAuthority() string
- func (sshMesh *SSHMesh) Client(ctx context.Context, dst string) (*SSHCMux, error)
- func (sshMesh *SSHMesh) DialHTTP(ctx context.Context, host string, orig string) (io.ReadWriteCloser, error)
- func (sshMesh *SSHMesh) FromEnv()
- func (sshMesh *SSHMesh) HandleAccepted(nc net.Conn) error
- func (sshMesh *SSHMesh) HandleServerConn(acceptedSSHMux *SSHSMux)
- func (sshMesh *SSHMesh) ListenAndStart() (net.Listener, error)
- func (sshMesh *SSHMesh) NodeCertAuthority() string
- func (sshMesh *SSHMesh) Provision(ctx context.Context) error
- func (sshMesh *SSHMesh) PubString()
- func (sshMesh *SSHMesh) ServeHTTP(writer http.ResponseWriter, request *http.Request)
- func (sshMesh *SSHMesh) SetCertClient(key string) error
- func (sshMesh *SSHMesh) SetCertHost(key string) error
- func (sshMesh *SSHMesh) SetKeyCrypto(cpk crypto.PrivateKey)
- func (sshMesh *SSHMesh) SetKeySSH(sshk string) error
- func (sshMesh *SSHMesh) Sign(pub ssh.PublicKey, certType uint32, names []string) ([]byte, *ssh.Certificate, error)
- func (sshMesh *SSHMesh) SignCert(cert *ssh.Certificate) ([]byte, error)
- func (sshMesh *SSHMesh) Start(ctx context.Context) error
- type SSHSMux
- type SSHSession
- type Stream
- type TokenChecker
- type TokenSource
- type Window
Constants ¶
This section is empty.
Variables ¶
StartWithSize starts the command with a pty - normally creack/pty, but avoiding the dep in this package.
Functions ¶
func DirectTCPIPHandler ¶
DirectTCPIPHandler is for 'direct-tcpip' channel type, to support client-originated reverseForwards. It runs on the server side.
See RFC 4254 7.2 RFC 4254 7.2" aria-label="Go to See RFC 4254 7.2">¶
- When client starts with a -L CPORT:host:port, and connects to CPORT - Also when client uses socks for dynamic reverseForwards (-D) - jump (-J)
If the destination port is 22/15022 - existing connections can be used to avoid an extra TCP connection.
Laddr is typically 127.0.0.1 (unless ssh has an open socks, and other machines use it)
Types ¶
type Command ¶
type Command struct {
Run func(env map[string]string, args []string, in io.Reader, out io.WriteCloser, err io.WriteCloser)
}
type ContextDialer ¶
type Exec ¶
type Exec struct { // Host of VM where this command will be executed. It will create a // SSH or https connection or reuse existing client mux for remote // connections, or use a command to enter the VM. Host string Args []string Env map[string]string WD string In io.Reader Out io.WriteCloser // will be a ssh.Channel for ssh }
Exec can be used with streams - SSH, H2 or other tunnels.
type RemoteExec ¶
RemoteExec is a "session" channel.
type SSHCMux ¶
type SSHCMux struct { // LastSeen time.Time ConnectTime time.Time `json:"-"` User string `json:"user,omitempty"` // network stream // May be an original con with net.Conn with remote/local addr NetConn io.ReadWriteCloser `json:"-"` // Dependency to the transport (doesn't have to be listenining) *SSHMesh `json:"-"` // If set, a persistent connection will be maintained and // - mux reverseForwards registered for 22, 80, 443 // - accept streams and trust auth Waypoint bool Address string `json:"address,omitempty"` // TODO: CIDR/Networks ReverseForwards map[string]string LastConnected time.Time `json:"-"` // The SSH Conn, client and internal objects SSHClient *ssh.Client `json:"-"` SSHConn ssh.Conn `json:"-"` // Last received remote key (should be a Certificate) RemoteKey ssh.PublicKey `json:"-"` // contains filtered or unexported fields }
SSHCMux is a multiplexed client connection to a single destination. That corresponds to a H2 connection - it is possible to have multiple SSHCMux connections to the same destination at the same time.
func (*SSHCMux) ClientSession ¶
func (sshc *SSHCMux) ClientSession()
func (*SSHCMux) Dial ¶
Dial opens one TCP or H2 connection to addr, and starts SSH handshake. It blocks until the SSH handshake is done.
addr can be a https:// address or a hostname.
func (*SSHCMux) ListenTCP ¶
ListenTCP requests the remote peer open a listening socket on port.
Regular SSH servers don't multiplex on port. RFC4254: "" means that connections are to be accepted on all protocol
families supported by the SSH implementation. o "0.0.0.0" means to listen on all IPv4 addresses. o "::" means to listen on all IPv6 addresses. o "localhost" means to listen on all protocol families supported by the SSH implementation on loopback addresses only ([RFC3330] and [RFC3513]). o "127.0.0.1" and "::1" indicate listening on the loopback interfaces for IPv4 and IPv6, respectively.
Port 0 is usually supported.
func (*SSHCMux) OpenStream ¶
OpenStream creates a new stream. This uses the same channel in both directions.
func (*SSHCMux) Proxy ¶
func (sc *SSHCMux) Proxy(ch io.ReadWriteCloser, dstp string, s string)
Proxy an incoming stream to a destination, for remotely accepted steams (-R) TODO: optimize.
func (*SSHCMux) StayConnected ¶
func (sshc *SSHCMux) StayConnected()
StayConnected will maintain an active connection, typically with a jump host.
'addr' is the IP:port to connect to - not the 'canonical' service.
type SSHMesh ¶
type SSHMesh struct { // Address to listen on as SSH. Will default to 14022 for regular nodes and // 15022 for gateways. Address string `json:"addr,omitempty"` KeepAlive map[string]*SSHCMux `json:"connect,omitempty"` CertClient string `json:"id_ecdsa_cert.pub,omitempty"` CertHost string `json:"cert_host.pub,omitempty"` // Primary key - in PEM format (also used for mTLS) Key string `json:"tls.key,omitempty"` // AuthorizedKeys is the same as authorized_keys file. // The keys are used as 'trusted sources' for authentication. Any user key can be used for shell/debug access. // The CA keys are allowed to connect - but can get a shell only if 'role=admin' is present in the cert. // // If empty, the SSH_AUTHORIZED_KEYS env is used, falling back to authorized_keys in $HOME/.ssh (if FromEnv is called) AuthorizedKeys string `json:"authorized_keys,omitempty"` // User is in email format, as expected by the SSH client certificates. // User string `json:"id,omitempty"` Domain string `json:"namespace,omitempty"` // Can be set to a custom dialer, for example for mesh protocol tunneling. Dialer ContextDialer `json:"-"` // Can be set to a custom dialer, for example for mesh protocol tunneling. H2Dialer ContextDialer `json:"-"` Listener net.Listener `json:"-"` CertChecker *ssh.CertChecker `json:"-"` ConnectErrors atomic.Int64 `json:"-"` // Map of public key to user ID. // Key is the marshalled public key (from authorized_keys), value is the user ID (comment) UsersKeys map[string]string `json:"-"` // Signer is the 'workload identity' signer. It is using the main workload // private key (workload key), but with a host certificate. Signer ssh.Signer `json:"-"` // SignerClient is a client workload identity - using the SA cert when // a CA is used. Otherwise, same as Signer. SignerClient ssh.Signer `json:"-"` SignerHost ssh.Signer `json:"-"` // Forward is a function that will proxy a stream to a destination. // If missing, it will be dialed. // Used on a server for all client forwarding - except locally connected clients. Forward func(context.Context, string, io.ReadWriteCloser) `json:"-"` // WIP: Internally defined commands. InternalCommands map[string]*Command `json:"-"` // Root CA keys - will be authorized to connect and create tunnels, not get shell. AuthorizedCA []ssh.PublicKey `json:"-"` // WIP: Custom channel handlers. ChannelHandlers map[string]func(ctx context.Context, sconn *SSHSMux, newChannel ssh.NewChannel) `json:"-"` // TokenChecker will verify the password field - as a JWT or other forms. TokenChecker TokenChecker `json:"-"` // TokenSource will provide passwords or tokens. // Normally SSH is cert based - but in some cases all we get is a token. For example K8S, Cloudrun, etc. TokenSource TokenSource `json:"-"` sync.Mutex `json:"-"` Logger *slog.Logger // contains filtered or unexported fields }
SSHMesh is a minimal L4S (ambient) mesh implementation based on SSH, and compatible with standard SSH clients and servers.
func (*SSHMesh) AddAuthorizedFile ¶
AddAuthorizedFile will load the ssh "authorized_files" content.
All CAs are added separately, and will also be used for host authorization. The 'comment' field is saved - and will be used as 'user' when public key auth is using that key.
func (*SSHMesh) CertAuthority ¶
func (*SSHMesh) Client ¶
Client returns a SSH client for a destination. It may be disconnected - first call is always disconnected.
func (*SSHMesh) DialHTTP ¶
func (sshMesh *SSHMesh) DialHTTP(ctx context.Context, host string, orig string) (io.ReadWriteCloser, error)
DialHTTP will forward an HTTP connection to a client that opened a -R connection. The host must match the 'canonical' hostname of the client.
func (*SSHMesh) FromEnv ¶
func (sshMesh *SSHMesh) FromEnv()
FromEnv is called to load private key and configs from file or env variables. Not useful for a library - only as a main app.
It will use the same key for clients and servers. Existing $HOME/.ssh is used unless SSHM_CFGDIR is set.
Configs: - id_ecdsa and id_ecdsa_{host,cert}.pub (optional) - authorzied_keys
func (*SSHMesh) HandleServerConn ¶
Handles a connection as SSH server, using a net.Conn - which might be tunneled over other transports. SSH handles multiplexing and packets.
func (*SSHMesh) NodeCertAuthority ¶
func (*SSHMesh) ServeHTTP ¶
func (sshMesh *SSHMesh) ServeHTTP(writer http.ResponseWriter, request *http.Request)
ServeHTTP is the main function implemented by SSH for HTTP purpose. It will take the H2 request and treat it as a TCP connection. HandleAccepted is handling accepted TCP connections.
func (*SSHMesh) SetCertClient ¶
func (*SSHMesh) SetCertHost ¶
func (*SSHMesh) SetKeyCrypto ¶
func (sshMesh *SSHMesh) SetKeyCrypto(cpk crypto.PrivateKey)
Cert.PrivateKey can be used as a source, if one is loaded.
func (*SSHMesh) Sign ¶
func (sshMesh *SSHMesh) Sign(pub ssh.PublicKey, certType uint32, names []string) ([]byte, *ssh.Certificate, error)
Sign will sign a client or server certificate.
Each host can sign - the resulting cert should be under the host trust.
func (*SSHMesh) SignCert ¶
func (sshMesh *SSHMesh) SignCert(cert *ssh.Certificate) ([]byte, error)
SignCert signs an arbitrary certificate. The cert is expected to include Key, Valid*, CertType, ValidPrincipals.
Optional: Serial, KeyId, Permissions ( a map of claims and the critical like "force-command", "source-address" )
The cert signing will initialize Nonce, Signature.
The result is in 'authorized keys' format.
type SSHSMux ¶
type SSHSMux struct { // Includes the private key of this node SSHServer *SSHMesh `json:"-"` // LastSeen time.Time ConnectTime time.Time // network stream // May be an original con with net.Conn with remote/local addr NetConn net.Conn `json:"-"` // ServerConn - also has Permission ServerConn *ssh.ServerConn `json:"-"` RemoteKey ssh.PublicKey `json:"-"` //RemoteHostname string //RemoteAddr net.Addr FQDN string }
SSHSMux is a server ssh connection - a long lived, accepted connection.
type SSHSession ¶
type SSHSession struct { Channel ssh.Channel // Window keeps getting update during execution. PTY *Pty Env []*KV Cmd *exec.Cmd // contains filtered or unexported fields }
SSHSession is a net connection (H2 stream equivalent), but with extra packets for executing commands including SFTP and an extra stderr stream.
This is closer to a WebSocket in binary mode: packets, can multiplex sub-channels and commands - flow control is like H2, both on stream and mux.
The actual execution is in the exec.go -
func (*SSHSession) Close ¶
func (sess *SSHSession) Close() error
func (*SSHSession) Handle ¶
func (sess *SSHSession) Handle(ctx context.Context, newChannel ssh.NewChannel)
WIP: The SSH 'gateway' will not have a real shell / sftp session (except for debug). Instead, the session is used as a general purpose communication.
Notes on sessions: -N - do not start a session at all -T - do not get a pty If ssh is piped, a terminal will not be allocated - but no flushing seems to happen.
Inside a session - ~. close, ~B break, ~C CLI, ~# connections, ~? help
func (*SSHSession) SFTPHandler ¶
func (s *SSHSession) SFTPHandler(ctx context.Context, req *ssh.Request)
type Stream ¶
Stream is a client or server stream - 'Channel' in SSH terms.
Also implements gossh.Channel - add SendRequest and Stderr, as well as CloseWrite