Documentation
¶
Overview ¶
Package sshpool dials an instance's SSH endpoint with its stored credentials and reports how the presented host key relates to the pinned one. Nothing here writes to the database: pinning is the caller's decision, taken on the report this package returns.
Index ¶
Constants ¶
const HardlinkExtension = "hardlink@openssh.com"
HardlinkExtension is the sftp extension a server advertises when it can make hard links.
Variables ¶
var ErrConnect = errors.New("could not connect to the SSH host")
ErrConnect marks a failure to reach the host or complete the handshake, as opposed to a fault in what qui stored: the caller answers the two differently, and only the first earns an unreadable pin its precedence.
var ErrNoExec = errors.New("the connection does not have the exec tier")
ErrNoExec answers an exec on a connection whose probe did not find the exec tier, for example because the key lost its shell since the stored tier was written.
var ErrNotRemote = errors.New("instance is not in remote filesystem mode")
ErrNotRemote answers a dial for an instance whose row is not in remote filesystem mode. It is not memoised: the row changes without the host doing anything, and the next dial reads it again.
var ErrOutputLimit = errors.New("command output exceeds the limit")
ErrOutputLimit answers a command that printed more than Output keeps.
var ErrPinUnusable = errors.New("host key pin is unusable")
ErrPinUnusable marks the errors Connect raises before it dials, when the stored pin is missing or will not decrypt or parse. The pool dials only rows in remote mode, which carry a pin, so there it means a pin that will not decrypt or parse. That lasts until the pin changes, which is why the pool tells it apart from a host that is merely down.
var ErrPoolClosed = errors.New("ssh pool is closed")
ErrPoolClosed answers a caller that arrives after shutdown began: nothing may dial once Close has run.
Functions ¶
This section is empty.
Types ¶
type Capabilities ¶
type Capabilities struct {
SFTP bool
Statvfs bool
Hardlink bool
Limits bool
Exec bool
// POSIXShell is a login shell that reads a single-quoted word the POSIX
// way. Every remote command is quoted for that shell, so a shell that
// treats a quote differently (fish escapes a closing quote with the
// backslash before it, tcsh rejects a newline inside a quote and reads the
// next line as a new command) could run a path as a command, and gets no
// exec tier.
POSIXShell bool
GNUUserland bool
}
Capabilities is what the server lets us do, probed read-only.
func (*Capabilities) Tier ¶ added in v1.33.0
func (c *Capabilities) Tier() models.SSHTier
Tier is the tier these capabilities give: exec needs sftp and a POSIX shell with the GNU tools, and every other host gets sftp. Every pooled connection opens sftp first, so exec without sftp serves nothing.
type Command ¶ added in v1.33.0
type Command struct {
Name string
Options []string
Paths []string
// Expression comes after the paths, for find.
Expression []string
}
Command is one remote command. String quotes every word and puts "--" between the options and the paths, so a raw path never reaches the shell and a path that starts with "-" is never read as an option.
type Conn ¶ added in v1.33.0
type Conn struct {
// contains filtered or unexported fields
}
Conn runs remote commands on one connection, at most cap(slots) at a time. Pool.Exec gives out a Conn only when the probe of its connection found the exec tier. The probes build their own, before any tier is known.
type Dialer ¶
type Dialer struct {
// contains filtered or unexported fields
}
Dialer opens SSH connections: one-shot ones for Test and Confirm, and the long-lived ones Pool keeps through Connect.
func (*Dialer) Confirm ¶
func (d *Dialer) Confirm(ctx context.Context, inst *models.Instance, hostKey []byte) (*Capabilities, error)
Confirm dials the instance and succeeds only if the host presents hostKey, so the caller can pin the key the user was shown rather than whatever the host offers at pin time. hostKey is in SSH wire format, the form the pin column holds. It then probes the host, on the key it just verified, so the caller can store the tier with the pin.
type MismatchError ¶
MismatchError reports that the host presented a key other than the expected one. Error prints fingerprints only, so the message is safe to log; the fields carry the keys for callers that need them.
func (*MismatchError) Error ¶
func (e *MismatchError) Error() string
type Pool ¶ added in v1.31.0
type Pool struct {
// contains filtered or unexported fields
}
Pool keeps one SSH connection per instance, with one SFTP session and at most execSessions exec sessions on it.
func (*Pool) Close ¶ added in v1.31.0
func (p *Pool) Close()
Close drops every connection and refuses every later caller. Called once, at shutdown; a caller mid-dial holds its entry until that dial ends, which the dial timeout bounds.
func (*Pool) Exec ¶ added in v1.33.0
Exec returns the instance's connection for remote commands, dialing like SFTP. It answers ErrNoExec when the probe of the live connection did not find the exec tier, which happens when the key lost its shell after the caller read the stored tier.
func (*Pool) Invalidate ¶ added in v1.31.0
Invalidate ends the instance's connection and forgets its memo. The credential, pin and instance update routes call it after they write the row, so the next dial reads the new values. A mismatch is re-memoised by the next dial, so a refusal survives a spurious call at the cost of one dial. Safe on a nil pool.
func (*Pool) Remove ¶ added in v1.31.0
Remove is Invalidate for an instance that no longer exists: the entry goes with the connection.
type Report ¶
type Report struct {
Status Status
HostKey ssh.PublicKey
PinnedKey ssh.PublicKey // mismatch only
Capabilities *Capabilities // nil on mismatch and pin_unreadable: no session is opened
}
Report is the outcome of Test. A mismatch is a result, not a failure: the user has to see both keys to decide whether the host was re-keyed or replaced.
type Status ¶
type Status string
Status is how the host key the server presented relates to the stored pin.
const ( StatusUnpinned Status = "unpinned" StatusPinned Status = "pinned" StatusMismatch Status = "mismatch" // StatusPinUnreadable: the stored pin does not decrypt. The presented key // is reported so the user can replace the pin through the same heavy // confirmation a mismatch gets; nothing is trusted and nothing is probed. StatusPinUnreadable Status = "pin_unreadable" )