一、背景
计算机信息系统等级保护(俗称等保)的要求之一是应用服务器具有病毒防护手段,并定期升级病毒特征库。这个防护场景通常被称为Endpoint Detection and Response(EDR),也可简称终端防护。EDR一般是采用侵入性的防护方式。所谓侵入性意味着需要在EC2虚拟机内植入专门的Agent才可以进行安全防护。在亚马逊云科技上,可通过Marketplace方式订阅多个第三方厂家的EDR,也可以线下采购。
商用的EDR方案有完整的检测、识别、发现、预防、干预、强化、集中管控等一整套管理功能,不过相对带来的问题是成本较高。在一些非严格等保的场合,如果只是要求实现病毒扫描和防护能力,那么可使用本文介绍的ClamAV方案进行替代。
ClamAV是一个开源的引擎,用于检测病毒、木马、恶意软件和其他威胁。ClamAV支持Windows、Linux和MacOS等系统。Github官网在这里。ClamAV由Talos所有,后者又被Cisco收购,用于为Cisco供应威胁情报。ClamAV社区提供了免费的持续的病毒特征库升级。因此可实现一次部署,长期使用。
本文介绍如何在Amazon Linux 2操作系统上部署,其他系统如Ubuntu安装过程相仿请参考对应文档。
二、安装ClamAV并执行手工扫描
1、安装软件包
注意:ClamAV加载特征库和全盘扫描比较消耗CPU和内存资源,因此建议在不小于4GB内存的机型上安装部署。内存仅为1GB、2GB的机型运行速度可能较为缓慢,甚至出现部分时间假死的情况。
本文采用操作系统自带的软件源。执行如下命令安装。
yum update -y
amazon-linux-extras install epel
yum install clamav clamd -y
安装好的ClamAV有几个主要组成部分:
- clamscan:手工扫描程序
- clamdscan:依赖后台服务的扫描程序
- clamonacc:按需扫描程序(实时监控),对应配置文件
/etc/clamd.d/scan.conf
- clamd:按需扫描的后台进程,对应配置文件
/etc/clamd.d/scan.conf
- fleshclam:病毒库升级工具,对应配置文件
/etc/fleshclam.conf
- clamconf:配置文件生成工具
2、手工更新病毒库
首次安装后,必须先下载病毒库。执行如下命令更新病毒库:
freshclam
返回结果如下表示升级成功:
ClamAV update process started at Sat Dec 3 14:15:51 2022
daily database available for download (remote version: 26739)
Time: 0.7s, ETA: 0.0s [========================>] 57.54MiB/57.54MiB
Testing database: '/usr/local/share/clamav/tmp.645c56b964/clamav-293585c0119a1f028368c597169d1634.tmp-daily.cvd' ...
Database test passed.
daily.cvd updated (version: 26739, sigs: 2013388, f-level: 90, builder: raynman)
main database available for download (remote version: 62)
Time: 0.6s, ETA: 0.0s [========================>] 162.58MiB/162.58MiB
Testing database: '/usr/local/share/clamav/tmp.645c56b964/clamav-e66a7c48ee3b6ac03f488235d68bf206.tmp-main.cvd' ...
Database test passed.
main.cvd updated (version: 62, sigs: 6647427, f-level: 90, builder: sigmgr)
bytecode database available for download (remote version: 333)
Time: 0.0s, ETA: 0.0s [========================>] 286.79KiB/286.79KiB
Testing database: '/usr/local/share/clamav/tmp.645c56b964/clamav-12719bf9f9650a8a8000cad457a59542.tmp-bytecode.cvd' ...
Database test passed.
bytecode.cvd updated (version: 333, sigs: 92, f-level: 63, builder: awillia2)
设置后台自动升级病毒库:
systemctl start clamav-freshclam
systemctl enable clamav-freshclam
默认的升级频率是每2小时升级1次,折合每天12次。如果需要调整,可以编辑如下配置文件/etc/freshclam.conf
,找到其中的如下一段,把数值改为1:
# Number of database checks per day.
# Default: 12 (every two hours)
Checks 1
重启服务,即可将升级频率设置为每天升级1次。
3、手工扫描特定文件夹
手工对某一个目录执行扫描。执行如下命令:
clamscan -r -i /
其中-r
参数表示扫描子目录,-i
参数表示只输出疑似病毒扫描结果。在启动后,首先ClamAV会验证特征库的签名,然后执行扫描。对根目录扫描的时间会很长,可能长达数分钟。
返回如下结果表示扫描完成。
----------- SCAN SUMMARY -----------
Known viruses: 8645335
Engine version: 1.0.0
Scanned directories: 4801
Scanned files: 43128
Infected files: 0
Data scanned: 1770.53 MB
Data read: 1315.73 MB (ratio 1.35:1)
Time: 420.401 sec (7 m 0 s)
Start Date: 2022:12:03 15:23:33
End Date: 2022:12:03 15:30:33
三、开启实时检测和定期检测
ClamAV在Linux系统上支持实时检测,也就是对当前系统读取和写入的文件进行检测,被称为on-access scanning
。
1、修改配置文件
实时检测需要启动clamd服务。这个服务的配置文件根据不同安装方式,可能配置文件路径和文件名不一样。本文使用的Amazon Linux 2的epel源安装后,配置文件是/etc/clamd.d/scan.conf
。这其中要修改监听管道、启动用户等多处配置。
编辑/etc/clamd.d/scan.conf
,修改如下的几个参数(排名和顺序可能所有不同,不影响效果)。
# Path to a local socket file the daemon will listen on.
# Default: disabled (must be specified by a user)
LocalSocket /tmp/clamd.socket
# Sets the group ownership on the unix socket.
# Default: disabled (the primary group of the user running clamd)
LocalSocketGroup clamscan
# Sets the permissions on the unix socket to the specified mode.
# Default: disabled (socket is world accessible)
LocalSocketMode 660
# Modifies fanotify blocking behaviour when handling permission events.
# If off, fanotify will only notify if the file scanned is a virus,
# and not perform any blocking.
# Default: no
OnAccessPrevention yes
# This option allows exclusions via user names when using the on-access
# scanning client. It can be used multiple times.
# It has the same potential race condition limitations of the
# OnAccessExcludeUID option.
# Default: disabled
OnAccessExcludeUname clamscan
# Set the include paths (all files inside them will be scanned). You can have
# multiple OnAccessIncludePath directives but each directory must be added
# in a separate line.
# Default: disabled
OnAccessIncludePath /home
# Uncomment this option to enable logging.
# LogFile must be writable for the user running daemon.
# A full path is required.
# Default: disabled
LogFile /var/log/clamd.scan
# Maximum size of the log file.
# Value of 0 disables the limit.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers. If LogFileMaxSize is enabled, log
# rotation (the LogRotate option) will always be enabled.
# Default: 1M
LogFileMaxSize 20M
# Log time with each message.
# Default: no
LogTime yes
名为LocalSocket的参数的是服务监听参数。启动有localsocket和网络监听两种模式,可独立使用,也可以同时使用。对于EC2的本机扫描而言,适用Unix管道的localsocket模式即可。
名为OnAccess的参数是实时扫描相关,分别表示:打开实时防护并拦截有风险的访问;设置要执行实施监控的路径(不建议对/
根路径监控,建议只监控应用路径,本文以/home
为例);实时检测要排除的用户名。由于clamd不能以root身份运行,而需要以普通用户身份运行,在本文使用操作系统安装源时候,会自动创建名为clamscan
的新用户,然后以这个身份运行。因此在配置文件中,这里需要设置一个与clamd服务启动的用户名保持一致,否则会发生自己触发扫描自己的递归调用,造成不必要的资源消耗。
名为Log相关的参数是日志路径和日志大小配置。在刚安装好的配置文件中,默认配置LogSyslog yes
这个参数的生效,因此扫描到的病毒结果会输出到系统日志中。本文为了便于查询,额外又设置了如上配置文件中的日志地址/var/log/clamd.scan
并且配置了最大体积为20MB。
都修改完毕后,保存退出。
执行如下命令创建日志文件:
touch /var/log/clamd.scan
chown clamscan:clamscan /var/log/clamd.scan
2、启动clamd和clamonacc后台服务
以root身份执行如下命令启动clamd
服务:
systemctl start clamd@scan
systemctl enable clamd@scan
systemctl start clamonacc
systemctl enable clamonacc
为了验证实时监控在运行,可执行clamdtop
命令查看后台进程。显示结果类似如下:
__ ____
_____/ /___ _____ ___ ____/ / /_____ ____
/ ___/ / __ `/ __ `__ \/ __ / __/ __ \/ __ \
/ /__/ / /_/ / / / / / / /_/ / /_/ /_/ / /_/ /
\___/_/\__,_/_/ /_/ /_/\__,_/\__/\____/ .___/
/_/
Connecting to: /run/clamd.scan/clamd.sock
然后即可进入类似Top命令的资源占用查看界面,即可证明clamd
服务启动正常。
3、验证实时防护
为了验证实时防护的有效性,需要模拟一个病毒特征来触发告警。在云上请勿使用真实病毒来测试您的网络安全,如用真实病毒测试,可能会触发对外部网络的扫描等恶意行为,将导致您的云账号被投诉和甚至关停。因此这里引入一个测试特征码来测试。欧洲计算机防病毒研究所 (EICAR) 开发了一种测试特征码,他是一个惰性的文本文件,也就是一串字符串,并且不包含任何程序代码无法被执行。这个特征码包含在多数防病毒的特征中可以被识别出来。这里将它写入一个文本文件eicar.virus
。由于前文配置Clamd后台进程是监控的/home
目录,这里需要与之匹配,所以将这个病毒特征文件放到/home
目录下。如果放在其他目录下则没有办法被扫描到。执行如下命令即可生成特征码。
cat > /home/eicar.virus <<'EOF'
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
EOF
现在以普通ec2-user用户的身份调用访问这个文件cat /home/eicar.virus
,此时将会触发实时防护,访问将被拦截。此时的ec2-user用户的console上会有如下提示:
cat: eicar.virus: Operation not permitted
在操作系统日志/var/log/message
中可看到实时防护的结果提示:
Dec 15 15:36:20 ip-172-31-29-112 clamd[2157]: /home/eicar.virus: Eicar-Signature FOUND
在配置文件中指定的日志文件/var/log/clamd.scan
内,也可以看到:
Thu Dec 15 15:42:03 2022 -> /home/eicar.virus: Eicar-Signature FOUND
4、查看历史日志过滤结果
执行如下命令即可过滤结果只发现的病毒:
grep FOUND /var/log/clamd.scan
返回结果如下:
Thu Dec 15 15:42:03 2022 -> /home/eicar.virus: Eicar-Signature FOUND
Fri Dec 16 03:50:11 2022 -> /home/eicar.virus: Eicar-Signature FOUND
Wed Dec 21 10:33:07 2022 -> /home/eicar.virus: Eicar-Signature FOUND
5、设置定期扫描的计划任务
除了实时检测外,实现病毒防护另一个主要途径是定期进行全盘扫描,例如每晚对整个磁盘进行100%的手工扫描。这个步骤可以通过计划任务进行。
新建计划任务配置文件/etc/cron.daily/fullscan
,添加如下:
#!/bin/sh
/bin/clamscan -r / -i -l /var/log/clamd.scan
以上命令中,-r /
表示对本机根目录上所有文件、文件夹和子文件夹进行递归的扫描,-i
表示只输出受影响的文件,-l /var/log/clamd.scan
表示将扫描日志写入到特定文件中,下文将配置集中的日志上报。
然后将这个文件设置为可执行权限。
chmod +x /etc/cron.daily/fullscan
这样即可完成每日全盘扫描,并将日志输出到特定文件。
四、集中上报扫描结果
不管是手工发起的扫描,还是按需扫描(On-access scanning),其扫描结果都会写入/etc/clamd.d/scan.conf
配置文件中指定的日志/var/log/clamd.scan
。因此这意味着,只要对这个日志进行监控即可满足集中上报的需求。
1、安装CloudWatch Agent
这里以Amazon Linux 2系统为例,安装Cloudwatch Log Agent进行日志采集。Cloudwatch Log Agent的新一代被称为Unified Agent
,前一代被称为Previously Agent
。这两个版本的说明文档都在本文末尾的参考链接中。本文使用前一代Previously Agent
进行配置。执行如下命令安装:
yum update -y
yum install -y awslogs
安装成功。
2、确保EC2有CloudWatch写入日志的权限
从EC2向CloudWatch上传日志需要AWS API操作权限。常见的方法有两种,1是安装AWSCLI并设置正确的密钥;2是通过EC2 IAM Profile的方式为EC2挂载对应权限。本文采用方法2。具体如何给EC2挂载IAM Profile可以参考这篇使用Session Manager登录EC2的文档。
确定了当前EC2在使用的IAM Profile后,为当前这个IAM Role再增加一个新的policy,名为:
CloudWatchAgentServerPolicy
这个IAM Policy是AWS内置的托管Policy,所有AWS账号内都默认带有这个Policy。这个Policy赋予EC2创建日志组(CreateLogGroup)、创建日志流(CreateLogStream)和写入日志(PutLogEvents)的权限。
如果EC2之前已经具有了IAM Profile,那么挂载好的新的Policy后等待数秒钟,不需要重启EC2即可生效。如果之前EC2没有挂载过IAM Profile,那么完成挂载后可能要等待几分钟,如果长时间没有生效,可重启下EC2以确保新的IAM Profile立刻生效。
3、注释掉默认采集的系统日志以节约日志存储成本
按照前文通过yum方式安装的配置文件路径在/etc/awslogs/awslogs.conf
。编辑这个配置文件。在这个配置文件的末尾已经有一段预设的参数负责上传/var/log/messages
的日志。这一段建议都注释掉,减少从EC2上传的日志的体积,然后手工配置需要上传的ClamAV的扫描日志。
如下一段是建议注释掉的日志。
[/var/log/messages]
datetime_format = %b %d %H:%M:%S
file = /var/log/messages
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/messages
4、新加入ClamAV日志的配置段
前文配置中已经有生成日志/var/log/clamd.scan
,因此可分析这个日志文件的输出格式,然后编写有针对性的如下一段:
[clamav]
log_group_name = clamav
log_stream_name = {instance_id}
initial_position = start_of_file
datetime_format = %a %b %d %H:%M:%S %Y
file = /var/log/clamd.scan
buffer_duration = 5000
将以上这一段配置文件加入配置文件/etc/awslogs/awslogs.conf
的末尾,保存后继续下一步。
5、设置上报的Region然后启动服务
编辑配置文件/etc/awslogs/awscli.conf
,修改默认region设置。如果不修改,默认会上传日志到us-east-1
区域。因此需要改成应用所在的区域,例如本文是新加坡区域(ap-southeast-1)。
[plugins]
cwlogs = cwlogs
[default]
region = ap-southeast-1
配置文件调整好后,启动服务。
systemctl start awslogsd
systemctl enable awslogsd
6、通过CloudWatch日志组查看日志
进入CloudWatch Log Groups日志组界面,找到日志组的名称,按照上一步配置文件中名称是clamav
。如下截图。

