audit

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package audit implements VORTEX's tamper-proof audit log (build plan M3.6): an append-only, HMAC-SHA256 hash-chained record of security-relevant events. Each entry's hash covers the previous entry's hash, so removing, reordering, or modifying any entry breaks the chain and is detected by Verify. It uses only the standard library (crypto/hmac, crypto/sha256).

Index

Constants

View Source
const (
	ArchiveThreshold = 100 * 1024 * 1024 // 100MB
	ArchiveRetention = 2 * 365 * 24 * time.Hour
)

Archival policy (build plan M19): the live log is rotated into a gzipped archive once it exceeds ArchiveThreshold, and archives older than ArchiveRetention are pruned.

Variables

This section is empty.

Functions

func ExportCSV

func ExportCSV(log *Log, filter QueryFilter, w io.Writer) error

ExportCSV writes the filtered entries as CSV with a header row. The detail map is JSON-encoded into a single column.

func ExportJSON

func ExportJSON(log *Log, filter QueryFilter, w io.Writer) error

ExportJSON writes the filtered entries as a single JSON array to w.

func ExportSplunk

func ExportSplunk(log *Log, filter QueryFilter, w io.Writer) error

ExportSplunk writes the filtered entries in Splunk HEC JSON format, one event per line: {"time":<epoch>,"event":{...entry fields...}}.

func ExportSyslog

func ExportSyslog(log *Log, filter QueryFilter, w io.Writer) error

ExportSyslog writes the filtered entries in RFC 5424 syslog format, one line per entry. VORTEX audit events use facility 13 (log audit) and severity 6 (informational), giving PRI = 13*8 + 6 = 110.

Types

type ComplianceReport added in v0.3.0

type ComplianceReport struct {
	Period         string         `json:"period"`
	TotalEvents    int            `json:"total_events"`
	ChainValid     bool           `json:"chain_valid"`
	EventsByActor  map[string]int `json:"events_by_actor"`
	EventsByAction map[string]int `json:"events_by_action"`
	SecurityEvents []Entry        `json:"security_events"` // auth failures, policy denials
	AdminActions   []Entry        `json:"admin_actions"`   // config changes, secret/key/namespace ops
	GeneratedAt    time.Time      `json:"generated_at"`
}

ComplianceReport summarises a period of audit activity for compliance review: event volumes, chain integrity, and the security-relevant and administrative entries themselves.

func GenerateComplianceReport added in v0.3.0

func GenerateComplianceReport(log *Log, since, until time.Time) (*ComplianceReport, error)

GenerateComplianceReport builds a ComplianceReport over entries with timestamps in [since, until]. Zero bounds are open-ended. ChainValid reflects Verify over the whole live log, not just the reported window — a tampered entry outside the window still invalidates the log.

func (*ComplianceReport) WriteCSV added in v0.3.0

func (r *ComplianceReport) WriteCSV(w io.Writer) error

WriteCSV renders the report as metric rows (section,key,value) for spreadsheet analysis.

func (*ComplianceReport) WriteJSON added in v0.3.0

func (r *ComplianceReport) WriteJSON(w io.Writer) error

WriteJSON renders the report as indented JSON for SIEM ingestion.

func (*ComplianceReport) WriteMarkdown added in v0.3.0

func (r *ComplianceReport) WriteMarkdown(w io.Writer) error

WriteMarkdown renders the report as a human-readable Markdown document.

type Entry

type Entry struct {
	Seq       uint64         `json:"seq"`
	Timestamp time.Time      `json:"timestamp"`
	Actor     string         `json:"actor"`    // user ID, "system", "cli", or an IP
	Action    string         `json:"action"`   // e.g. "config.reload", "secret.set"
	Resource  string         `json:"resource"` // what was acted on
	Detail    map[string]any `json:"detail,omitempty"`
	Hash      string         `json:"hash"`
}

Entry is a single audit record. Hash is the HMAC chaining this entry to the previous one; it is computed over the previous hash plus this entry's fields.

type Log

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

Log is an append-only audit log backed by a newline-delimited JSON file. It is safe for concurrent Append calls.

func NewLog

func NewLog(path string, hmacKey []byte) (*Log, error)

NewLog opens (creating if needed) the audit log at path and reads the tail so new entries continue the existing chain. hmacKey keys the HMAC-SHA256 chain.

func (*Log) Append

func (l *Log) Append(_ context.Context, actor, action, resource string, detail map[string]any) error

Append writes a new entry to the log with the next sequence number and a hash chaining it to the previous entry. It is safe for concurrent use.

func (*Log) Archive added in v0.3.0

func (l *Log) Archive() (string, error)

Archive rotates the live log into audit-<year>-<month>.log.gz beside it and starts a fresh log (the hash chain restarts at seq 1, so Verify stays valid for both the archive's snapshot and the new live log). Archives older than ArchiveRetention are pruned. It returns the archive path, or "" when the live log is empty.

func (*Log) ArchiveIfOver added in v0.3.0

func (l *Log) ArchiveIfOver(limit int64) (string, bool, error)

ArchiveIfOver rotates the live log only when it exceeds limit bytes (<= 0 uses ArchiveThreshold), returning the archive path and whether it rotated.

func (*Log) Query

func (l *Log) Query(filter QueryFilter) ([]Entry, error)

Query returns the entries matching filter. Without a Limit results are in chronological (oldest-first) order; with a Limit the newest matches are returned first, capped at Limit.

func (*Log) Rekey added in v0.3.0

func (l *Log) Rekey(newKey []byte) error

Rekey rewrites the entire live log, recomputing the HMAC chain under newKey, used by the master-key migration (production audit C1) to move a legacy cluster-name-keyed log onto the master-derived key. The sequence numbers, timestamps, and payloads are preserved; only the chain hashes are recomputed. The pre-migration log verifies under the OLD key (this Log's current key); after Rekey it verifies under newKey. It returns an error if the existing chain does not verify under the current key (refusing to "launder" a tampered log onto a fresh key).

func (*Log) Verifies added in v0.3.0

func (l *Log) Verifies() bool

Verifies reports whether the live log verifies under this Log's current key — a probe used by migration to detect which key a log is on.

func (*Log) Verify

func (l *Log) Verify() error

Verify reads every entry and recomputes the hash chain. It returns an error naming the first entry whose recomputed hash does not match (tamper, deletion, or reordering), or nil if the chain is intact.

type QueryFilter

type QueryFilter struct {
	Actor    string
	Action   string
	Resource string
	Since    time.Time
	Until    time.Time
	Limit    int
}

QueryFilter restricts which entries Query returns. Zero-valued fields are not applied. Since and Until bound the timestamp (inclusive). Limit caps the result count and, when set, returns the newest matching entries first.

Jump to

Keyboard shortcuts

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