Skip to content

Latest commit

Β 

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›‘οΈ EC2 - Linux Security Monitor

ClamAV malware scanning with quarantine and alerting, automatic security updates, and a terminal status dashboard for systemd Linux β€” built for EC2, tested on Ubuntu and Amazon Linux

Shell Linux ClamAV License: MIT Lint

Features β€’ Quick Start β€’ Usage β€’ Testing β€’ Contributing


✨ Features

Feature What it does
🦠 ClamAV scanning Quick (30–90 s) or full (10–30 min) clamscan sweeps, non-existent paths skipped automatically
πŸ”’ Quarantine Infected files are moved (never deleted) to a 0700 root-owned directory, excluded from later scans
πŸ“£ Alerting Runs your ALERT_COMMAND with the findings on stdin β€” mail, SNS, Slack webhook, anything
πŸ”„ Auto updates Applies pending updates during every scan (apt / dnf) and reports applied vs still-available
🧬 Fresh definitions Runs freshclam before each scan, pausing the service so it can't hold the database lock
πŸ“Š Status dashboard Real state only: scan freshness, 5-point compliance score, services, signature version and age
⏰ systemd timers Daily scan + 6-hourly health check, Persistent=true so a stopped instance catches up
🩺 Self-healing health check Restarts dead services, refreshes stale definitions, re-enables stopped timers
βš™οΈ Single config file One /etc/security-monitor/security-monitor.conf drives behaviour and what the dashboard reports
πŸ“ Managed logs Logrotate for the service logs, age-based pruning for per-scan logs, status as JSON

πŸ—ΊοΈ Architecture

Two scripts. security-manager installs and maintains; security-monitor scans and reports. Both read the same config file, so a schedule or path is stated in exactly one place.

flowchart LR
    CONF["βš™οΈ security-monitor.conf"]

    subgraph timers["⏰ systemd timers"]
        ST["πŸ•‘ scan.timer"]
        HT["🩺 health.timer"]
    end

    ST --> MON["πŸ›‘οΈ security-monitor scan"]
    HT --> MGR["πŸ”§ security-manager health"]

    MON --> FC["🧬 freshclam"]
    MON --> PKG["πŸ”„ apt / dnf upgrade"]
    MON --> CS["🦠 clamscan"]

    CS -->|infected| Q["πŸ”’ quarantine dir"]
    CS -->|infected| AL["πŸ“£ ALERT_COMMAND"]

    MON --> SJ["πŸ“„ status.json"]
    SJ --> DASH["πŸ“Š security-monitor status"]

    MGR -.->|repairs| FC
    MGR -.->|re-enables| timers

    CONF -.-> MON
    CONF -.-> MGR
    CONF -.-> DASH
Loading

A single scan runs three steps, then persists a result the dashboard can read:

sequenceDiagram
    autonumber
    participant T as ⏰ scan.timer
    participant M as πŸ›‘οΈ security-monitor
    participant C as 🦠 ClamAV
    participant A as πŸ“£ ALERT_COMMAND

    T->>M: scan full
    M->>C: freshclam (service paused)
    M->>M: apt/dnf upgrade, count applied + remaining
    M->>C: clamscan -r -i --move=quarantine
    C-->>M: exit 0 clean / 1 infected / 2+ error
    alt infected files found
        M->>A: subject + findings on stdin
    end
    M->>M: write status.json, prune old scan logs
Loading

πŸ“‹ Prerequisites

Requirement Notes
Linux + systemd Timers and services are managed with systemctl; install refuses to run without it
Bash 4.0+ Both scripts are pure Bash
Root access install, uninstall, health, and scan need root. status does not
Internet access To download ClamAV packages and virus definitions

Supported distributions

βœ… Ubuntu / Debian (apt, unattended-upgrades) β€” βœ… Amazon Linux 2023 (dnf, dnf-automatic)

install refuses anything else with Unsupported operating system. The scan and dashboard code also recognises rhel/centos/fedora for service and package-manager naming, but those are untested and the installer won't set them up.


πŸš€ Quick Start

git clone https://github.com/CaputoDavide93/EC2-Linux-Security-Monitor.git
cd EC2-Linux-Security-Monitor
chmod +x security-monitor.sh security-manager.sh
sudo ./security-manager.sh install

The installer runs nine steps: package lists, ClamAV + jq + curl + auto-update tooling, ClamAV configuration, unattended updates, the config file, logrotate, both scripts into /usr/local/bin, the systemd timers, and the shell shortcuts.

