Documentation
Getting Started
Documentation Index Installation Details Quickstart
Architecture
Alert Geometry Coverage Data Flow Sequences Design Standards Display System Architecture Eas Decoding Summary Eas Monitor V3 Architecture Sdr Service Architecture System Architecture Theory Of Operation
Development
Agents Certification Reliability Plan Component Library Contributing Fcc Part11 Compliance Matrix Javascript Api Large File Refactor Plan Navigation Releasing Sdr Frequency Validation User Interface Guide
Hardware
Alpha Led Guide Argon40 Zigbee Setup Capacity And Sizing Gpio Guide Gps Hat Setup Hwsetup Helper Neopixel Led Control Sdr Setup Serial To Ethernet Adapters Vfd Display Setup Waveshare Rs232 Wifi Setup
Guides
Alert Signals Analytics And Reporting Api Key Management Application Settings Audio Monitoring Audit Log Review Database Backups Database Browser Disk Space Cleanup Eas Config Tool Eas Test Signal Pipeline Gated Alerts Hardware Quickstart Health Monitoring Help Https Setup Icecast Streaming Setup Ipaws Feed Integration Local Authorities Local Mail Server Manual Eas Events Mfa Totp Setup Notifications One Button Upgrade Setup Instructions Smart Setup Sms Opt In Ssl Web Ui Guide Tailscale Setup Tts Normalization
Troubleshooting
Audio Sdr Fix Tool Firewall Requirements Polling Not Working Sdr Master Troubleshooting Guide Troubleshooting 504 Timeout Tts Troubleshooting
Security
Audit Log Integrity Public Routes Security
Reference
About Alpha M Protocol Changelog Dependency Attribution Diagrams Ecig Cap To Eas Implementation Guide V1 0 Fcc 26 38 Eas Cybersecurity Fips Data Sources Mdc1200 Nrsc4B Same Standard Nws Alert Parameters Nws Zone Catalog Ohio Eas Documentation Overview Protocols Overview Rbds Standard Repository Statistics Sage Endec Same Site Reorganization Vtec Event Linking
Policies
Privacy Policy Sms Messaging Terms Of Use Trademark Policy

Audit Log Review

EAS Station™ maintains two audit trails: a structured database audit log that captures user actions and security events, and a security log file in fail2ban-compatible format that captures authentication events.

The database audit log is tamper-evident: every entry is hash-chained to its predecessor and signed with the station's Ed25519 key, so edits, deletions, and insertions are cryptographically detectable. See Audit Log Integrity for the full design, threat model, and key management.


Database Audit Log

The database audit log records:

  • Successful and failed login attempts
  • MFA enrollment and verification events
  • Permission denial events
  • Configuration changes
  • Alert lifecycle events — every CAP alert received, EAS message generated, and manual activation is captured automatically

Viewing Audit Logs in the Web Interface

  1. Navigate to System Logs and select the Audit tab (/logs?type=audit), or use the Audit Log card on the Admin dashboard.
  2. Use the filter controls to narrow results:
    • Date range — filter by start and end date/time
    • User — filter by username
    • Action type — filter by event category
    • IP address — filter by source IP
  3. Click any row to expand details.
  4. Use Export CSV to download the filtered log for archival or analysis.

Audit Log Event Types

Every action value is a dotted string defined by AuditAction in app_core/auth/audit.py. The most relevant ones:

Event Trigger
auth.login.success Successful username/password authentication
auth.login.failure Failed login attempt (wrong password)
auth.logout User session ended
auth.session.expired Session timed out
mfa.enrolled MFA enabled on an account
mfa.disabled MFA disabled on an account
mfa.verify.success Successful TOTP verification
mfa.verify.failure Invalid MFA code entered
mfa.backup_code.used Backup code used for login
user.created New admin account created
user.updated / user.deleted Admin account edited / deleted
user.role.changed Account's role changed
user.password.changed Password changed or reset
role.created / role.updated / role.deleted RBAC role management
permission.granted / permission.revoked Direct permission grant/revoke
security.permission_denied Access denied due to insufficient role
security.invalid_token Invalid/expired token presented
security.rate_limit_exceeded Login rate limit tripped
config.updated Application configuration updated
receiver.configured Audio/radio receiver configuration changed
gpio.activated / gpio.deactivated GPIO relay keyed / released
alert.received CAP alert ingested from a polling source (automatic)
alert.deleted An alert record was deleted
eas.broadcast EAS message generated for broadcast (automatic)
eas.manual_activation Operator-initiated manual EAS activation (automatic)
eas.cancellation Operator-forced broadcast abort
log.exported / log.deleted Log export or deletion
audit.chain.verified An operator ran tamper-evidence verification

