monitor

package
v0.3.7 Latest Latest
Warning

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

Go to latest
Published: Nov 13, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package monitor finds what needs an admin – expiring certificates, CA certificates and CRLs, a sealed server, silent agents, failed deployments – keeps it as alerts in system.db and (step 23) tells someone about it (docs/PHASE3.md §9). Everything here works while the server is sealed: it reads pki.db and the keyring state and decrypts nothing.

Index

Constants

View Source
const (
	Warning  = "warning"
	Critical = "critical"
)

Severities of an alert.

View Source
const (
	KindCertExpiry       = "cert_expiry"
	KindCAExpiry         = "ca_expiry"
	KindCRL              = "crl"
	KindSealed           = "sealed"
	KindAgentSilent      = "agent_silent"
	KindAgentCertificate = "agent_certificate"
	KindDeployFailed     = "deploy_failed"

	// The TLS scan (docs/PHASE3.md §10.2, v0.3.4).
	KindScanMismatch    = "scan_mismatch"
	KindScanExpiry      = "scan_expiry"
	KindScanUnreachable = "scan_unreachable"
	KindScanChain       = "scan_chain"
)

Kinds of alerts (docs/PHASE3.md §9.2).

View Source
const ResolvedWindow = 7 * 24 * time.Hour

ResolvedWindow is how long a resolved alert stays on the Alerts page and in the API (it is kept 30 days, see internal/server/monitor.go).

Variables

This section is empty.

Functions

This section is empty.

Types

type Agents

type Agents interface {
	ListAgents(ctx context.Context, who keys.Who) ([]agents.Agent, error)
	GetAgent(ctx context.Context, who keys.Who, id string) (*agents.Agent, error)
}

Agents is what the evaluation reads about agents; nil when the agent listener is off.

type Alert

type Alert struct {
	ID, Key, Kind, Subject, Severity, Detail, Href string
	FirstSeen, LastSeen                            time.Time
	Resolved                                       time.Time // zero while open
	NotifiedSeverity                               string    // "" = not reported yet
	Notified                                       time.Time
}

Alert is one row of the alerts table.

func (Alert) Open

func (a Alert) Open() bool

Open reports whether the alert still holds.

type Changes

type Changes struct {
	Opened, Raised, Lowered, Resolved []Alert
}

Changes is what one Sync changed – for the log; notifications read the notified_* columns, so a lost Changes value loses no message.

func (Changes) Empty

func (c Changes) Empty() bool

Empty reports whether nothing changed.

type DigestOptions

type DigestOptions struct {
	Server      string              // host name in the subject
	RepeatEvery time.Duration       // reminder for an alert still open
	Link        func(string) string // UI path → absolute link; nil = none
	Channels    []string            // queue one message per channel
}

DigestOptions shape the digest of one evaluation.

type EndpointSource added in v0.3.4

type EndpointSource interface {
	List(ctx context.Context, who keys.Who) ([]tlsscan.Endpoint, error)
}

EndpointSource is what the evaluation reads about TLS endpoints (*tlsscan.Service).

type EndpointState added in v0.3.4

type EndpointState struct {
	Endpoint   tlsscan.Endpoint
	Assessment tlsscan.Assessment
	// Input is the expected set and the served leaf as the PKI knows it (the
	// serial of the newest certificate, for the page).
	Input tlsscan.Input
	// ServedID is the ID of the served leaf if the PKI issued it, else "".
	ServedID string
}

EndpointState is an endpoint with what the PKI says about it and the assessment of the two – the state the page, the API and the alerts all show.

func Created added in v0.3.4

func Created(ep tlsscan.Endpoint) EndpointState

Created is the state of an endpoint that was just added: nothing is known about it before its first scan.

type Endpoints added in v0.3.4

type Endpoints struct {
	Service *tlsscan.Service
	Eval    *Evaluator
	Clock   clock.Clock
}

Endpoints is the TLS scan as the REST API and the UI use it (docs/PHASE3.md §10): the endpoint service, which checks the roles and audits, plus the assessment the alerts follow, so that the page, the API and the alerts show the same state.

func (*Endpoints) Create added in v0.3.4

func (e *Endpoints) Create(ctx context.Context, who keys.Who, req tlsscan.Request) (*tlsscan.Endpoint, error)

Create adds an endpoint (permission endpoint.manage, audited by the service).

func (*Endpoints) Delete added in v0.3.4

func (e *Endpoints) Delete(ctx context.Context, who keys.Who, id string) error

Delete removes an endpoint (permission endpoint.manage, audited).

func (*Endpoints) List added in v0.3.4

func (e *Endpoints) List(ctx context.Context, who keys.Who) ([]EndpointState, error)

List returns every endpoint with its assessed state, by host. The endpoint service decides whether who may read (tenant-wide pki.read); the assessment itself is computed with the evaluator's system principal and only for what the service returned.

func (*Endpoints) ScanNow added in v0.3.4

func (e *Endpoints) ScanNow(ctx context.Context, who keys.Who, id string) error

ScanNow makes an endpoint due at once (permission endpoint.scan, audited, once per endpoint and 60 seconds: a *tlsscan.WaitError otherwise).

func (*Endpoints) Settings added in v0.3.4

func (e *Endpoints) Settings() tlsscan.Settings

