kernelalerts

package
v4.2.0-rc.2 Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package kernelalerts raises the kernel's operational alerts: leaf certificates (Agent, forward link, module) that were not renewed in time, CAs close to their end, and phased processes (the node credential split, the identity cutover) left in a non-final phase. A Monitor scans the certificate stores and the phase tables read-only, keeps one row per alert in v4_kernel_alert, and sends the administrators one digest of the alerts that are new, worse or due again. GET /api/v4/kernel/alerts lists the rows. Nothing here changes a certificate or a phase.

Index

Constants

View Source
const (
	// KindAgentCertificate: a node's latest Agent client certificate is
	// close to its end (or past it) and was not renewed.
	KindAgentCertificate = "agent_certificate_expiring"
	// KindLinkCertificate: the same for a forward node's link certificate
	// (H28).
	KindLinkCertificate = "link_certificate_expiring"
	// KindModuleCertificate: the same for a module's certificate.
	KindModuleCertificate = "module_certificate_expiring"
	// KindCAExpiring: the current module (Agent, kernel) CA or forward link
	// CA is within ca_expiry_days of its end.
	KindCAExpiring = "ca_expiring"
	// KindNodeSecretsSplitStalled: a node credential split table sits in
	// dual_write or dual_read and was not touched for phase_stuck_after.
	KindNodeSecretsSplitStalled = "node_secrets_split_stalled" // #nosec G101 -- names an alert kind, not a credential.
	// KindNodeSecretsFinalizeInterrupted: a table's finalize started and
	// did not complete.
	KindNodeSecretsFinalizeInterrupted = "node_secrets_finalize_interrupted" // #nosec G101 -- names an alert kind, not a credential.
	// KindIdentityImportStalled: the identity authority sits in importing
	// without progress for phase_stuck_after.
	KindIdentityImportStalled = "identity_import_stalled"
	// KindIdentityCutoverPending: identity owns logins since the latest
	// cutover, but legacy credentials were not finalized for
	// phase_stuck_after.
	KindIdentityCutoverPending = "identity_cutover_not_finalized"
)

Alert kinds.

View Source
const (
	SubjectNode        = "node"
	SubjectCA          = "ca"
	SubjectModule      = "module"
	SubjectNodeSecrets = "node_secrets" // #nosec G101 -- names a subject kind, not a credential.
	SubjectIdentity    = "identity"
)

Subject kinds.

View Source
const (
	StatusActive   = "active"
	StatusResolved = "resolved"
	StatusAll      = "all"
)

Statuses a listing filters by.

View Source
const (
	DefaultLimit = 100
	MaxLimit     = 500
)

Listing limits.

Variables

View Source
var ErrInvalidQuery = errors.New("invalid alert query")

ErrInvalidQuery wraps every reason a listing query is refused.

Functions

This section is empty.

Types

type Alert

type Alert struct {
	ID             uint           `json:"id"`
	Key            string         `json:"key"`
	Kind           string         `json:"kind"`
	Severity       string         `json:"severity"`
	Status         string         `json:"status"`
	SubjectKind    string         `json:"subject_kind"`
	Subject        string         `json:"subject"`
	Message        string         `json:"message"`
	Detail         map[string]any `json:"detail"`
	ExpiresAt      *time.Time     `json:"expires_at"`
	FirstSeenAt    time.Time      `json:"first_seen_at"`
	LastSeenAt     time.Time      `json:"last_seen_at"`
	LastNotifiedAt *time.Time     `json:"last_notified_at"`
	NotifyCount    int            `json:"notify_count"`
	ResolvedAt     *time.Time     `json:"resolved_at"`
}

Alert is an alert as the admin API answers it.

type Finding

type Finding struct {
	Kind        string
	Severity    string
	SubjectKind string
	Subject     string
	Message     string
	// Detail holds the facts behind the alert; no secret, ever.
	Detail    map[string]any
	ExpiresAt *time.Time
}

Finding is one alert condition a scan found.

func (Finding) Key

func (f Finding) Key() string

Key is the alert's identity: its kind and subject.

type Monitor

type Monitor struct {
	DB       *gorm.DB
	Settings config.AlertSettings
	// Notifier may be nil: alerts are then only recorded and listed.
	Notifier Notifier
	// Now defaults to time.Now.
	Now func() time.Time
}

Monitor keeps v4_kernel_alert in step with what the Scanner finds and notifies the administrators of what needs their attention. Run it in one process at a time (the singleton workers' lease).

func (*Monitor) Run

func (m *Monitor) Run(ctx context.Context)

Run scans every check interval until ctx ends. A disabled monitor, or one without a database, returns at once.

func (*Monitor) RunOnce

func (m *Monitor) RunOnce(ctx context.Context) (ScanSummary, error)

RunOnce scans, updates the alert rows and sends the digest of what is due.

type Notification

type Notification struct {
	Title   string
	Content string
	Alerts  []model.KernelAlert
}

Notification is one digest for the administrators: every alert that is new, worse or due again in a scan, in one message.

type Notifier

type Notifier interface {
	Notify(ctx context.Context, notification Notification) error
}

Notifier delivers a digest to the administrators. An error means nothing was delivered: the alerts stay due and the next scan tries again.

type Page

type Page struct {
	Alerts  []Alert `json:"alerts"`
	Summary Summary `json:"summary"`
}

Page is a listing: the alerts and the counts of all active alerts.

func List

func List(ctx context.Context, db *gorm.DB, query Query) (Page, error)

List answers the alerts of query, critical first and, within a severity, the soonest to end first, with the counts of all active alerts. A database without the alert table has none.

type Query

type Query struct {
	Status string
	// Kind and Severity filter when set.
	Kind     string
	Severity string
	Limit    int
}

Query selects alerts: Status is active (the default), resolved or all.

func ParseQuery

func ParseQuery(status, kind, severity, limit string) (Query, error)

ParseQuery validates raw query values.

type ScanResult

type ScanResult struct {
	Findings []Finding
	// Unevaluated lists the kinds whose check failed. The alerts of those
	// kinds are left as they are: a failed scan proves nothing is resolved.
	Unevaluated map[string]bool
}

ScanResult is what one scan found.

type ScanSummary

type ScanSummary struct {
	Active   int
	Opened   int
	Resolved int
	Notified int
}

ScanSummary is what one scan did.

type Scanner

type Scanner struct {
	DB       *gorm.DB
	Settings config.AlertSettings
	// Now defaults to time.Now.
	Now func() time.Time
}

Scanner reads the certificate stores and the phase tables and answers what is wrong now. It never writes.

func (*Scanner) Scan

func (s *Scanner) Scan(ctx context.Context) (ScanResult, error)

Scan runs every check. A check that fails is logged and its kinds are reported in Unevaluated; the others still run. Only a cancelled context fails the scan.

type Summary

type Summary struct {
	Active   int64 `json:"active"`
	Critical int64 `json:"critical"`
	Warning  int64 `json:"warning"`
}

Summary counts the active alerts.

Jump to

Keyboard shortcuts

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