There is currently no dedicated AuditAction for API keys or IP filters — the API-key feature itself is not yet implemented (see API Key Management). Deleting or toggling an IP filter is recorded under the generic config.updated action (with the specific action and IP address in details); adding a filter is not logged at all.


Verifying the Log Hasn't Been Tampered With

Every database audit entry carries three cryptographic fields — prev_hash, entry_hash, and signature — that chain it to the entry before it and sign it with the station's Ed25519 key.

To verify via the web UI:

  1. Navigate to System Logs → Audit tab (/logs?type=audit).
  2. In the Chain Integrity card at the top, choose a scope (entire chain, or newest N rows for very large logs).
  3. Click Verify Chain Integrity.
  4. A green banner means every hash link and signature checked out — the log has not been edited, deleted from, or reordered. A red banner reports the first bad row id and the exact reason.

To verify via the API:

curl -b cookies.txt "https://your-eas-station.example.com/security/audit-logs/verify"

Each verification run is itself recorded in the chain as an audit.chain.verified entry, giving you a receipt of when the log was last checked and what the verdict was.

!!! warning "Ephemeral key warning" If the verification result warns about an ephemeral signing key, the station has no persistent Ed25519 key and signatures will not survive a service restart. Provision one — see Audit Log Integrity → Key Management.