进入日志组后,如果有多个EC2都安装了CloudWatch Log Agent,那么这里会出现多个Log Streams,每一个的名字就是EC2的ID。
点击其中一台EC2的名称,向下滚动即可看到最新的日志。如下截图。

日志集中采集配置成功后,就可以进一步去配置统一告警。
注意:同一个病毒文件被多次访问,在日志中会形成多条FOUND记录,也会触发多个告警。
五、设置CloudWatch Log Groups发现病毒后的集中告警
CloudWatch Log Groups可以采集多个EC2的日志,对多个EC2的病毒扫描结果可以过滤关键字来触发告警。
本阶段配置,如果觉得跟上操作有难度,可观看这个视频。
1、设置CloudWatch Log Groups Metrics
进入CloudWatch的Log Groups日志组界面,点击第二个标签页Metric filters
,点击右侧按钮Create metric filter
创建新的过滤器。如下截图。

在弹出的向导第一步,输入新建特征的关键字。这里在Filter pattern
对话框内输入FOUND
,注意是英文的全大写,与日志中找到病毒时候提示的关键信息一致。然后在Test pattern
位置,从下拉框中选择当前已经有的几个EC2节点之一作为测试。选中节点ID名称后,下方的Log event message
将自动带出来前一步配置的从EC2集中提取的/var/log/clamd.scan
日志文件。这时候按下Test pattern
按钮,在下方的Show test results
部分也会打出来验证关键字的结果。通过测试可以看到,发现病毒后日志的关键字是FOUND
。现在点击屏幕右下角的按钮Next
进入下一步配置。如下截图。