Then reload your shell to pick up the shortcuts:

source /etc/profile.d/security-monitor.sh

Run your first scan and view the dashboard:

sudo security-monitor scan     # quick scan
security-monitor status        # dashboard β€” no sudo needed

Upgrading from v2.x? install removes the old /etc/cron.d/security-monitor and replaces it with systemd timers. Your existing config is never overwritten.


βš™οΈ Configuration

Everything lives in /etc/security-monitor/security-monitor.conf (installed from security-monitor.conf, and never overwritten once present). It is sourced by both scripts, so a value set here changes behaviour and what the dashboard reports.

Variable Purpose Default
SECURITY_DIR Runtime data β€” status.json, quarantine /var/lib/security-monitor
LOG_DIR Log destination /var/log/security-monitor
QUARANTINE_DIR Where infected files are moved $SECURITY_DIR/quarantine
QUARANTINE_ENABLED yes moves infected files, no only reports them yes
ALERT_COMMAND Shell command fed the alert on stdin; empty disables alerting (empty)
SCAN_SCHEDULE OnCalendar for the scan timer *-*-* 02:00:00
HEALTH_SCHEDULE OnCalendar for the health timer *-*-* 00/6:00:00
SCAN_MODE Mode the scheduled scan uses β€” quick or full full
QUICK_SCAN_PATHS Paths for a quick scan /home /root
FULL_SCAN_PATHS Paths for a full scan /home /root /opt /tmp /var /usr/local
DB_MAX_AGE_DAYS Definitions older than this are stale 7
SCAN_MAX_AGE_HOURS Scans older than this are overdue 48
LOG_RETENTION_DAYS Per-scan logs older than this are deleted after each scan 30

After changing a *_SCHEDULE or SCAN_MODE, re-run sudo security-manager install to rewrite the timer units. Every other value takes effect on the next scan.

πŸ“£ Alerting examples

ALERT_COMMAND receives the subject line and the matching clamscan output on stdin. It runs only when a scan finds infected files.

# Local mail
ALERT_COMMAND="mail -s 'ClamAV alert' root"

# Amazon SNS
ALERT_COMMAND="aws sns publish --topic-arn arn:aws:sns:eu-west-1:123456789012:alerts --message \"\$(cat)\""

# Generic webhook
ALERT_COMMAND="curl -sS -X POST -H 'Content-Type: text/plain' --data-binary @- https://example.com/hook"

Verify the plumbing without real malware, using the EICAR test file:

printf 'X5O!P%%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /root/eicar.txt
sudo security-monitor scan
πŸ”’ Working with quarantined files

Infected files are moved, not deleted, so a false positive is always recoverable:

sudo ls -l /var/lib/security-monitor/quarantine     # what was caught
sudo mv /var/lib/security-monitor/quarantine/FILE /original/path   # restore
sudo rm /var/lib/security-monitor/quarantine/FILE                 # destroy

The directory is 0700 and root-owned, and is excluded from subsequent scans so the same file is never re-reported. Set QUARANTINE_ENABLED="no" to report without moving anything β€” safer for hosts where an application might depend on a flagged file.

uninstall deletes the data directory, and warns first if anything is still quarantined.


πŸ“– Usage

security-monitor

Usage: security-monitor [scan [quick|full]|status|version]

  scan [quick|full]   Run a security scan (default: quick, needs root)
  status              Show the status dashboard (default, no root needed)
  version             Print version
Mode Paths Extra limits Typical duration
quick (default) $QUICK_SCAN_PATHS max filesize 50M, scansize 100M, recursion 5 30–90 seconds
full $FULL_SCAN_PATHS none 10–30 minutes

Both modes exclude /sys, /proc, /dev, the quarantine directory, .git, node_modules, and .cache.

The status dashboard reports scan status and freshness, a 5-point compliance score, pending and applied updates, ClamAV and timer state, and the signature database version, signature count, and age. Every figure comes from the live system or the last scan β€” there are no placeholder values.

security-manager

Usage: security-manager [install|uninstall|health|version]

  install     Install the security monitoring system
  uninstall   Remove the security monitoring system
  health      Perform a health check
  version     Print version

Run without arguments for an interactive menu.

health checks β€” and where it can, repairs β€” the freshclam service, the ClamAV daemon, signature age (re-downloads past DB_MAX_AGE_DAYS), both systemd timers, and the installed scripts, config, and shell shortcuts. It exits after reporting how many checks needed attention.

