Documentation
¶
Overview ¶
Package sshprovision adopts a machine the operator already has (any VPS, home server, Raspberry Pi) as a node by dialing into it over SSH and installing the node agent there. This is a different feature from internal/provision (which creates a brand-new VM at a cloud provider's API and drives it through cloud-init on first boot): this package never imports that one, and duplicates the small agent systemd-unit/env-file shell snippet CloudInitParams.agentImage/RenderCloudInit render for a fresh VM, adapted to run as direct SSH commands against a machine that already exists instead of a cloud-init document a fresh VM processes on first boot.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrHostKeyRequired = errors.New("sshprovision: a host key fingerprint is required, run the preflight and confirm the server's fingerprint")
ErrHostKeyRequired means a Provision call carried neither a pinned fingerprint nor an explicit opt out of host key verification.
Functions ¶
func NormalizeFingerprint ¶ added in v0.2.2
NormalizeFingerprint trims fp, adds a missing "SHA256:" prefix, and reports whether the result is a well-formed SHA256 fingerprint.
func PinnedHostKeyCallback ¶ added in v0.2.2
func PinnedHostKeyCallback(fp string) ssh.HostKeyCallback
PinnedHostKeyCallback accepts only a host key whose SHA256 fingerprint is fp.
Types ¶
type AuthType ¶
type AuthType string
AuthType selects how Credentials authenticates to the remote host.
type Credentials ¶
type Credentials struct {
Host string
Port int // 0 defaults to 22
Username string
Auth AuthType
// PrivateKey is a PEM-encoded private key, required when Auth is AuthKey.
PrivateKey string
// Passphrase decrypts PrivateKey when it's encrypted. Optional.
Passphrase string
// Password authenticates when Auth is AuthPassword.
Password string
// HostKeyFingerprint pins the server's host key (SHA256:...). Provision
// refuses to send credentials to a server presenting any other key.
HostKeyFingerprint string
// InsecureSkipHostKeyCheck accepts any host key; the caller must warn loudly.
InsecureSkipHostKeyCheck bool
}
Credentials dials and authenticates to one remote host for the duration of a single Provision call. The caller must discard it once Provision returns: nothing in this package persists it anywhere.
type DetectedHost ¶
type DetectedHost struct {
// OS is the lowercased `uname -s` output, e.g. "linux". Provision
// fails before installing anything if this isn't "linux".
OS string
// Arch is "amd64" or "arm64", normalized from `uname -m`. Empty means
// an unsupported architecture, and Provision fails before installing
// anything.
Arch string
// Distro is /etc/os-release's PRETTY_NAME, best effort. "unknown" if
// the file is missing or unreadable.
Distro string
DockerPresent bool
SystemdPresent bool
}
DetectedHost is what Provision learns about the remote machine before it changes anything: shown to the operator so this doesn't feel like a black box.
type Event ¶
type Event struct {
Step Step
Message string
// Err is set on the terminal event for a failed step; Provision
// returns the same error.
Err error
}
Event is one line of progress Provision reports through onEvent. Message is always safe to log and show to an operator: Provision never puts a credential or the join token in a Message.
type HostKey ¶ added in v0.2.2
type HostKey struct {
// Type is the key algorithm, e.g. "ssh-ed25519" or "ssh-rsa".
Type string
// Fingerprint is "SHA256:" plus the unpadded base64 SHA-256 of the key.
Fingerprint string
}
HostKey is one public host key a server presented, as ssh-keygen -l prints it.
type HostKeyMismatchError ¶ added in v0.2.2
HostKeyMismatchError reports that no key the server presented matches the pinned fingerprint.
func (*HostKeyMismatchError) Error ¶ added in v0.2.2
func (e *HostKeyMismatchError) Error() string
type InstallParams ¶
type InstallParams struct {
ControlPlaneAddr string
JoinToken string
CAFingerprint string
NodeName string
// AgentImage overrides defaultAgentImage (repo:tag). Empty uses the
// default, the caller is expected to resolve a real release tag the
// same way provision.CloudInitParams.agentImage does (internal/api
// wires this from internal/version.Version).
AgentImage string
// MeshEnabled gives the agent container the TUN device and NET_ADMIN
// its WireGuard device needs; off keeps the original unprivileged run.
MeshEnabled bool
}
InstallParams is what the remote host needs to enroll as a node agent: the same information provision.CloudInitParams carries for a freshly created VM, minus the fields that only make sense for a cloud-init document (this package's own doc comment explains why the two aren't shared).
type Provisioner ¶
type Provisioner struct {
// DialTimeout bounds the initial TCP+SSH handshake. Zero uses
// defaultDialTimeout.
DialTimeout time.Duration
// AgentName is the brand-derived stem for the unit, container and paths (brand.AgentName()).
AgentName string
// DisplayName is the brand's human name used in the unit description (brand.Name).
DisplayName string
}
Provisioner adopts an existing machine over SSH: connects, detects its OS/arch, ensures Docker and systemd, then installs and starts the node agent as a systemd-managed container.
func New ¶
func New(agentName, displayName string) *Provisioner
New returns a Provisioner that installs the agent under agentName, described as displayName.
func (*Provisioner) Provision ¶
func (p *Provisioner) Provision(ctx context.Context, creds Credentials, params InstallParams, onEvent func(Event)) (DetectedHost, error)
Provision connects to creds, detects the remote host, and installs the node agent there so it enrolls with params.ControlPlaneAddr using params.JoinToken. It reports progress through onEvent (which may be nil) and returns what it detected about the host even on failure, where that's known before the failure occurred.
Provision returns once the agent's systemd unit reports active; it does not wait for the agent to actually dial the control plane and enroll; that is the caller's job to poll for separately (the same "server is up" vs. "node has enrolled" split internal/provision's own node-provision flow already draws between the provider API and the node registry).
func (*Provisioner) ScanHostKeys ¶ added in v0.2.2
ScanHostKeys connects to host:port and returns every host key the server presents, like ssh-keyscan. It never authenticates: each handshake is aborted inside the host key callback, so no username or credential is sent.
type Step ¶
type Step string
Step is one stage of Provision, reported through onEvent as it starts, streams command output, and finishes.
const ( StepConnect Step = "connect" StepDetect Step = "detect" StepPrereqs Step = "prereqs" StepDocker Step = "docker" StepAgent Step = "agent" StepDone Step = "done" )
The stages Provision reports through onEvent, in order. Not every install reaches StepDocker's own install sub-events: DockerPresent already true skips straight past them.