Documentation
¶
Overview ¶
Package auditx is the FedRAMP / NIST 800-53 audit logging layer for apic. It provides the building blocks for tamper-evident audit trails; it does not auto-wire those trails into generated servers.
What this package provides today:
- An event catalog (AllEvents, LookupControls) mapping each audit event code to the NIST 800-53 control IDs it contributes evidence for. The Controls field is a comma-separated list chosen for easy CSV consumption by an external control-mapping report.
- An emit API (Logger.Emit) that, given an Event whose Code is in the catalog, fills in the mapped controls, redacts sensitive values in Extra (see redact.go), and forwards an Envelope to each configured Sink. Emitting a code not in the catalog is a hard error (ErrUnknownEventCode).
- A per-Logger hash chain (Envelope.PrevHash / RecordHash) that provides tamper evidence: an external auditor can re-hash each record's JSON-canonical form and verify it links to the prior record's RecordHash. Under FIPS profiles the chain is the integrity anchor for AU-9.
- A rotating file sink (FileSink, NewFileSink) that writes JSON-Lines records. It is the only Sink implementation shipped today; the config validator rejects the reserved "syslog"/"cef" sink kinds until real sinks exist (GAP-0081).
Not yet implemented (future work):
- A standalone audit-report CLI that emits the control-mapping CSV from the catalog (no such command exists in cmd/).
- Generator-emitted middleware that calls Logger.Emit automatically from generated handlers. cmd/apic does not emit any auditx call today, so events — including the AC-2/AC-6 admin.* catalog entries — must be emitted by consumers at their own call sites. Install a process-wide Logger with SetDefault and emit via Default().Emit.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrUnknownEventCode = errors.New("auditx: unknown event code")
ErrUnknownEventCode is returned by Emit for codes not in the catalog.
Functions ¶
func LookupControls ¶
LookupControls returns the 800-53 control list for code, or false when the code is not in the catalog.
Types ¶
type CatalogEntry ¶
type CatalogEntry struct {
Code string
Description string
// Controls is a comma-separated list of NIST 800-53 control IDs.
// Format chosen for easy CSV consumption.
Controls string
}
CatalogEntry records one event code and the 800-53 controls it contributes evidence for.
func AllEvents ¶
func AllEvents() []CatalogEntry
AllEvents returns a copy of the catalog. Callers that mutate this slice do not affect the package state.
type Envelope ¶
type Envelope struct {
Code string `json:"code"`
Controls string `json:"controls"`
Subject string `json:"subject"`
Resource string `json:"resource,omitempty"`
Outcome string `json:"outcome,omitempty"`
AtUnixNano int64 `json:"at_unix_nano"`
Extra map[string]any `json:"extra,omitempty"`
PrevHash string `json:"prev_hash"`
RecordHash string `json:"record_hash"`
}
Envelope is what a Sink receives — the input Event plus the chain metadata. The hash chain (PrevHash, RecordHash) provides tamper evidence: an external auditor can verify the chain by re-hashing each record's JSON canonical form and comparing against the recorded RecordHash.
type Event ¶
type Event struct {
Code string // catalog event code (must be in AllEvents)
Subject string // user id / EDIPI / sub claim
Resource string // HTTP path, file path, key ID, etc.
Outcome string // "success" | "failure" | "denied" | "begin"
At time.Time // wall-clock; defaults to time.Now()
Extra map[string]any // additional context (callers should redact secrets)
}
Event is the input to Logger.Emit. Subject and Resource are typed strings to keep the JSON payload stable; everything else lives in Extra. Subject is typically the EDIPI / sub claim / mtlsx.Principal.
type FileSink ¶
type FileSink struct {
// contains filtered or unexported fields
}
FileSink writes JSON-Lines records to a rotated log file.
func NewFileSink ¶
func NewFileSink(cfg FileSinkConfig) (*FileSink, error)
NewFileSink validates cfg and constructs a file sink. N-07: the godoc always claimed validation, but the body previously only applied defaults -- an empty Path was accepted (lumberjack silently falls back to a process-name-derived file under os.TempDir(), which is not what an AU-2/AU-9 audit-sink operator configured), and there was no symlink/ regular-file guard, unlike the sibling rotating sink at pkg/obsx/logfile.go NewRotatingHandler. Mirrors that guard: an empty path is rejected; an existing path whose final component is a symlink is rejected outright (a log/audit sink is always application-created, never legitimately delivered as a symlink); an existing non-symlink path is canonicalized and must resolve to a regular file via obsx.ResolveSensitivePath.
type FileSinkConfig ¶
type FileSinkConfig struct {
Path string
MaxSizeMB int
MaxBackups int
MaxAgeDays int
Compress bool
}
FileSinkConfig configures a file-backed JSON-Lines sink with rotation via lumberjack. Defaults match FedRAMP AU-11 baseline (100 MiB / 7 backups / 365 days retention).
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger is the public emit API.
func Default ¶
func Default() *Logger
Default returns the current package-level Logger (may be nil).