Settings are the monitor.scan_* keys the scan runs with (the allowed ports, the limit of endpoints, scanning off) – the page shows them next to the add form.

type Engine

type Engine interface {
	Certificates(ctx context.Context, who keys.Who, f ca.CertificateFilter) (*ca.CertificatePage, error)
	Certificate(ctx context.Context, who keys.Who, id string) (*ca.CertificateInfo, error)
	CAs(ctx context.Context, who keys.Who) ([]ca.CAInfo, error)
	// CertificateByFingerprint finds the certificate a TLS endpoint serves.
	CertificateByFingerprint(ctx context.Context, who keys.Who, fingerprint string) (*ca.CertificateInfo, error)
}

Engine is what the evaluation reads from the CA engine.

type Evaluator

type Evaluator struct {
	Engine Engine
	Agents Agents // nil = no agent rules
	Seal   func() keys.Status
	Rules  Rules
	Who    keys.Who // a system principal that may read the whole tenant
	// Scan gives the TLS endpoints and their last scans; nil = no scan rules
	// (docs/PHASE3.md §10.2).
	Scan EndpointSource
	// ScanOff: scanning is switched off (monitor.scan_interval: off). The scan
	// alerts are not produced, so they resolve – there is no fresh result –
	// but EndpointStates still tells the last known state.
	ScanOff bool
}

Evaluator finds the conditions of docs/PHASE3.md §9.2.

func (*Evaluator) EndpointStates added in v0.3.4

func (e *Evaluator) EndpointStates(ctx context.Context, now time.Time) ([]EndpointState, error)

EndpointStates assesses every endpoint at now, in the order of the source. It reads like the evaluation and changes nothing; with no endpoint source it returns nothing.

func (*Evaluator) Evaluate

func (e *Evaluator) Evaluate(ctx context.Context, now time.Time) ([]Finding, error)

Evaluate returns every condition that holds at now, sorted by key.

type Finding

type Finding struct {
	Key, Kind, Subject, Severity, Detail, Href string
}

Finding is one condition the evaluation found. Key is stable across runs (kind and the ID of what it is about), so the store can tell new, changed and gone conditions apart.

type Rules

type Rules struct {
	// End-entity certificates: warning and critical before they expire.
	ExpiryWarn, ExpiryCrit time.Duration
	// CA certificates.
	CAWarn, CACrit time.Duration
	// A sealed server: warning after SealedAfter; critical once a CRL's
	// next update is closer than CRLHorizon (a sealed server can't sign).
	SealedAfter, CRLHorizon time.Duration
	// Agents: warning and critical after this long without a report.
	AgentSilentWarn, AgentSilentCrit time.Duration
	// An active agent's own certificate: critical below this.
	AgentCertificate time.Duration
	// ExpiredFor: an expired, not superseded certificate stays an alert this
	// long after its end, then the alert is closed.
	ExpiredFor time.Duration
	// RepeatEvery: a reminder for an open alert (step 23).
	RepeatEvery time.Duration
	// The TLS scan (docs/PHASE3.md §10.2): failed scans in a row before an
	// endpoint is unreachable, and how old the newest certificate for a name
	// must be before an older one that is still served is an alert.
	ScanUnreachableAfter int
	ScanMismatchAfter    time.Duration
}

Rules are the thresholds of the evaluation (configuration `monitor:`).

func DefaultRules

func DefaultRules() Rules

DefaultRules are the owner-approved defaults (Q7, 2026-10-29).

type Store

type Store struct {
	DB     *sql.DB // system.db, the write connection
	Tenant string
	Rand   io.Reader // nil = crypto/rand (IDs)
}

Store keeps the alerts of one tenant in system.db.

func (*Store) Digest

func (s *Store) Digest(ctx context.Context, now time.Time, opt DigestOptions) (notify.Digest, error)

Digest collects what to report since the last digest – new alerts, alerts that became critical, reminders, resolved alerts whose opening was reported – marks them and queues one message per channel, all in one transaction. It returns the digest (no events = nothing queued). Without channels nothing is marked: once a channel is configured, the first message lists every open alert.

func (*Store) List

func (s *Store) List(ctx context.Context, who keys.Who, now time.Time) (open, resolved []Alert, err error)

List is what the Alerts page and GET /alerts show to who: the open alerts (critical first, then the oldest) and those resolved within ResolvedWindow (newest first). Alerts name certificates, CAs and hosts of the whole tenant, so it needs the tenant-wide read role (viewer); a role limited to one CA does not see them.

func (*Store) Open

func (s *Store) Open(ctx context.Context) ([]Alert, error)

Open lists the open alerts, critical first.

func (*Store) Prune

func (s *Store) Prune(ctx context.Context, cutoff time.Time) (int64, error)

Prune deletes alerts resolved before cutoff.

func (*Store) Since

func (s *Store) Since(ctx context.Context, since time.Time) ([]Alert, error)

Since lists the open alerts and those resolved at or after since.

func (*Store) Sync

func (s *Store) Sync(ctx context.Context, now time.Time, findings []Finding) (Changes, error)

Sync makes the open alerts match findings in one transaction: new keys open an alert, known keys are updated (and may rise or fall), open alerts without a finding are resolved.

Jump to

Keyboard shortcuts

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