Operational/how-to references updated to the role entry playbooks after the ADR-0001 migration. Historical incident narrative (dated callouts, commit refs) preserved. - clamav-fleet-deployment: override + re-run -> clamav.yml; role note - ssh-hardening-ansible-fleet: note this is now the ssh_hardening role - vps-migration-baseline-checklist: table -> clamav.yml / ssh_hardening.yml - ssh-socket-tailscale-race-condition: Affected Hosts + Prevention + References -> tailscale role tasks (network_wait/ssh_only_ubuntu/ssh_only_fedora) - freshclam-logwatch-false-no-updates: codify refs -> clamav role
4.7 KiB
| title | domain | category | tags | status | created | updated | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Logwatch Falsely Reports 'No freshclam updates' in ClamAV Daemon Mode | troubleshooting | security |
|
published | 2026-06-06 | 2026-06-06 |
Logwatch Falsely Reports "No freshclam updates" in ClamAV Daemon Mode
Logwatch's daily clam-update section emails:
No updates detected in the log for the freshclam daemon (the ClamAV update process). If the freshclam daemon is not running, you may need to restart it.
…even though freshclam is running and signatures are current. It's a parser quirk specific to running freshclam as a daemon. Don't act on the "restart it" suggestion — first confirm whether signatures are actually stale.
Seen on tttpod (2026-06-06). All four freshclam hosts (majorlinux, majortoot-hetzner, teelia, tttpod) hit this on quiet days.
First: is it real or false?
systemctl is-active clamav-freshclam # active?
ls -l /var/lib/clamav/daily.c[lv]d # mtime today/yesterday?
grep 'updated' /var/log/clamav/freshclam.log | tail # real download events
- Fresh
daily.cld+ active service → false positive (this page). daily.cldweeks old / service disabled → real. Re-enable freshclam and update (see Related). A daemonless box still needs freshclam enabled —clamav_use_daemon: falseonly disables the scanner daemon, not the updater.
Why It False-Alarms
logwatch's clam-update script (/usr/share/logwatch/scripts/services/clam-update) decides "updated" by counting ClamAV update process started lines ($UpdatedNum) within its range (Range = yesterday). It does not count the actual daily.cld updated (version: …) download lines.
freshclam emits "update process started" only when the daemon (re)starts — not on its periodic in-daemon checks (Checks 24, ExecStart=/usr/bin/freshclam -d). So on any day the box doesn't reboot or restart freshclam, yesterday's log has zero "started" lines → $UpdatedNum == 0 → the warning fires, regardless of whether signatures downloaded. (Conversely, on a day you do reboot, the warning won't fire.) The script was written for the old cron-driven freshclam, which started a fresh process each run.
Fix
Silence just that one message — real ERROR / WARNING / outdated alerts still report:
# /etc/logwatch/conf/services/clam-update.conf
$ignore_no_updates = 1
No service restart needed; logwatch picks it up on its next daily run. (The variable is read as $ENV{'ignore_no_updates'} by the script — note: not prefixed clam_update_, despite what the script's own self-help text suggests.)
Codify (Ansible)
Deploy the drop-in wherever freshclam runs in daemon mode. On the fleet it's a task in the clamav role (roles/clamav/tasks/install.yml, group clamav), right after freshclam is enabled — originally added in MajorAnsible commit cb27c93:
- name: Suppress logwatch clam-update false "no updates" alert (daemon-mode freshclam)
ansible.builtin.copy:
dest: /etc/logwatch/conf/services/clam-update.conf
mode: '0644'
content: |
$ignore_no_updates = 1
tags: [logwatch]
Key Notes
- Confirm freshness before suppressing. If signatures really are stale (freshclam off / no update timer), suppressing hides a genuine security gap. On a daemonless host that disabled freshclam, the warning is true.
- The script's built-in options B/C (about syslog format) don't apply when freshclam logs to its own file (
LogSyslog false);$ignore_no_updatesis the right lever. - Don't alert with
mail. Themail/mailxCLI is absent on most fleet hosts (only Postfix's/usr/sbin/sendmailis guaranteed). A health script that ends inmail -s … rootsilently fails to send. Pipe a headered message to/usr/sbin/sendmail -taddressed toadmin_emaildirectly (don't rely on an/etc/aliasesrootrewrite either).
Proactive monitoring (don't rely on logwatch for "is it updating?")
Since logwatch's heuristic is suppressed, a direct daily watchdog is what actually catches a dead freshclam. The clamav role deploys /etc/cron.daily/clamav-freshness (originally MajorAnsible 9d1a1a9) to every clamav-group host: it emails the admin (via sendmail) if clamav-freshclam is inactive or daily.cld is older than clamav_staleness_threshold_days (default 3) — and stays silent otherwise. Test without emailing:
CLAMAV_STALE_DAYS=0 /etc/cron.daily/clamav-freshness # forces the stale branch
This is what would have caught dcaprod's 20-day drift immediately instead of it surfacing by accident.