uninstall removes the timers and units, the legacy cron file, both scripts, the logrotate config, shell shortcuts, config, data, and logs. ClamAV packages stay installed β€” remove them with apt-get remove --purge 'clamav*' or dnf remove 'clamav*'.

Scan results

$SECURITY_DIR/status.json (mode 0640) holds the last result. Counts are JSON numbers:

{
  "last_scan": "2026-08-26T02:00:11+00:00",
  "scan_mode": "full",
  "scan_status": "clean",
  "infected_files": 0,
  "scanned_files": 18432,
  "quarantined_files": 0,
  "updates_available": 0,
  "updates_applied": 12
}

scan_status is clean, attention (infected files found), or error (clamscan failed to run β€” exit code 2 or above).


⏰ Automated Monitoring

install creates and enables two timers:

Unit Schedule Runs
security-monitor-scan.timer SCAN_SCHEDULE (02:00 daily) security-monitor scan $SCAN_MODE
security-monitor-health.timer HEALTH_SCHEDULE (every 6 h) security-manager health

Both use Persistent=true, so a run missed while the instance was stopped happens on next boot. The scan service runs at Nice=10 and IOSchedulingClass=idle to stay off the critical path on small instances, and the scan timer adds RandomizedDelaySec=15m so a fleet doesn't scan in lockstep.

systemctl list-timers 'security-monitor-*'     # when they next fire
journalctl -u security-monitor-scan.service    # what the last scan did
sudo systemctl start security-monitor-scan     # run one now, out of band

Change the schedule in the config file, then re-run sudo security-manager install. Editing the unit files directly works too, but install will overwrite them.


πŸ“ Repo structure

EC2-Linux-Security-Monitor/
β”œβ”€β”€ .github/workflows/
β”‚   └── lint.yml              # πŸ§ͺ shellcheck + bash -n + OnCalendar validation
β”œβ”€β”€ security-monitor.sh       # πŸ›‘οΈ scanning, quarantine, alerting, dashboard
β”œβ”€β”€ security-manager.sh       # πŸ”§ install, uninstall, health check
β”œβ”€β”€ security-monitor.conf     # βš™οΈ default config, installed to /etc/security-monitor/
β”œβ”€β”€ CONTRIBUTING.md           # 🀝 how to contribute
β”œβ”€β”€ SECURITY.md               # πŸ”’ vulnerability reporting
└── LICENSE                   # πŸ“„ MIT

πŸ§ͺ Testing

There is no automated test suite. CI (lint.yml) lints both scripts, checks syntax, and validates the config and timer schedules on every push and PR:

shellcheck --severity=warning security-monitor.sh security-manager.sh

See CONTRIBUTING.md for the full local check list.


πŸ› οΈ Troubleshooting

⚠ "Freshclam had issues (may be in cooldown)"

ClamAV rate-limits definition downloads. The scan continues with the current database and freshclam retries automatically:

sudo tail /var/log/clamav/freshclam.log
❌ Dashboard says "No scan data available"

The dashboard reads $SECURITY_DIR/status.json, written by the first scan, and needs jq (installed by install):

sudo security-monitor scan
⚠ Dashboard shows "Scan Timer: βœ— Not active"

The health check re-enables stopped timers, or do it by hand:

sudo security-manager health
systemctl list-timers 'security-monitor-*'
sudo systemctl enable --now security-monitor-scan.timer
⚠ Compliance is below 100%

The score is five equally weighted checks, and the dashboard lists exactly which ones failed: no infected files, scan timer active, a scan within SCAN_MAX_AGE_HOURS, definitions within DB_MAX_AGE_DAYS, and automatic updates enabled. Fix the listed item, or adjust the threshold in the config file if it doesn't suit the host.

❌ "Unsupported operating system"

install supports Ubuntu, Debian, and Amazon Linux only. Elsewhere the package and service names differ, so it refuses rather than guessing.


πŸ”’ Security

This tool runs as root, applies package updates unattended, and can move files into quarantine. Review both scripts before installing them on anything you care about. See SECURITY.md for vulnerability reporting and what the tool touches.


🀝 Contributing

Contributions are welcome β€” see CONTRIBUTING.md for guidelines.


πŸ“„ License

MIT β€” see LICENSE.


⭐ If this tool helped you, please give it a star! ⭐ · Made with ❀️ by Davide Caputo

About

πŸ›‘οΈ Automated Linux security monitoring with ClamAV antivirus, auto-updates, and beautiful status dashboard. Ubuntu & Amazon Linux.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages