conncheck

package
v0.19.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

Package conncheck validates that a configured server row is actually reachable and usable: that an SSH bastion accepts the stored key, and that a database target can be dialed (and authenticated against) — optionally through that bastion.

It exists so provisioning is not write-and-hope: creating a bastion with a typo'd host, a wrong username or a key the bastion does not accept used to look exactly like success until some user's first real query failed.

The result is deliberately staged: the stage is what tells an admin which field they got wrong. Secrets (private key, passphrase, password) are never echoed into the result or the logs.

Index

Constants

View Source
const DefaultTimeout = 15 * time.Second

DefaultTimeout bounds a whole check (bastion handshake + target dial + target auth). Kept below the shared dialer's own 30s per-dial timeout so a wedged host fails the HTTP request in bounded time rather than hanging on it.

Variables

This section is empty.

Functions

This section is empty.

Types

type Checker

type Checker struct {
	// contains filtered or unexported fields
}

Checker runs connectivity checks. It owns no long-lived state: every check builds a fresh SSH dialer so a pooled, already-open bastion client from the live proxy pool can never make a broken configuration look healthy.

func New

func New(resolver shared.ServerResolver, encryptionKey []byte) *Checker

New builds a Checker over the given resolver (normally *store.Store) and master encryption key.

func (*Checker) Check

func (c *Checker) Check(ctx context.Context, srv *store.Server) Result

Check validates srv: an SSH bastion handshake for `protocol: ssh` rows, or a target dial (through the bastion chain when via_uid is set) plus a protocol-level login for database rows.

It never returns an error: a failed check is a successful call with OK=false, because the staged failure is the answer the caller asked for.

func (*Checker) WithTimeout

func (c *Checker) WithTimeout(d time.Duration) *Checker

WithTimeout returns a copy of the checker bounded by d. Callers serving an HTTP request use it to stay inside their own write timeout.

type Code

type Code string

Code is a stable, machine-readable classification of the failure within a stage. The UI keys its guidance off this, not off the message text.

const (
	// CodeOK marks a successful check.
	CodeOK Code = "ok"
	// CodeDNSFailure means the hostname did not resolve.
	CodeDNSFailure Code = "dns_failure"
	// CodeTimeout means the dial or handshake exceeded the deadline.
	CodeTimeout Code = "timeout"
	// CodeUnreachable means the TCP connection was refused or the network is unreachable.
	CodeUnreachable Code = "unreachable"
	// CodeHostKeyMismatch means the bastion presented a host key differing from
	// the TOFU-pinned one.
	CodeHostKeyMismatch Code = "host_key_mismatch"
	// CodeAuthRejected means the bastion refused the offered credentials.
	CodeAuthRejected Code = "auth_rejected"
	// CodeBadPrivateKey means the stored private key could not be parsed (wrong
	// format, or a wrong/missing passphrase).
	CodeBadPrivateKey Code = "bad_private_key"
	// CodeNoAuthMethod means the bastion row carries neither key nor password.
	CodeNoAuthMethod Code = "no_auth_method"
	// CodeViaCycle means the via_uid chain loops.
	CodeViaCycle Code = "via_cycle"
	// CodeViaNotSSH means via_uid points at a row that is not an SSH bastion.
	CodeViaNotSSH Code = "via_not_ssh"
	// CodeHandshakeFailed is an SSH handshake failure that is not an auth
	// rejection (protocol mismatch, no common algorithm, ...).
	CodeHandshakeFailed Code = "handshake_failed"
	// CodeDBAuthFailed means the target accepted the connection but refused the
	// stored database credentials (or the database name).
	CodeDBAuthFailed Code = "db_auth_failed"
	// CodeDBHandshakeFailed means the target was reachable but the protocol
	// handshake did not complete (wrong port, TLS mismatch, not a database).
	CodeDBHandshakeFailed Code = "db_handshake_failed"
	// CodeMissingConfig means the row is missing a field the protocol needs
	// before anything can be dialed (an Oracle row with no service name).
	CodeMissingConfig Code = "missing_config"
	// CodeUnsupported means no protocol-level probe exists for this protocol;
	// reachability was verified but credentials were not.
	CodeUnsupported Code = "auth_not_verified"
	// CodeInternal is an unclassified failure.
	CodeInternal Code = "internal_error"
)

type Result

type Result struct {
	// OK reports whether the check succeeded end to end.
	OK bool `json:"ok"`
	// Stage is the last stage reached (on failure: the stage that failed).
	Stage Stage `json:"stage"`
	// Code classifies the outcome within the stage; CodeOK on success.
	Code Code `json:"code"`
	// Message is a human-readable explanation, safe to show to an admin.
	Message string `json:"message"`
	// HostKeyPinned is true when this check performed the TOFU pin (first
	// successful connect to a bastion that had no known_host_key yet).
	HostKeyPinned bool `json:"host_key_pinned,omitempty"`
	// KnownHostKey is the bastion's public host key after the check. Public
	// challenge material, safe to return.
	KnownHostKey string `json:"ssh_known_host_key,omitempty"`
	// DurationMs is how long the whole check took.
	DurationMs int64 `json:"duration_ms"`
}

Result is the structured outcome of a connectivity check. It carries no secret material: only the stage reached, a machine-readable code, a human-readable message and (for SSH rows) the public host key.

type Stage

type Stage string

Stage identifies how far the check got before it stopped. On success the stage is the last stage actually reached, so the caller can tell "tunnel and database both verified" from "tunnel verified, database auth not verified".

const (
	// StageConfig covers everything that fails before any packet is sent:
	// missing credentials, an unusable private key, a via_uid cycle.
	StageConfig Stage = "config"
	// StageBastionDial is the TCP dial of the SSH bastion (DNS, routing, firewall).
	StageBastionDial Stage = "bastion_dial"
	// StageBastionAuth is the SSH handshake: host-key verification and auth.
	StageBastionAuth Stage = "bastion_auth"
	// StageTargetDial is the TCP dial of the database target — through the
	// bastion when via_uid is set, direct otherwise.
	StageTargetDial Stage = "target_dial"
	// StageTargetAuth is the protocol-level handshake and login against the
	// database target.
	StageTargetAuth Stage = "target_auth"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL