Back to Microsandbox

SSH

docs/sdk/go/ssh.mdx

0.5.1023.5 KB
Original Source

Reach a running sandbox over SSH: open a native in-process SSH client, run exec requests, attach an interactive shell, transfer files over SFTP, or stand up a reusable SSH server endpoint. See SSH for usage flows.

<div className="msb-glance"> <p className="msb-gl"><span className="msb-dot instance"></span>Methods<span className="msb-ct">20</span></p> <a className="msb-row" href="#sb-ssh"><span className="msb-rn">sb.SSH()</span><span className="msb-rg">SSH namespace for this sandbox</span></a> <a className="msb-row" href="#ssh-openclient"><span className="msb-rn">ssh.OpenClient()</span><span className="msb-rg">open a native client</span></a> <a className="msb-row" href="#ssh-prepareserver"><span className="msb-rn">ssh.PrepareServer()</span><span className="msb-rg">prepare a server endpoint</span></a> <a className="msb-row" href="#c-exec"><span className="msb-rn">c.Exec()</span><span className="msb-rg">run a command</span></a> <a className="msb-row" href="#c-attach"><span className="msb-rn">c.Attach()</span><span className="msb-rg">interactive shell</span></a> <a className="msb-row" href="#c-sftp"><span className="msb-rn">c.SFTP()</span><span className="msb-rg">open an SFTP session</span></a> <a className="msb-row" href="#c-close"><span className="msb-rn">c.Close()</span><span className="msb-rg">close the client</span></a> <a className="msb-row" href="#srv-serveconnection"><span className="msb-rn">srv.ServeConnection()</span><span className="msb-rg">serve one connection</span></a> <a className="msb-row" href="#srv-close"><span className="msb-rn">srv.Close()</span><span className="msb-rg">release the endpoint</span></a> <a className="msb-row" href="#o-success"><span className="msb-rn">o.Success()</span><span className="msb-rg">exit status was 0</span></a> <a className="msb-row" href="#sftpclient"><span className="msb-rn">sftp.Read()</span><span className="msb-rg">read a file</span></a> <a className="msb-row" href="#sftpclient"><span className="msb-rn">sftp.Write()</span><span className="msb-rg">write a file</span></a> <a className="msb-row" href="#sftpclient"><span className="msb-rn">sftp.Mkdir()</span><span className="msb-rg">create a directory</span></a> <a className="msb-row" href="#sftpclient"><span className="msb-rn">sftp.Rename()</span><span className="msb-rg">rename a path</span></a> <a className="msb-row" href="#sftpclient"><span className="msb-rn">sftp.RealPath()</span><span className="msb-rg">resolve a canonical path</span></a> <a className="msb-row" href="#sftpclient"><span className="msb-rn">sftp.Symlink()</span><span className="msb-rg">create a symlink</span></a> <a className="msb-row" href="#sftpclient"><span className="msb-rn">sftp.Close()</span><span className="msb-rg">+ 3 more in SFTPClient</span></a> <p className="msb-gl"><span className="msb-dot builder"></span>Options<span className="msb-ct">10</span></p> <div className="msb-chiprow"> <a className="msb-chip" href="#sshclientoption">WithSSHUser()</a> <a className="msb-chip" href="#sshclientoption">WithSSHTerm()</a> <a className="msb-chip" href="#sshclientoption">WithSSHClientSFTP()</a> <a className="msb-chip" href="#sshexecoption">WithSSHTTY()</a> <a className="msb-chip" href="#sshattachoption">WithSSHAttachTerm()</a> <a className="msb-chip" href="#sshattachoption">WithSSHDetachKeys()</a> <a className="msb-chip" href="#sshserveroption">WithSSHHostKeyPath()</a> <a className="msb-chip" href="#sshserveroption">WithSSHAuthorizedKeysPath()</a> <a className="msb-chip" href="#sshserveroption">WithSSHServerUser()</a> <a className="msb-chip" href="#sshserveroption">WithSSHServerSFTP()</a> </div> <p className="msb-gl"><span className="msb-dot type"></span>Types</p> <div className="msb-chiprow"> <a className="msb-typepill" href="#sandboxsshops">SandboxSSHOps</a> <a className="msb-typepill" href="#sshclient">SSHClient</a> <a className="msb-typepill" href="#sftpclient">SFTPClient</a> <a className="msb-typepill" href="#sshserver">SSHServer</a> <a className="msb-typepill" href="#sshoutput">SSHOutput</a> <a className="msb-typepill" href="#sshclientoption">SSHClientOption</a> <a className="msb-typepill" href="#sshexecoption">SSHExecOption</a> <a className="msb-typepill" href="#sshattachoption">SSHAttachOption</a> <a className="msb-typepill" href="#sshserveroption">SSHServerOption</a> </div> </div> <p className="msb-label" id="typical-flow">Typical flow</p>
go
import (
    "context"

    m "github.com/superradcompany/microsandbox/sdk/go"
)

ctx := context.Background()

client, err := sb.SSH().OpenClient(ctx)   // 1. open a native client
if err != nil {
    return err
}
defer client.Close(ctx)

out, err := client.Exec(ctx, "uname -a")  // 2. run a command
if err != nil {
    return err
}
fmt.Printf("%s (exit %d)\n", out.Stdout, out.Status)

Methods


<span className="msb-recv">sb.</span><span className="msb-hn">SSH()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (s *Sandbox) SSH() *SandboxSSHOps

Return the SSH operations namespace for this sandbox. The namespace groups the client and server helpers; it holds no resources of its own.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#sandboxsshops">*SandboxSSHOps</a></div> <div className="msb-param-desc">SSH client and server helpers for this sandbox.</div> </div> </div> <Accordion title="Example">
go
ssh := sb.SSH()
client, err := ssh.OpenClient(ctx)
</Accordion>

<span className="msb-recv">ssh.</span><span className="msb-hn">OpenClient()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (ssh *SandboxSSHOps) OpenClient(ctx context.Context, opts ...SSHClientOption) (*SSHClient, error)

Open a native in-process SSH client to this sandbox. Generates an ephemeral Ed25519 client and host key pair, stands up an internal server bound to a duplex stream, and authenticates over public key. With no options it uses login user root, terminal from $TERM (falling back to xterm), and SFTP enabled.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels the connection attempt.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshclientoption">...SSHClientOption</a></div> <div className="msb-param-desc">Login user, terminal name, and SFTP toggle.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#sshclient">*SSHClient</a></div> <div className="msb-param-desc">Native SSH client session.</div> </div> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
client, err := sb.SSH().OpenClient(ctx,
    m.WithSSHUser("app"),
    m.WithSSHTerm("xterm-256color"),
)
if err != nil {
    return err
}
defer client.Close(ctx)
</Accordion>

<span className="msb-recv">ssh.</span><span className="msb-hn">PrepareServer()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (ssh *SandboxSSHOps) PrepareServer(ctx context.Context, opts ...SSHServerOption) (*SSHServer, error)

Prepare a reusable SSH server endpoint for this sandbox. Loads or creates the host key and resolves authorized keys from the default authorized-keys file unless overridden. The returned SSHServer can serve connections one at a time over the process's standard streams.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels server preparation.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshserveroption">...SSHServerOption</a></div> <div className="msb-param-desc">Host key, authorized keys, guest user, and SFTP toggle.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#sshserver">*SSHServer</a></div> <div className="msb-param-desc">Prepared server endpoint.</div> </div> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
srv, err := sb.SSH().PrepareServer(ctx,
    m.WithSSHAuthorizedKeysPath("/etc/msb/authorized_keys"),
)
if err != nil {
    return err
}
defer srv.Close(ctx)
</Accordion>

<span className="msb-recv">c.</span><span className="msb-hn">Exec()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (c *SSHClient) Exec(ctx context.Context, command string, opts ...SSHExecOption) (*SSHOutput, error)

Run an SSH exec request and collect stdout, stderr, and the exit status. The command is run through the sandbox's configured shell. No PTY is requested unless WithSSHTTY is passed.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels the exec request.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>command</code><span className="msb-type">string</span></div> <div className="msb-param-desc">Command string sent through SSH.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshexecoption">...SSHExecOption</a></div> <div className="msb-param-desc">PTY toggle for the exec channel.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#sshoutput">*SSHOutput</a></div> <div className="msb-param-desc">Captured stdout, stderr, and exit status.</div> </div> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
out, err := client.Exec(ctx, "python -V")
if err != nil {
    return err
}
if !out.Success() {
    return fmt.Errorf("exit %d: %s", out.Status, out.Stderr)
}
fmt.Printf("%s", out.Stdout)
</Accordion>

