Audit log¶
Every write operation (create, update, delete) on relevant tables lands in audit_log. With diff between old and new, with author, with timestamp.
Contents¶
| Field | Meaning |
|---|---|
id |
Entry UUID |
tenant_id |
Tenant scope |
user_id |
who did it (NULL for system actions) |
action |
host.create, alert_rule.update, dashboard.delete, … |
target_kind |
host, alert_rule, dashboard, … |
target_id |
UUID of affected resource |
old_values |
JSONB pre-change |
new_values |
JSONB post-change |
created_at |
time |
ip |
user's IP |
old_values and new_values are filled by track_change — a small helper converting SQLAlchemy models to dicts and masking sensitive fields.
Instrumented routes¶
These routes write audit entries:
- Hosts (create, update, delete)
- Host services (create, update, delete, ack, downtime set)
- Tenants
- Alert rules
- Notification channels
- Dashboards
- Monitoring scripts
- Profiles + profile-checks
- Users + roles
Login / logout / failed-login are also logged with action = auth.login_success / auth.login_failed.
Redacted fields¶
AUDIT_FIELD_BLACKLIST (in api/app/audit.py):
password_hashtwo_fa_secrettoken_hashkey_hashsnmp_communityssh_passwordprivate_key
These appear as "***" in the audit log — even when changed, never as plaintext.
Diff view¶
/audit-log → collapsible rows with diff highlighting:
- alert_rule_threshold_warn: 80
+ alert_rule_threshold_warn: 50
- alert_rule_channels: ["ops-email"]
+ alert_rule_channels: ["ops-email", "ops-push"]
Red/green colored, old/new side by side.
Filters¶
| Filter | Example |
|---|---|
| Action | only delete actions |
| Target kind | only host |
| Target ID | only changes to a specific host |
| User | who did it |
| Time | last 24 h, last 30 d, custom |
Filters persist in URL: /audit-log?action=delete&target_kind=host.
Audit on host detail¶
Per host: Audit tab shows entries with target_id = <hostId>. Useful for „what happened to this host?" on one page.
Retention¶
| Tier | Default retention |
|---|---|
| Community | 30 days |
| Pro | 90 days |
| Enterprise | configurable up to unlimited |
Auto-purge runs daily. For longer retention: regular audit export (CSV / JSON) to external storage.
Export¶
curl -H "Authorization: Bearer <JWT>" \
"https://your-domain.tld/api/v1/audit-log/export?from=2026-04-01&format=csv" \
> audit-april.csv
Format: CSV or JSON, all fields.
Security¶
- Audit log is read-only via UI — no edit/delete endpoints
- DB-side: no
UPDATEtriggers onaudit_log(except system migrations) - Backups include audit log — restoring an old backup loses recent entries
Permissions¶
| Permission | Effect |
|---|---|
audit.view |
View audit log |
audit.export |
CSV/JSON export |
audit.purge |
Manually delete older-than-X (super admin only) |
Compliance¶
When an auditor asks „who changed the threshold of service X on date Y?":
/audit-log?target_id=<service-uuid>&action=update- Sort by date, expand each
- Diff shows old and new values
- Author and IP visible
Sufficient for most ISO 27001 audits.
Next¶
- Soft delete & trash — what happens on delete
- PDF reports — audit as formal report