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 ¶
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 ¶
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.
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" )