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 容器里的数据大致分三类:
- 容器可写层(临时性强)
- bind mount(宿主机真实目录)
- 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 优先调用 ClamAVscan_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
这样做的原因是:
- 仅扫描当前单个文件,无法覆盖后续新上传或新生成的文件
- 提升到父目录后,目录中新出现的恶意文件也能被每日扫描纳入
当前脚本已经按这个思路处理 pki、config、conf.d、scripts、certs、logs 等常见文件级挂载。
放进/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 数据目录的判断规则,已经统一为“同时检查容器挂载目标路径和宿主机源路径”,主要包括:
- 通用数据目录关键字:
data、data-dir、datadir、db、dbdata、database、databases、pgdata - 备份/归档目录关键字:
backup、backups、dump、dumps、archive、archives、snapshot、snapshots - 持久化/状态目录关键字:
storage、store、appendonly、appendonlydir、aof、rdb、wal、xlog、journal、journals、queue、queues - 常见中间件数据路径:
var/lib/mysql、var/lib/mariadbvar/lib/postgresql、var/lib/pgsqlvar/lib/redisvar/lib/rabbitmqvar/lib/elasticsearchvar/lib/nacosusr/share/elasticsearch/databitnami/*/data、opt/bitnami/*/datausr/local/nacos/data、opt/nacos/data、home/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:
/data、appendonlydir、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 安装
适合内网环境。
做法:
- 在可联网机器下载以下 RPM 及依赖:
- clamav
- clamav-freshclam
- clamd
- clamav-filesystem
- 传到 Anolis 8.9 服务器
- 使用以下命令安装:
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 内部实现层当作日常重点扫描对象
当前最合适的策略
- 每日扫描:高价值、低风险目录
- 每周离峰:业务状态数据目录
- 全局默认不自动隔离
- 遇到明确可疑目录时再单独提升处置强度