<span className="msb-recv">c.</span><span className="msb-hn">Attach()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (c *SSHClient) Attach(ctx context.Context, opts ...SSHAttachOption) (int, error)

Bridge the local terminal to an interactive SSH shell. Requests a PTY sized to the current terminal, puts the terminal into raw mode, forwards keystrokes, relays window-resize events, and returns when the shell exits or the detach key sequence is typed.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels the attach session.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#sshattachoption">...SSHAttachOption</a></div> <div className="msb-param-desc">Terminal name and detach key sequence.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">int</span></div> <div className="msb-param-desc">Shell exit code (128 if terminated by signal).</div> </div> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
code, err := client.Attach(ctx,
    m.WithSSHAttachTerm("xterm-256color"),
    m.WithSSHDetachKeys("ctrl-p,ctrl-q"),
)
if err != nil {
    return err
}
fmt.Printf("shell exited with %d\n", code)
</Accordion>

<span className="msb-recv">c.</span><span className="msb-hn">SFTP()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (c *SSHClient) SFTP(ctx context.Context) (*SFTPClient, error)

Open an SFTP session over this SSH connection. Returns a high-level SFTP client for reading, writing, and managing files inside the guest. Requires SFTP enabled on the client (the default).

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels opening the SFTP session.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#sftpclient">*SFTPClient</a></div> <div className="msb-param-desc">SFTP client session.</div> </div> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
sftp, err := client.SFTP(ctx)
if err != nil {
    return err
}
defer sftp.Close(ctx)

if err := sftp.Write(ctx, "/tmp/hello.txt", []byte("hi")); err != nil {
    return err
}
</Accordion>

<span className="msb-recv">c.</span><span className="msb-hn">Close()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (c *SSHClient) Close(ctx context.Context) error

Close this SSH client session. The handle is consumed; do not use it after closing.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels the close.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
defer client.Close(ctx)
</Accordion>

<span className="msb-recv">srv.</span><span className="msb-hn">ServeConnection()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (srv *SSHServer) ServeConnection(ctx context.Context) error

Serve one SSH transport over this process's stdin and stdout. Returns when the connection ends. Call again on the same SSHServer to serve another connection.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels serving the connection.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
srv, err := sb.SSH().PrepareServer(ctx)
if err != nil {
    return err
}
defer srv.Close(ctx)

if err := srv.ServeConnection(ctx); err != nil {
    return err
}
</Accordion>

<span className="msb-recv">srv.</span><span className="msb-hn">Close()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (srv *SSHServer) Close(ctx context.Context) error

Release this prepared server endpoint. The handle is consumed; do not use it after closing.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>ctx</code><span className="msb-type">context.Context</span></div> <div className="msb-param-desc">Cancels the close.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">error</span></div> <div className="msb-param-desc">Typed microsandbox error.</div> </div> </div> <Accordion title="Example">
go
defer srv.Close(ctx)
</Accordion>

<span className="msb-recv">o.</span><span className="msb-hn">Success()</span>

<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>
go
func (o SSHOutput) Success() bool

Report whether the command exited with status 0.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">bool</span></div> <div className="msb-param-desc"><code>true</code> when <code>Status</code> is <code>0</code>.</div> </div> </div> <Accordion title="Example">
go
out, err := client.Exec(ctx, "test -f /etc/passwd")
if err != nil {
    return err
}
fmt.Println("present:", out.Success())
</Accordion>

Types

SandboxSSHOps

<div className="msb-tags"><span className="msb-tag is-type">struct</span></div> <p className="msb-backref">Returned by <a href="#sb-ssh">SSH()</a></p>

SSH operations namespace for a sandbox. Obtained via sb.SSH(). Holds no resources; it groups the client and server entry points.

MethodReturnsDescription
OpenClient(ctx, opts...)(*SSHClient, error)Open a native in-process SSH client
PrepareServer(ctx, opts...)(*SSHServer, error)Prepare a reusable SSH server endpoint

