sshprivilege

package
v0.8.4 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package sshprivilege implements liveness.PrivilegeProbeFunc: dial SSH with the host's resolved credential, run `sudo -n true`, and report whether passwordless privilege escalation is configured.

Per system-ssh-connectivity v1.2.0 the probe ALSO consults systemconfig.SecurityConfig.AllowCredentialSudoPassword; when the initial `sudo -n true` returns non-zero AND the credential carries a non-empty Password AND the policy is on, the probe retries via `sudo -S -k -p ” true` with the password fed through stdin. The retry shape is identical across the THREE inline-retry call sites — this probe, the collector's ssh.RunSudo, and discovery.probeFirewall — and drift between them is forbidden by the spec's C-09. (The compliance scan also supports password sudo, but via a different shape — a per-connection sudo-mode probe in internal/kensa, see system-connection-profile — so it is intentionally not part of this trio; it consults the SAME kill-switch + auth-method gate.)

This package is kept OUT of internal/liveness because the liveness package's AC-14 invariant forbids credential + crypto/ssh imports. The PrivilegeProbeFunc is wired in cmd/openwatch/main.go where both the credential resolver and the liveness service are already in scope.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Probe

func Probe(resolver Resolver, opts ...ProbeOption) liveness.PrivilegeProbeFunc

Probe builds a liveness.PrivilegeProbeFunc backed by the given resolver. The returned function:

  1. Looks up the host's credential. On ErrNoCredential it returns attempted=false (the multi-layer state machine leaves the privilege axis untouched).
  2. Dials TCP-22 with cfg.Timeout = timeout.
  3. Runs `sudo -n true`. Exit 0 → ok=true.
  4. Non-zero exit AND AllowCredentialSudoPassword AND cred.Password non-empty AND cred.AuthMethod ∈ {password, both} → retries as `sudo -S -k -p ” true` with the password fed via stdin. Exit 0 from the retry → ok=true. Any other outcome → ok=false.

Spec system-ssh-connectivity v1.2.0 C-09, AC-18, AC-19, AC-21.

The probe dials through internal/ssh.Dial — the SAME path the compliance scan and discovery use — so its auth-method handling (key, password, AND PAM keyboard-interactive) and host-key verification stay identical and cannot drift. In particular it offers keyboard-interactive, so a hardened host (PasswordAuthentication no + UsePAM keyboard-interactive) authenticates here exactly as it does for a scan. Host keys are verified via TOFU against the shared registry when WithKnownHosts is wired.

Types

type ConnProfileStore

type ConnProfileStore interface {
	Get(ctx context.Context, hostID uuid.UUID) (connprofile.Profile, error)
	RecordSSHAuth(ctx context.Context, hostID uuid.UUID, m connprofile.SSHAuthMethod) error
	RecordSudoMode(ctx context.Context, hostID uuid.UUID, m connprofile.SudoMode) error
}

ConnProfileStore is the subset of connprofile the probe uses to lead the dial with the host's known-good SSH auth method AND its sudo mode, and to record what actually worked. nil (the default) disables learning.

The liveness probe is the authoritative sudo-mode learner: it runs an innocuous `true` sentinel every cycle (~5 min), so unlike the opportunistic discovery/collector paths it reliably confirms the mode.

type Dialer

type Dialer interface {
	Dial(ctx context.Context, cred *credential.Credential, addr string, timeout time.Duration, prefer connprofile.SSHAuthMethod) (SessionExecutor, connprofile.SSHAuthMethod, error)
}

Dialer opens an SSH session against a host. Production uses realDialer (crypto/ssh.Dial); tests inject a stub.

prefer is the host's learned SSH auth method (connprofile.AuthUnknown when none): the dialer leads with it but still offers the other method. The returned method is the one that authenticated, for the caller to record. Both are best-effort learning, never a hard requirement.

type PolicyLoader

type PolicyLoader interface {
	LoadSecurity(ctx context.Context) (systemconfig.SecurityConfig, error)
}

PolicyLoader returns the current SecurityConfig — specifically the AllowCredentialSudoPassword flag that gates the sudo -S fallback. Implementations typically wrap systemconfig.Store.LoadSecurity. A nil loader OR an error from the loader defaults to "policy off" so the fallback path stays opt-in.

type ProbeOption

type ProbeOption func(*probeConfig)

ProbeOption configures the probe at construction time. Use WithDialer / WithPolicyLoader.

func WithDialer

func WithDialer(d Dialer) ProbeOption

WithDialer overrides the production SSH dialer. Tests pass a stub that doesn't open real connections.

func WithKnownHosts

func WithKnownHosts(store owssh.KnownHostsStore) ProbeOption

WithKnownHosts pins the probe's SSH dial to the shared host-key registry (TOFU), so the liveness probe verifies host keys exactly like the scan and discovery paths instead of ignoring them. Pass the same pool-backed store the other paths use (knownhosts.NewStore(pool)). nil (the default) still uses TOFU but against an in-process memory store (no cross-restart persistence) — fine for tests, not for production.

func WithPolicyLoader

func WithPolicyLoader(p PolicyLoader) ProbeOption

WithPolicyLoader wires the systemconfig reader the probe consults to decide whether to engage the sudo -S fallback. A nil loader (the default) is equivalent to "policy off".

Spec system-ssh-connectivity v1.2.0 C-09 / AC-18.

func WithProfiles

func WithProfiles(p ConnProfileStore) ProbeOption

WithProfiles enables per-host SSH auth-method learning: the probe leads the dial with the host's recorded method and records which method authenticated. nil (the default) keeps the historical key-first, no-learning order. See system-connection-profile.

type Resolver

type Resolver interface {
	Resolve(ctx context.Context, hostID uuid.UUID) (*credential.Credential, error)
}

Resolver returns the credential to use for a host. Implementations typically wrap credential.Service.Resolve. ErrNoCredential is the "no auth configured" signal — the probe records attempted=false and returns without touching SSH.

type SessionExecutor

type SessionExecutor interface {
	Run(ctx context.Context, cmd string) ([]byte, int, error)
	RunWithStdin(ctx context.Context, cmd string, stdin io.Reader) ([]byte, int, error)
	Close() error
}

SessionExecutor is the seam between the probe and the SSH session. Production wraps a real *ssh.Client (see realSession below); tests stub it directly to verify the call ordering without standing up an SSH server.

RunWithStdin feeds the reader's content into the remote process's stdin — used to deliver the credential password to `sudo -S`. The reader is consumed once.

Jump to

Keyboard shortcuts

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