在向导的第二步,设置Metric的名称,在页面上方Filter name
的位置输入ClamAV
,在下方Metric namespace
的位置输入clamav/found
,在Metric name
的位置输入在VIRUSFOUND
。然后向下滚动页面。如下截图。

将页面向下滚动后,继续输入信息。在Metric value
位置输入值是1
,表示每次遇到FOUND
关键字则统计值加1。在Default value
位置输入默认值0
,在Unit
单位的下拉框中选择计数单位是 Count
。然后点击右下角的Next
按钮继续。如下截图。

在向导的最后一步,点击Create metric filter
按钮完成创建。如一下截图。

创建Metric完成。点击名字即可跳转到CloudWatch Metric界面查看详情。如下截图。

点击Metrics可加载数据。如下截图。

点击第一个标签页浏览Browse
,然后从下方选择自定义的名称VIRUSFOUND
,然后再点击第三个标签页Graphed metrics
。如下截图。

进入第三个标签页Graphed metrics
后,从下方找到统计Statistic
列,点击下拉框,将页面上默认的average
平均值改为Sum
求和。如下截图。

对于一个新创建的Metric,可能只有一个数据点显示为0,因为缺少历史数据而不是特别直观。当运行了一段时间后,如果不定期的间隔发现了病毒,其显示效果如下截图。

上图的阅读方法是:在FOUND
指标不为零的时间点即表示发现了病毒。基于这样的统计数据,就可以进一步定义告警了。为了后续查询方便起见,当前浏览器地址栏的全路径可以被加入到收藏夹,便于以后查询。
2、创建Alarm告警
创建告警的发起界面从CloudWatch Log Groups的界面,点击第二个标签页Metric filters
,点击选中之前步骤新建的metric,然后点击右上角的Create alarm
。如下截图。

在创建告警向导的第一步,在Metric name
位置系统自动带出了之前输入的VIRUSFOUND
名称,在Statistic
位置自动带出了Sum
表示求和,在Period
位置自动带出了选项5 minutes
五分钟内。确认这些选项正确,然后向下滚动页面继续。如下截图。

在创建向导的下半部分,选择Threshold type
是Static
静态,选择值是Greater
表示大于,选择than
的数字是0
。由此表示,只要此值大于0,就意味着发现了病毒,然后发出告警。点击下一步继续。如下截图。

在配置告警向导的第二步,选择Alarm state trigger
是In alarm
,选择通过SNS Topic的方式是Create new topic
新建一个SNS Topic。在下方Create a new topic
的位置输入新的SNS Topic名字clamavfound
(注意不要有空格),然后下方输入要订阅这个Topic的邮箱用于接收告警。输入完成后,点击Create topic
按钮创建SNS Topic。如下截图。

