feat(audit): JSONL-Logger mit Größenrotation, gzip und SIGHUP-Reopen

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
This commit is contained in:
Carsten Abele 2026-08-14 09:08:19 +02:00
parent b47ee11ba4
commit 2eb69bdcfe
5 changed files with 526 additions and 0 deletions

60
internal/audit/event.go Normal file
View file

@ -0,0 +1,60 @@
// Package audit schreibt strukturierte Audit-Ereignisse als JSON Lines.
package audit
import (
"crypto/sha256"
"encoding/hex"
)
// Audit-Ereignisse.
const (
EventLoginSuccess = "login_success"
EventLoginFailed = "login_failed"
EventLogout = "logout"
EventSessionExpired = "session_expired"
EventConfigDownload = "config_download"
EventDownloadDenied = "download_denied"
)
// Betriebsereignisse.
const (
EventNoCertFound = "no_cert_found"
EventOPNsenseUnreachable = "opnsense_unreachable"
EventLDAPFailover = "ldap_failover"
EventRateLimited = "rate_limited"
EventStartup = "startup"
)
// UnknownUser ersetzt den eingegebenen Namen, wenn der Benutzer im AD nicht
// gefunden wurde. Damit landet ein versehentlich ins Username-Feld getipptes
// Passwort nie im Klartext im Log.
const UnknownUser = "<unknown>"
// Event ist eine Zeile im Audit-Log. Leere Felder werden nicht serialisiert.
type Event struct {
TS string `json:"ts"`
Event string `json:"event"`
User string `json:"user,omitempty"`
SrcIP string `json:"src_ip,omitempty"`
Session string `json:"session,omitempty"`
Reason string `json:"reason,omitempty"`
VPNInstance string `json:"vpn_instance,omitempty"`
CertCN string `json:"cert_cn,omitempty"`
CertExpiry string `json:"cert_expiry,omitempty"`
Format string `json:"format,omitempty"`
Pattern string `json:"pattern,omitempty"`
Server string `json:"server,omitempty"`
Version string `json:"version,omitempty"`
ConfigSum string `json:"config_sum,omitempty"`
Detail string `json:"detail,omitempty"`
}
// ShortSession liefert eine kurze, nicht umkehrbare Korrelations-ID.
// Der Session-Token selbst darf niemals ins Log gelangen.
func ShortSession(token string) string {
if token == "" {
return ""
}
sum := sha256.Sum256([]byte(token))
return hex.EncodeToString(sum[:])[:4]
}