亚马逊AWS官方博客
在 EC2 Linux 操作系统上部署 ClamAV 并开启实时防护、集中日志采集和统一告警
一、背景
计算机信息系统等级保护(俗称等保)的要求之一是应用服务器具有病毒防护手段,并定期升级病毒特征库。这个防护场景通常被称为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的机型运行速度可能较为缓慢,甚至出现部分时间假死的情况。
本文采用操作系统自带的软件源。执行如下命令安装。
安装好的ClamAV有几个主要组成部分:
- clamscan:手工扫描程序
- clamdscan:依赖后台服务的扫描程序
- clamonacc:按需扫描程序(实时监控),对应配置文件
/etc/clamd.d/scan.conf - clamd:按需扫描的后台进程,对应配置文件
/etc/clamd.d/scan.conf - fleshclam:病毒库升级工具,对应配置文件
/etc/fleshclam.conf - clamconf:配置文件生成工具
2、手工更新病毒库
首次安装后,必须先下载病毒库。执行如下命令更新病毒库:
返回结果如下表示升级成功:
设置后台自动升级病毒库:
默认的升级频率是每2小时升级1次,折合每天12次。如果需要调整,可以编辑如下配置文件/etc/freshclam.conf,找到其中的如下一段,把数值改为1:
重启服务,即可将升级频率设置为每天升级1次。
3、手工扫描特定文件夹
手工对某一个目录执行扫描。执行如下命令:
其中-r参数表示扫描子目录,-i参数表示只输出疑似病毒扫描结果。在启动后,首先ClamAV会验证特征库的签名,然后执行扫描。对根目录扫描的时间会很长,可能长达数分钟。
返回如下结果表示扫描完成。
三、开启实时检测和定期检测
ClamAV在Linux系统上支持实时检测,也就是对当前系统读取和写入的文件进行检测,被称为on-access scanning。
1、修改配置文件
实时检测需要启动clamd服务。这个服务的配置文件根据不同安装方式,可能配置文件路径和文件名不一样。本文使用的Amazon Linux 2的epel源安装后,配置文件是/etc/clamd.d/scan.conf。这其中要修改监听管道、启动用户等多处配置。
编辑/etc/clamd.d/scan.conf,修改如下的几个参数(排名和顺序可能所有不同,不影响效果)。
名为LocalSocket的参数的是服务监听参数。启动有localsocket和网络监听两种模式,可独立使用,也可以同时使用。对于EC2的本机扫描而言,适用Unix管道的localsocket模式即可。
名为OnAccess的参数是实时扫描相关,分别表示:打开实时防护并拦截有风险的访问;设置要执行实施监控的路径(不建议对/根路径监控,建议只监控应用路径,本文以/home为例);实时检测要排除的用户名。由于clamd不能以root身份运行,而需要以普通用户身份运行,在本文使用操作系统安装源时候,会自动创建名为clamscan的新用户,然后以这个身份运行。因此在配置文件中,这里需要设置一个与clamd服务启动的用户名保持一致,否则会发生自己触发扫描自己的递归调用,造成不必要的资源消耗。
名为Log相关的参数是日志路径和日志大小配置。在刚安装好的配置文件中,默认配置LogSyslog yes这个参数的生效,因此扫描到的病毒结果会输出到系统日志中。本文为了便于查询,额外又设置了如上配置文件中的日志地址/var/log/clamd.scan并且配置了最大体积为20MB。
都修改完毕后,保存退出。
执行如下命令创建日志文件:
2、启动clamd和clamonacc后台服务
以root身份执行如下命令启动clamd服务:
为了验证实时监控在运行,可执行clamdtop命令查看后台进程。显示结果类似如下:
然后即可进入类似Top命令的资源占用查看界面,即可证明clamd服务启动正常。
3、验证实时防护
为了验证实时防护的有效性,需要模拟一个病毒特征来触发告警。在云上请勿使用真实病毒来测试您的网络安全,如用真实病毒测试,可能会触发对外部网络的扫描等恶意行为,将导致您的云账号被投诉和甚至关停。因此这里引入一个测试特征码来测试。欧洲计算机防病毒研究所 (EICAR) 开发了一种测试特征码,他是一个惰性的文本文件,也就是一串字符串,并且不包含任何程序代码无法被执行。这个特征码包含在多数防病毒的特征中可以被识别出来。这里将它写入一个文本文件eicar.virus。由于前文配置Clamd后台进程是监控的/home目录,这里需要与之匹配,所以将这个病毒特征文件放到/home目录下。如果放在其他目录下则没有办法被扫描到。执行如下命令即可生成特征码。
现在以普通ec2-user用户的身份调用访问这个文件cat /home/eicar.virus,此时将会触发实时防护,访问将被拦截。此时的ec2-user用户的console上会有如下提示:
在操作系统日志/var/log/message中可看到实时防护的结果提示:
在配置文件中指定的日志文件/var/log/clamd.scan内,也可以看到:
4、查看历史日志过滤结果
执行如下命令即可过滤结果只发现的病毒:
返回结果如下:
5、设置定期扫描的计划任务
除了实时检测外,实现病毒防护另一个主要途径是定期进行全盘扫描,例如每晚对整个磁盘进行100%的手工扫描。这个步骤可以通过计划任务进行。
新建计划任务配置文件/etc/cron.daily/fullscan,添加如下:
以上命令中,-r /表示对本机根目录上所有文件、文件夹和子文件夹进行递归的扫描,-i表示只输出受影响的文件,-l /var/log/clamd.scan表示将扫描日志写入到特定文件中,下文将配置集中的日志上报。
然后将这个文件设置为可执行权限。
这样即可完成每日全盘扫描,并将日志输出到特定文件。
四、集中上报扫描结果
不管是手工发起的扫描,还是按需扫描(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进行配置。执行如下命令安装:
安装成功。
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,名为:
这个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的扫描日志。
如下一段是建议注释掉的日志。
4、新加入ClamAV日志的配置段
前文配置中已经有生成日志/var/log/clamd.scan,因此可分析这个日志文件的输出格式,然后编写有针对性的如下一段:
将以上这一段配置文件加入配置文件/etc/awslogs/awslogs.conf的末尾,保存后继续下一步。
5、设置上报的Region然后启动服务
编辑配置文件/etc/awslogs/awscli.conf,修改默认region设置。如果不修改,默认会上传日志到us-east-1区域。因此需要改成应用所在的区域,例如本文是新加坡区域(ap-southeast-1)。
配置文件调整好后,启动服务。
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:clamavfoundTo confirm this subscription, click or visit the link below (If this was in error no action is necessary):
Confirm subscriptionPlease 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






















