ClamAVとCloudWatch Logsを連携してウィルス検出をメールで通知する

clamav-trademark

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、せーのです。このところClamAVをよく触っているわけですが、今日はClamAVでウイルスを検出した時にCloudWatch Logsのアラートの仕組みを使って通知する、というアーキテクチャをご紹介します。

EC2からメールを飛ばすのは手続きがある

ClamAVはEC2の中に入っているのだから、そこから直接メールを飛ばせばいいじゃん、と思う方もいらっしゃるかもしれません。ですがEC2からメールを飛ばすには事前にAWSに対してメール送信制限の解除申請というのを行う必要があります。まあ、出してしまえばいいんですが、この1ステップがめんどくさい。メールを送るだけなのでサクッとやっつけたい、というエンジニアの心、よくわかります。 このような場合に一番簡単なのはSNSからメールを通知することです。でもEC2にSDKを入れてSNSのトピックを叩くのはスマートではありません。ここはスキャン結果をCloudWatch Logsに吐き出して、そこからフィルタリングしてカスタムメトリクスを作成し、それとSNSを紐付けることにします。そうすることでコードを一行も書くことなくウィルス検出からメール送信までほぼリアルタイムでの通知が可能となります。

clamavtocloudwatch

やってみた

ClamAVのインストールとテスト

それではやってみましょう。まずはこちらの記事を元にAmazon LinuxにClamAVをインストールします。

インストールが完了したら一旦手動でウイルススキャンをかけてみます。

$ sudo clamscan -r -i ~

----------- SCAN SUMMARY -----------
Known viruses: 3897909
Engine version: 0.98.7
Scanned directories: 2
Scanned files: 6
Infected files: 0
Data scanned: 0.00 MB
Data read: 0.00 MB (ratio 0.00:1)
Time: 7.509 sec (0 m 7 s)

オプションを確認

ここでウイルススキャンのコマンド[clamscan]のオプションについて確認しておきましょう。clamscanコマンドの詳細は[man clamscan]と打ち込む事で出てきます。

clamscanはclamscan [option] [file/directory/-]という形で認識され、オプションの種類はその下に説明があります。主なオプションを以下に書きます。

  • -v : 出力を詳細にする
  • -l FILE: 結果をファイルへ出力
  • -i: ウイルスに感染したファイルのみを出力
  • -r: サブディレクトリごと再帰的に検査。圧縮ファイルは再帰的に解凍して検査
  • --exclude=PATT: パターンにマッチするファイルを検査しない
  • --include=PATT: パターンにマッチするファイルのみを検査する
  • --quiet: エラー情報のみ出力
  • --remove: ウイスルに感染したファイルを削除する
  • --move=DIRECTORY: ウイスルに感染したファイルをDIRECTORYへ移動する

ちなみに単独のファイルを検査した時に限りclamscanは戻り値を返します。戻り値は - 0: ウィルスは検出されなかった - 1: 1つ以上のウイルスが検出された - その他: 何らかの理由でclamscanが正常に実行されなかった の3種類です。

今回はroot権限で/home/ec2-user/フォルダ以下をスキャンし、その結果をエラー情報のみログファイルに記すcronを書きます。実際の運用時は専用のグループ、ユーザーを作って動作させたほうが良いかと思います。

$ sudo su -
# mkdir /var/log/clamav
# cd /var/log/clamav/
# touch clam.log
# chmod 666 clam.log

ログファイルに入るかどうかテストします。

# clamscan -r -l /var/log/clamav/clam.log -i --quiet /home/ec2-user
# cat clam.log
----------- SCAN SUMMARY -----------
Known viruses: 3897909
Engine version: 0.98.7
Scanned directories: 2
Scanned files: 7
Infected files: 0
Data scanned: 0.00 MB
Data read: 0.00 MB (ratio 0.00:1)
Time: 7.713 sec (0 m 7 s)

問題なく入っているようです。

CloudWatch Logsのインストールと設定

次にCloudWatch Logsのエージェントをインストールし、設定します。まずはCloudWatch Logsのエージェントをインストールします。

# yum install -y awslogs

設定ファイルを見直します。リージョンを東京に変えます。

# vi /etc/awslogs/awscli.conf
[plugins]
cwlogs = cwlogs
[default]
region = ap-northeast-1

次に監視対象ファイルを先ほどのClamAVのログファイルがあるパスにて設定します。ここらへんの細かい設定はこちらの記事を御覧ください。

# vi /etc/awslogs/awslogs.conf
...
...
[/var/log/clamav/clam.log]
log_group_name=/var/log/clamav
log_stream_name={hostname}_clamav_error
file = /var/log/clamav/clam.log
datetime_format = [%a %b %d %H:%M:%S %Y]
initial_position = start_of_file
buffer_duration = 5000

一旦テストしてみます。

# clamscan -r -l /var/log/clamav/clam.log -i --quiet /home/ec2-user

CloudWatchを確認してみましょう。

cloudwatchlogs_clamav1

cloudwatchlogs_clamav2

とれているようです。

CloudWatch Logsでウイルスを検出してメールを投げる

後は設定関係でおしまいです。まずウイルスを検出した時のパターンを特定します。こちらの記事のようにeicar.comを使ってウイルスを検出してみます。

vi ~/eicar.com
# clamscan -r -l /var/log/clamav/clam.log -i --quiet /home/ec2-user

cloudwatchlogs_clamav3

どうやらウイルスを検出すると[◯◯ FOUND」と出るようですので[FOUND]という文字をフィルタリングし、アラートを投げてみたいと思います。 まず警告用のSNSトピックを作成します。

cloudwatchlogs_clamav4

トピックでは私宛にメールを投げるように設定しました。

cloudwatchlogs_clamav5-1

次にCloudWatch Logsより[FOUND]という文字列でログをフィルタリングします。 まずフィルタリングメトリクスを開きます。

cloudwatchlogs_clamav6

「メトリックスフィルタの追加」より新しいフィルタを作成します。

cloudwatchlogs_clamav7

文字列「FOUND」をフィルタリングするように設定します。

cloudwatchlogs_clamav8

完成したフィルタに対してアラートを作成します。先ほどのフィルタメトリクスが1以上になったらSNSトピックへのアクション、つまりメールが飛ぶように設定します。

cloudwatchlogs_clamav9

テスト

これで準備は完成です。テストしてみましょう。

# clamscan -r -l /var/log/clamav/clam.log -i --quiet /home/ec2-user

cloudwatchlogs_clamav10

無事メールが飛んできました。

まとめ

いかがでしょうか。このようにメール通知はSNSやCloudWatch Logsと併用することで簡単に実装することが出来ます。ClamAVは大きく分けて「ウイルスをスキャンする(clamscan)」と「ウイルスのDBを更新する(freshclam)」の2つしかコマンドがないので、そちらをログに吐くようにしてCloudWatch Logsで監視すればClamAV関連で異常が起きた時にはすぐにメール通知で知ることが出来るようになります。 ちなみにウイルスが検知されていない時は作成したフィルタメトリクスは「0」ではなく「no point data」となるので普段は上記のアラートは「OK」ではなく「INSUFFICIENT_DATA(データ不足)」というステータスに置かれます。動きには特に関係がないのでこのままで行きましょう。 次回はウイルススキャンとDBの更新を自動化します。