Linux杀毒软件ClamAV+LMD部署流程.md

Anolis 8.9 上部署 ClamAV + Linux Malware Detect(LMD)实践文档

1. 适用场景

本文适用于:

  • 操作系统:Anolis OS 8.9
  • 部署形态:宿主机 + Docker 容器
  • 目标:在宿主机上部署 ClamAV + LMD,完成基础恶意文件检测、定时巡检、可选的高风险目录监控

2. 原理说明

2.1 ClamAV 的作用

ClamAV 是开源杀毒引擎,主要负责:

  • 病毒库更新(freshclam
  • 常驻扫描服务(clamd
  • 按需扫描(clamscan / clamdscan

其中:

  • freshclam:负责更新病毒库
  • clamd:常驻服务,启动后驻留内存,提供 socket 给客户端调用
  • clamdscan:通过 socket 调用 clamd,速度快,适合和 LMD 配合

2.2 LMD 的作用

Linux Malware Detect(LMD / maldet)更偏向 Linux 服务器场景,主要负责:

  • 面向 Linux/Web 场景的恶意文件识别
  • 定时扫描
  • 基于 inotify 的监控
  • 报告、告警、隔离、恢复
  • 调用 ClamAV 引擎提升扫描效率与覆盖面

2.3 为什么 Docker 宿主机应优先扫持久化目录

Docker 容器里的数据大致分三类:

  1. 容器可写层(临时性强)
  2. bind mount(宿主机真实目录)
  3. named volume(宿主机上的 volume 挂载点)

对于宿主机杀毒来说,最值得扫的是 bind mount 源目录和实际在用的 volume Mountpoint,因为这些路径:

  • 会长期保留
  • 会被容器持续读写
  • 容器删除后通常仍然存在

相比之下,overlay2 等 Docker 内部层通常不是日常重点扫描对象。


3. 安装方案总览

3.1 推荐方案:系统仓库 / yum(dnf)

适合:

  • 能访问仓库
  • 希望维护简单
  • 按 EL8 兼容方式安装

3.4 非 yum 方案:LMD 官方 tarball 安装

适合:

  • 官方推荐安装方式
  • 系统仓库通常不提供最新 maldet

4. 安装 ClamAV(yum / dnf 方案)

4.1 直接使用系统仓库安装

sudo dnf makecache
sudo dnf install -y clamav clamav-freshclam clamd clamav-filesystem

4.2 如果系统仓库缺包,使用 EPEL

sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
sudo dnf --enablerepo=epel install -y clamav clamav-freshclam clamd clamav-filesystem

4.3 检查安装结果

rpm -ql clamav-freshclam | grep freshclam.conf
rpm -ql clamd | grep -E 'clamd|service'
rpm -ql clamav-filesystem | grep scan.conf
systemctl list-unit-files 'clam*'

正常情况下会看到:

  • /etc/freshclam.conf
  • /etc/clamd.d/scan.conf
  • /usr/lib/systemd/system/clamd@.service

5. 配置 freshclam

编辑 /etc/freshclam.conf

UpdateLogFile /var/log/freshclam.log
LogTime yes
LogRotate yes
DatabaseOwner clamupdate
DatabaseMirror database.clamav.net
NotifyClamd /etc/clamd.d/scan.conf

创建日志文件:

touch /var/log/freshclam.log
chown clamupdate:clamupdate /var/log/freshclam.log

更新病毒库并启动服务:

freshclam
systemctl enable --now clamav-freshclam.service

检查:

cat /etc/freshclam.conf | grep -v '^#' | grep -v '^$'

6. 配置并启动 clamd

6.1 恢复标准配置

如果 /etc/clamd.d/scan.conf 被误改,可以直接从文档目录恢复:

cp -f /usr/share/doc/clamd/clamd.conf /etc/clamd.d/scan.conf

6.2 推荐最小可用配置

/etc/clamd.d/scan.conf 中至少保留以下关键项:

LogTime yes
LogSyslog yes
PidFile /run/clamd.scan/clamd.pid
DatabaseDirectory /var/lib/clamav
LocalSocket /run/clamd.scan/clamd.sock
LocalSocketMode 660
FixStaleSocket yes
User clamscan

不建议在 clamd@scan.service 这个 systemd unit 场景下保留 Foreground yes,因为该 unit 的类型是 Type=forking,与前台运行模式不匹配,可能导致服务一直停留在 activating

6.3 启动服务

systemctl enable --now clamd@scan.service
systemctl status clamd@scan.service

6.4 验证

clamdscan /etc/hosts

正常应返回:

/etc/hosts: OK

7. 安装 LMD(官方 tarball 方案)

cd /usr/local/src
wget https://www.rfxn.com/downloads/maldetect-current.tar.gz
wget https://www.rfxn.com/downloads/maldetect-current.tar.gz.md5
md5sum -c maldetect-current.tar.gz.md5

tar xzf maldetect-current.tar.gz
cd maldetect-*
./install.sh

更新签名:

maldet -u

8. LMD 配置

编辑 /usr/local/maldetect/conf.maldet,建议项如下:

scan_clamscan="1"
scan_ignore_root="0"
scan_yara="1"

quarantine_hits="0"
quarantine_clean="0"
quarantine_suspend_user="0"

cron_daily_scan="1"


autoupdate_signatures="1"
autoupdate_version="1"

配置含义

  • scan_clamscan="1":让 LMD 优先调用 ClamAV
  • scan_ignore_root="0":不跳过 root 拥有的文件,适合 Docker 宿主机
  • quarantine_hits="0":全局默认不自动隔离,避免误伤业务数据目录
  • scan_days="2":daily cron 只扫最近 2 天改动文件

9. Docker 宿主机目录规划建议

假设宿主机当前运行容器主要使用以下 bind mount:

/data/soft/openvpn-as/openvpn-data
/home/data/taiyuan/nacos2.2.3/data
/home/data/taiyuan/rabbitmq
/home/data/taiyuan/es-2/config
/home/data/taiyuan/es-2/data
/home/data/taiyuan/es-2/logs
/home/data/taiyuan/redis7.0.2/conf
/home/data/taiyuan/redis7.0.2/data
/home/data/taiyuan/redis7.0.2/logs
/home/data/taiyuan/redis6.2.13/conf
/home/data/taiyuan/redis6.2.13/data
/home/data/taiyuan/redis6.2.13/logs

9.1 推荐纳入每日扫描的目录

适合每日扫描的通常是:

  • 配置目录
  • 证书目录
  • 脚本目录
  • 上传目录
  • /tmp/var/tmp/dev/shm

如果 Docker 使用的是文件级 bind mount,例如:

  • /data/soft/openvpn/pki/ca.crt
  • /data/soft/openvpn/pki/server.key
  • /data/soft/nginx/conf.d/default.conf
  • /data/soft/app/scripts/entrypoint.sh

更推荐在扫描配置里直接写它们的父目录,而不是只写单个文件,例如:

  • /data/soft/openvpn/pki
  • /data/soft/nginx/conf.d
  • /data/soft/app/scripts

这样做的原因是:

  • 仅扫描当前单个文件,无法覆盖后续新上传或新生成的文件
  • 提升到父目录后,目录中新出现的恶意文件也能被每日扫描纳入

当前脚本已经按这个思路处理 pkiconfigconf.dscriptscertslogs 等常见文件级挂载。

放进/usr/local/maldetect/cron/custom.cron,写成真实执行命令

/tmp
/var/tmp
/dev/shm
/data/soft/openvpn-as/openvpn-data
/home/data/taiyuan/nacos2.2.3/data
/home/data/taiyuan/es-2/config
/home/data/taiyuan/redis7.0.2/conf
/home/data/taiyuan/redis6.2.13/conf

9.2 推荐低频扫描但不自动隔离的目录(weekly 数据目录)

推荐单独写一个脚本,然后放到 /etc/cron.weekly/,这里用 -a 全量扫,比 -r 更适合低频离峰体检。

当前脚本对 weekly 数据目录的判断规则,已经统一为“同时检查容器挂载目标路径和宿主机源路径”,主要包括:

  • 通用数据目录关键字: datadata-dirdatadirdbdbdatadatabasedatabasespgdata
  • 备份/归档目录关键字: backupbackupsdumpdumpsarchivearchivessnapshotsnapshots
  • 持久化/状态目录关键字: storagestoreappendonlyappendonlydiraofrdbwalxlogjournaljournalsqueuequeues
  • 常见中间件数据路径: var/lib/mysqlvar/lib/mariadb var/lib/postgresqlvar/lib/pgsql var/lib/redis var/lib/rabbitmq var/lib/elasticsearch var/lib/nacos usr/share/elasticsearch/data bitnami/*/dataopt/bitnami/*/data usr/local/nacos/dataopt/nacos/datahome/nacos/data

这意味着像下面这些目录,都更适合放进 weekly:

  • MySQL / MariaDB:/var/lib/mysql/bitnami/mysql/data.../mysql-backup-compose/backup
  • PostgreSQL:/var/lib/postgresql/bitnami/postgresql/data.../postgresql-backup-compose/backup
  • Redis:/dataappendonlydir、AOF/RDB 所在目录
  • RabbitMQ:/var/lib/rabbitmq
  • Elasticsearch:/usr/share/elasticsearch/data
  • Nacos:/home/nacos/data/opt/nacos/data
#!/bin/bash
/usr/local/sbin/maldet -b -a /home/data/taiyuan/rabbitmq,/home/data/taiyuan/es-2/data,/home/data/taiyuan/redis7.0.2/data,/home/data/taiyuan/redis6.2.13/data
/home/data/taiyuan/rabbitmq
/home/data/taiyuan/es-2/data
/home/data/taiyuan/redis7.0.2/data
/home/data/taiyuan/redis6.2.13/data

9.3 默认不作为每日重点扫描的目录不需要配置(日志目录通常无需纳入)

/home/data/taiyuan/es-2/logs
/home/data/taiyuan/redis7.0.2/logs
/home/data/taiyuan/redis6.2.13/logs

10. custom.cron 的正确写法

/usr/local/maldetect/cron/custom.cron 不是单纯写目录列表的文件,而是会被 /etc/cron.daily/maldet 直接 source 的 shell 片段。因此,正确写法应当是:

  • 写实际执行的 maldet 命令
  • 不要只写路径列表
  • 建议后台执行,并加上最近变更时间范围

推荐写法(每次增量检查)

cat > /usr/local/maldetect/cron/custom.cron <<'EOF'
# 每日扫描最近 2 天变更的高价值目录
/usr/local/sbin/maldet -b -r /tmp,/var/tmp,/dev/shm,/data/soft/openvpn-as/openvpn-data,/home/data/taiyuan/nacos2.2.3/data,/home/data/taiyuan/es-2/config,/home/data/taiyuan/redis7.0.2/conf,/home/data/taiyuan/redis6.2.13/conf 2
EOF

为什么这样写

因为:

  • cron_daily_scan="1" 只是启用 LMD 的 daily 扫描逻辑
  • custom.cron 是给 daily cron 的钩子代码
  • 直接写路径不会自动变成扫描任务
  • 写成 maldet -b -r ... 2 才是“每日扫描最近 2 天内变更文件”的真实执行逻辑

如果你倾向于“每天全量扫这些目录”,也可以改为 -a

/usr/local/sbin/maldet -b -a /tmp,/var/tmp,/dev/shm,/data/soft/openvpn-as/openvpn-data,/home/data/taiyuan/nacos2.2.3/data,/home/data/taiyuan/es-2/config,/home/data/taiyuan/redis7.0.2/conf,/home/data/taiyuan/redis6.2.13/conf

但从性能和实用性上看,更推荐 -r ... 2 的增量式思路


11. ignore_paths 推荐写法

创建 /usr/local/maldetect/ignore_paths

cat > /usr/local/maldetect/ignore_paths <<'EOF'
/proc
/sys
/dev
/run
/data/soft/docker/overlay2
/data/soft/docker/containers
/data/soft/docker/image
/data/soft/docker/buildkit
EOF

说明

这些路径要么不是正常业务内容目录,要么是 Docker 内部实现层,通常不适合作为日常重点扫描对象。


12. 手工扫描命令

12.1 立即扫描高价值目录

maldet -a /tmp,/var/tmp,/dev/shm,/data/soft/openvpn-as/openvpn-data,/home/data/taiyuan/nacos2.2.3/data,/home/data/taiyuan/es-2/config,/home/data/taiyuan/redis7.0.2/conf,/home/data/taiyuan/redis6.2.13/conf

12.2 离峰扫描业务数据目录(后台)

maldet -b -a /home/data/taiyuan/rabbitmq,/home/data/taiyuan/es-2/data,/home/data/taiyuan/redis7.0.2/data,/home/data/taiyuan/redis6.2.13/data

12.3 查看扫描报告

maldet --report list
maldet --dump-report <SCANID>

13. 每周离峰扫描建议

这类 weekly 扫描更适合覆盖:

  • MySQL / PostgreSQL / MariaDB 的 data、backup、dump 目录
  • Redis 的 data、appendonlydir、AOF/RDB 所在目录
  • RabbitMQ 的数据目录
  • Elasticsearch / Nacos 等中间件状态目录

不建议把日志目录纳入 weekly,除非你有明确的取证或审计要求。

创建脚本:

cat > /usr/local/sbin/maldet-weekly-docker-data.sh <<'EOF'
#!/bin/bash
/usr/local/sbin/maldet -b -a /home/data/taiyuan/rabbitmq,/home/data/taiyuan/es-2/data,/home/data/taiyuan/redis7.0.2/data,/home/data/taiyuan/redis6.2.13/data
EOF

chmod +x /usr/local/sbin/maldet-weekly-docker-data.sh

创建 cron.weekly:

cat > /etc/cron.weekly/maldet-docker-data <<'EOF'
#!/bin/bash
/usr/local/sbin/maldet-weekly-docker-data.sh
EOF

chmod +x /etc/cron.weekly/maldet-docker-data

14. 非 yum 的其他解决方案

14.1 方案一:离线 RPM 安装

适合内网环境。

做法:

  1. 在可联网机器下载以下 RPM 及依赖:
    • clamav
    • clamav-freshclam
    • clamd
    • clamav-filesystem
  2. 传到 Anolis 8.9 服务器
  3. 使用以下命令安装:
rpm -Uvh *.rpm

或:

dnf localinstall -y *.rpm

14.3 方案二:ClamAV 源码编译

适合需要指定版本或仓库不可用时。

大致流程:

wget https://www.clamav.net/downloads/production/clamav-<version>.tar.gz
tar xzf clamav-<version>.tar.gz
cd clamav-<version>
mkdir build && cd build
cmake ..
make -j$(nproc)
make install

注意:

  • 源码编译后需要自己处理 systemd unit、配置文件、运行用户和日志目录

15. 验证清单

15.1 检查 ClamAV

systemctl status clamav-freshclam.service
systemctl status clamd@scan.service
clamdscan /etc/hosts

15.2 检查 LMD

maldet -u
maldet -e

15.3 检查 Docker 挂载

for c in $(docker ps -q); do
echo "===== $(docker inspect -f '{{.Name}}' $c) ====="
docker inspect -f '{{range .Mounts}}{{println .Type "|" .Source "|" .Destination "|" .RW}}{{end}}' $c
done

16. 最终建议

推荐组合

  • ClamAV:负责病毒库 + 常驻扫描引擎
  • LMD:负责 Linux 场景规则 + 定时扫描 + 可选监控

Docker 宿主机原则

  • 优先扫 bind mount 源目录
  • 谨慎对待业务数据目录的自动隔离
  • 不把 Docker 内部实现层当作日常重点扫描对象

当前最合适的策略

  • 每日扫描:高价值、低风险目录
  • 每周离峰:业务状态数据目录
  • 全局默认不自动隔离
  • 遇到明确可疑目录时再单独提升处置强度

滚动至顶部