For the full design, threat model (including what tampering is and isn't detectable), and key management procedures, see Audit Log Integrity.


Via the REST API

Retrieve audit log entries programmatically:

Note: API-key authentication (X-API-Key) is planned but not yet implemented — see API Key Management. Until it ships, these endpoints require an authenticated browser session (log in first and reuse the session cookie).

curl -H "X-API-Key: <key>" \
  "https://your-eas-station.example.com/security/audit-logs?days=7"

Query parameters:

Parameter Description Default
days Lookback window 7
user Filter by username All
action Filter by event type All
limit Maximum results 100

Direct database query:

psql -U eas_station -d eas_station -c \
  "SELECT timestamp, action, username, ip_address, details
   FROM audit_logs
   WHERE timestamp > NOW() - INTERVAL '24 hours'
   ORDER BY timestamp DESC
   LIMIT 50;"

Security Log File

Authentication events are also written to /var/log/eas-station/security.log in a format compatible with fail2ban.

Log Format

[YYYY-MM-DD HH:MM:SS UTC] EVENT_TYPE from IP_ADDRESS username=USERNAME details=DETAILS

Example entries:

[2025-02-20 14:32:11 UTC] FAILED_LOGIN from 192.168.1.50 username=admin details=wrong_password
[2025-02-20 14:32:45 UTC] MALICIOUS_LOGIN from 203.0.113.10 username=admin'; DROP TABLE-- details=malicious_input
[2025-02-20 14:33:00 UTC] RATE_LIMIT_EXCEEDED from 203.0.113.10 username=unknown details=too_many_attempts

Event Types in Security Log

Event Type Description
FAILED_LOGIN Incorrect password
MALICIOUS_LOGIN SQL/command injection attempt detected in login fields
RATE_LIMIT_EXCEEDED IP locked out after too many failures

Tailing the Security Log

sudo tail -f /var/log/eas-station/security.log

Searching for Specific IPs or Events

# All events from a specific IP
grep "203.0.113.10" /var/log/eas-station/security.log

# All malicious attempts today
grep "MALICIOUS_LOGIN" /var/log/eas-station/security.log | grep "$(date +%Y-%m-%d)"

# Count failed logins per IP
grep "FAILED_LOGIN" /var/log/eas-station/security.log | \
  awk '{print $5}' | sort | uniq -c | sort -rn | head -20

fail2ban Integration

fail2ban here is an enforcement backend, not a log-parsing detector: EAS Station itself decides who to ban (via its own database-backed IP filter logic) and pushes those bans to an fail2ban "actuator jail" whose filter is deliberately written to never match any real log line (/etc/fail2ban/filter.d/eas-station-empty.conf, generated by webapp/admin/fail2ban.py) — the jail exists only so fail2ban will hold and enforce the application's bans at the firewall level. See the Security Guide for setup instructions.


Malicious Login Attempts Dashboard

EAS Station™ tracks injection and brute-force attempts in the Malicious Logins page:

  1. Navigate to the Malicious Logins card on the Admin dashboard (/security/malicious-logins).
  2. The dashboard shows:
    • Total malicious attempts logged
    • Number of unique attacking IPs
    • Attempts in the last 24 hours
    • Top attacking IPs by attempt count
  3. Use the Quick Ban button next to any IP to immediately add it to the blocklist.

IP Filter Management

View and manage automatically and manually created IP filters:

  1. Go to the IP Filters section of the Malicious Logins page (/security/malicious-logins).
  2. The list shows each filter's IP/CIDR, type (allowlist/blocklist), reason, and expiry.
  3. Actions:
    • Toggle — activate or deactivate a filter without deleting it
    • Delete — permanently remove the filter
    • Add new — manually add an IP to the allowlist or blocklist

Auto-ban triggers and durations:

Trigger Ban Duration
SQL/command injection in login 24 hours
5 consecutive failed logins 24 hours
10+ login attempts per minute (flooding) 1 hour

!!! tip "Add your admin IP to the allowlist" Before enabling strict rate limiting, add your own IP address to the allowlist to prevent accidental lockout. Go to Admin → Security → IP Filters → Add → Allowlist.


Log Rotation

No logrotate configuration ships for /var/log/eas-station/security.log. Neither install.sh nor the repository installs a /etc/logrotate.d/eas-station entry — the file grows unbounded until an operator rotates it manually. If you want rotation, add your own logrotate config, for example:

sudo tee /etc/logrotate.d/eas-station <<'EOF'
/var/log/eas-station/security.log {
    daily
    rotate 30
    compress
    missingok
    notifempty
}
EOF

Regular Review Recommendations

  • Daily: Glance at the Malicious Logins dashboard for new auto-bans.
  • Weekly: Export the audit log as CSV and archive it. Review any CONFIG_CHANGED or USER_CREATED events you did not initiate.
  • Monthly: Purge expired blocklist entries (Admin → Security → IP Filters → Cleanup) and review any remaining active blocks.
  • Immediately: Investigate any MALICIOUS_LOGIN events, unusual off-hours logins, or logins from unexpected IP ranges.

Troubleshooting

Audit log is empty

  • The audit log starts populating from the moment of the first login after the audit_logs table was created. Run alembic upgrade head to ensure the table exists.

Security log not being written

  • Check that /var/log/eas-station/ exists and is writable by the eas-station user:
    sudo mkdir -p /var/log/eas-station
    sudo chown eas-station:eas-station /var/log/eas-station
    sudo systemctl restart eas-station-web
    

fail2ban is not enforcing bans

fail2ban does not parse security.log for this jail — the filter (eas-station-empty.conf) is deliberately written to never match anything. Detection and the ban decision both happen in the application. If a ban recorded in EAS Station isn't actually blocking traffic:

  • Confirm the eas-station jail is loaded: sudo fail2ban-client status eas-station.
  • Check Admin → fail2ban in the web UI, which surfaces jail status and lets you re-apply the configuration.
  • Confirm /etc/fail2ban/jail.local declares the jail with logpath = /var/log/eas-station/security.log (required by fail2ban even though the filter never matches) and that the fail2ban service itself is running: sudo systemctl status fail2ban.

This document is served from docs/guides/AUDIT_LOG_REVIEW.md in the EAS Station™ installation.