Skip to content

Audit Logging

The Control Center implements structured audit logging inspired by NVIDIA NeMo Guardrails' rail activation tracking. Every security-relevant action is logged with timestamp, severity, and decision details.

Design Philosophy

NeMo Guardrails tracks every "rail" that fires when processing LLM requests — input validation, output filtering, topic boundary enforcement. We adopted this pattern for infrastructure actions:

  • Every firewall change is a "rail activation"
  • Every profile switch is a "policy decision"
  • Every killswitch toggle is a "critical event"
  • The log provides a complete audit trail for post-incident analysis

Log Format

Events are stored in JSON-lines format at /app/data/audit.jsonl:

{"ts": "2026-04-01T14:33:43.839686+00:00", "event": "system.started", "severity": "info", "details": {"firewall_enabled": true, "killswitch": false, "rules_count": 2}}
{"ts": "2026-04-01T14:35:12.123456+00:00", "event": "firewall.profile_applied", "severity": "info", "details": {"profile": "minimal", "rules_count": 3}}
{"ts": "2026-04-01T14:40:01.654321+00:00", "event": "firewall.killswitch", "severity": "critical", "details": {"activated": true}}

Each line is a self-contained JSON object. This format is:

  • Easy to parse with standard tools (jq, grep, Python)
  • Appendable without loading the entire file
  • Compatible with log aggregation systems

Event Types

System Events

Event Severity Details
system.started info firewall_enabled, killswitch, rules_count

Firewall Events

Event Severity Details
firewall.rule_added info rule_id, description, protocol, port, destination
firewall.rule_deleted info rule_id, description
firewall.rule_updated info rule_id, changed fields
firewall.killswitch critical (on) / warning (off) activated
firewall.toggled warning (off) / info (on) enabled
firewall.profile_applied warning (unrestricted) / info profile, rules_count
firewall.force_applied info —

DNS Events

Event Severity Details
dns.blocking_toggled info blocking state

Route Events

Event Severity Details
routes.added info subdomain, vm_port
routes.removed info route_id, subdomain

Severity Levels

Level Color Examples
info Blue Startup, rule added, profile applied
warning Orange Firewall disabled, killswitch deactivated, unrestricted profile
critical Red Killswitch activated

Storage Management

Rotation

The audit file rotates automatically:

  • Trigger: File exceeds 2 MB
  • Action: Keep only the last 5,000 lines
  • Check: After every write

Thread Safety

All file operations are protected by a threading lock:

_lock = threading.Lock()

def log_event(event, details, severity):
    with _lock:
        with open(AUDIT_FILE, "a") as f:
            f.write(line)
        _maybe_rotate()

API

GET /api/audit/events?limit=200&severity=

Parameter Type Default Description
limit int 200 Maximum events to return
severity string — Filter by severity level

Returns events in chronological order (oldest first). The frontend reverses them for display (newest first).

Command-Line Access

You can also query the audit log directly:

# Last 10 events
tail -10 /app/data/audit.jsonl | jq .

# All critical events
grep '"critical"' /app/data/audit.jsonl | jq .

# Events from today
grep '2026-04-01' /app/data/audit.jsonl | jq .

# Killswitch events
grep 'killswitch' /app/data/audit.jsonl | jq .