SSHClient

<div className="msb-tags"><span className="msb-tag is-type">struct</span></div> <p className="msb-backref">Returned by <a href="#ssh-openclient">OpenClient()</a></p>

A native in-process SSH client session. Obtained via OpenClient().

MethodReturnsDescription
Exec(ctx, command, opts...)(*SSHOutput, error)Run a command and collect output
Attach(ctx, opts...)(int, error)Bridge the local terminal to an interactive shell
SFTP(ctx)(*SFTPClient, error)Open an SFTP session over this connection
Close(ctx)errorClose the session (consumes the handle)

SFTPClient

<div className="msb-tags"><span className="msb-tag is-type">struct</span></div> <p className="msb-backref">Returned by <a href="#c-sftp">SFTP()</a></p>

A high-level SFTP client session over an SSH connection. Obtained via SFTP().

MethodReturnsDescription
Read(ctx, path)([]byte, error)Read a file into memory
Write(ctx, path, data)errorWrite a file, creating or truncating it
Mkdir(ctx, path)errorCreate a directory
RemoveFile(ctx, path)errorRemove a file
RemoveDir(ctx, path)errorRemove an empty directory
Rename(ctx, oldPath, newPath)errorRename a file or directory
RealPath(ctx, path)(string, error)Resolve a path to its canonical absolute form
ReadLink(ctx, path)(string, error)Read a symlink target
Symlink(ctx, target, linkPath)errorCreate a symlink
Close(ctx)errorClose the session (consumes the handle)

SSHServer

<div className="msb-tags"><span className="msb-tag is-type">struct</span></div> <p className="msb-backref">Returned by <a href="#ssh-prepareserver">PrepareServer()</a></p>

A prepared SSH server endpoint for a sandbox. Obtained via PrepareServer().

MethodReturnsDescription
ServeConnection(ctx)errorServe one SSH transport over stdin/stdout
Close(ctx)errorRelease the endpoint (consumes the handle)

SSHOutput

<div className="msb-tags"><span className="msb-tag is-type">struct</span></div> <p className="msb-backref">Returned by <a href="#c-exec">Exec()</a></p>

The output from an SSH exec request.

Field / MethodTypeDescription
StatusintExit status code
Stdout[]byteCaptured stdout bytes
Stderr[]byteCaptured stderr bytes
Success()booltrue when Status is 0

SSHClientOption

<div className="msb-tags"><span className="msb-tag is-type">option</span></div> <p className="msb-backref">Used by <a href="#ssh-openclient">OpenClient()</a></p>

Functional option for OpenClient(). Defaults: user root, terminal from $TERM (falling back to xterm), SFTP enabled.

OptionDescription
WithSSHUser(user)SSH login user. Default root
WithSSHTerm(term)Terminal name for interactive sessions
WithSSHClientSFTP(enabled)Enable or disable SFTP on the internal server. Default true

SSHExecOption

<div className="msb-tags"><span className="msb-tag is-type">option</span></div> <p className="msb-backref">Used by <a href="#c-exec">Exec()</a></p>

Functional option for Exec().

OptionDescription
WithSSHTTY(enabled)Request a PTY for the exec channel

SSHAttachOption

<div className="msb-tags"><span className="msb-tag is-type">option</span></div> <p className="msb-backref">Used by <a href="#c-attach">Attach()</a></p>

Functional option for Attach(). The default terminal comes from $TERM (falling back to xterm); detach keys default to the standard sequence.

OptionDescription
WithSSHAttachTerm(term)Terminal name for the interactive shell
WithSSHDetachKeys(keys)Detach key sequence

SSHServerOption

<div className="msb-tags"><span className="msb-tag is-type">option</span></div> <p className="msb-backref">Used by <a href="#ssh-prepareserver">PrepareServer()</a></p>

Functional option for PrepareServer(). SFTP is enabled by default; when no authorized-keys path is provided, the default authorized-keys file is loaded.

OptionDescription
WithSSHHostKeyPath(path)Override the host private key path
WithSSHAuthorizedKeysPath(path)Override the authorized-keys path
WithSSHServerUser(user)Override the guest user used for SSH exec requests
WithSSHServerSFTP(enabled)Enable or disable SFTP on the server endpoint. Default true