点击创建SNS Topic后,页面上的显示信息会发生变化,这里会自动刷新加载出来刚创建的SNS Topic并显示刚才订阅SNS的邮箱。接下来继续将页面向下滚动,跳过本页上其他配置,点击下一步。如下截图。

在向导第三步,输入告警的名称,输入友好显示信息。此信息只能在AWS控制台界面显示,告警邮件将是默认的文本信息。输入完毕后点击下一步继续。如下截图。

在向导的第四步,预览下刚才输入的配置,无需修改。将页面向下滚动到最下方,点击右下角的Create alarm
按钮完成创建。如下截图。

创建完成后,页面就会显示出来刚才新配置的告警信息ClamAV VIRUS FOUND
。此外页面上方还会有蓝色信息提示,提示刚才订阅SNS Topic的邮箱尚未进行验证。

接下来完成邮箱验证,即可接收告警信息。
3、验证SNS Topic订阅的邮箱地址并收取告警信息
在本地计算机上访问订阅上一步订阅SNS Topic时候输入的邮箱,邮箱内会收到如下一封英文邮件。
You have chosen to subscribe to the topic: arn:aws:sns:ap-southeast-1:1234567890123:clamavfound
To confirm this subscription, click or visit the link below (If this was in error no action is necessary): Confirm subscription
Please do not reply directly to this email. If you wish to remove yourself from receiving all future SNS subscription confirmation requests please send an email to sns-opt-out
这个邮件中会提供一个带有超链接的Confirm subscription
按钮,点击这个网址,即可打开默认浏览器完成邮箱地址的确认。
确认后浏览器显示信息如下截图。

至此确认订阅完成。
如果希望查看CloudWatch告警配置,可以通过CloudWatch的All alarms
菜单进入。点击上一步配置的告警名称ClamAV VIRUS FOUND
后,即可在右侧加载出来告警信息。如下截图。

当有出发告警信息时候,去检查邮箱,可以看到告警邮件。

告警邮件中可以看到,指示是否发现病毒的Metric即clamav/found
的数值大于0,因此触发了告警。
由此即实现了通过CloudWatch Log Groups、Metric和SNS Topic组合,在ClamAV发现病毒进行统一告警。
六、参考文档
Github软件源代码仓库:
https://github.com/Cisco-Talos/clamav
ClamAV On-access scanning配置说明:
https://docs.clamav.net/manual/OnAccess.html
安装前一代Cloudwatch Logs Agent(本文使用此版本部署)
https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html
前一代Cloudwatch Logs Agent配置文件参数说明:
https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/logs/AgentReference.html
新一代Cloudwatch Logs Agent统一日志(本文未采用此版本仅供参考):
https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/logs/UseCloudWatchUnifiedAgent.html
示例:CloudWatch Log对字词的出现次数进行计数
https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/logs/CountOccurrencesExample.html
全文完。