大柳です。
前回記事では、auditログをfluentd経由でCloudWatch Logsに連携できることが確認できました。
前回記事: EC2でファイル監査を設定する(fluentd+CloudWatch Logs設定編)
今回はexec_filter Output Pluginを使ってログを加工してCloudWatch Logsに連携してみます。
全体構成は以下の通りです。
Pythonスクリプトの作成
今回はPythonでログを加工するスクリプトを作成しました。(fluent.py)
スクリプトは http://qiita.com/hagino3000/items/de66d04c7d71d7d8fcad を参考に作成しました。
デバッグ用にロギングの設定(logger.conf)もしています。
ログ加工用スクリプト(fluent.py)
1$ vi /home/ec2-user/fluent.py 23# coding=utf-845import json6import logging7import logging.config8import sys9import traceback10import msgpack11import re12import time13from datetime import datetime1415logging.config.fileConfig('/home/ec2-user/logger.conf')16logger = logging.getLogger()17logger.propagate = False1819#ログを変換して返す20def log_filter(line):21 log_datetime=""22 log_username=""2324 lists=line.split() #空白文字でスプリット25 26 for record in lists:27 if re.match(r'^msg=audit\(',record):28 match = re.match(r'^msg=audit\(([\d\.]+)',record) ##時刻部分を取り出し29 log_datetime=datetime.fromtimestamp(float(match.group(1))).strftime('%Y-%m-%d %H:%M:%S.%f')30 continue31 elif re.match(r'uid=',record):32 log_username="unknown"33 match = re.match(r'^uid=([\d]+)',record)3435# idを取り出し3637 ld = open("/etc/passwd")38 uid_lists = ld.readlines()39 ld.close()40 for list in uid_lists:41 x=list.split(":")42 if x[2]==match.group(1): log_username = x[0]43 return log_datetime + " : " + log_username + " : " + line4445def main():46 stdin = sys.stdin47 output(convert(parse(readline(stdin))))4849def readline(stdin):50 for line in stdin:51 yield line5253def parse(lines):54 for line in lines:55 yield json.loads(line)5657def convert(rows):58 for row in rows:59 row['message']=log_filter(row['message'])60 yield row6162def output(rows):63 for row in rows:64 sys.stdout.write(msgpack.packb(row))6566if __name__ == '__main__':67 logger.info('Start main')68 try:69 main()70 except Exception as e:71 logger.error(traceback.format_exc())72 raise e73 logger.info('End main')ロギング設定(logger.conf)
1$ vi /home/ec2-user/logger.conf2[loggers]3keys=root45[handlers]6keys=fileHandler78[formatters]9keys=simpleFormatter1011[logger_root]12level=DEBUG13handlers=fileHandler1415[handler_fileHandler]16class=FileHandler17formatter=simpleFormatter18args=('/home/ec2-user/root.log','a')1920[formatter_simpleFormatter]21format=%(asctime)s - %(name)s - %(levelname)s - %(message)s22datefmt=fluentd設定
次にfluentdの設定です。
sourceブロックでaudit.logを読み込み、auditlogfilterブロックでPythonスクリプトで加工、auditlogfilter_outputブロックでCloudWatch Logsに連携しています。
1$ sudo vi /etc/td-agent/td-agent.conf2<source>3 type tail4 path /var/log/audit/audit.log5 pos_file /var/log/td-agent/audit.log.pos6 tag audit_log_filter7 format none8</source>910<match audit_log_filter>11 type exec_filter12 command /usr/bin/python /home/ec2-user/fluent.py13 in_format json14 out_format msgpack15 tag audit_log_filter_output16</match>1718<match audit_log_filter_output>19 type cloudwatch_logs20 log_group_name DevServer/audit/audit_log21 log_stream_name fluentd_audit_log_filtered22 auto_create_stream true23</match>稼働確認
ログ加工用のPythonスクリプトの配置、設定ファイル更新が完了したら、fluentdを再起動します。
1$ sudo /etc/init.d/td-agent startpsコマンドを打つとPythonスクリプトが稼働しているのが確認できます。
1$ ps -ef | grep python2root 2373 2355 0 12:25 ? 00:00:00 /usr/bin/python /home/ec2-user/fluent.pyPythonスクリプトに問題があってスクリプトが異常終了した場合は以下のようなメッセージが出力されます。loggingログを利用してデバッグして問題を修正してください。
12017-03-24 12:10:31 +0000 [warn]: exec_filter Broken pipe, child process maybe exited. 2command="/usr/bin/python /home/ec2-user/fluent.py"CloudWatch Logsのコンソールを確認すると、メッセージの先頭に時刻とユーザIDが表示できているのが確認できます。
まとめ
監査ログをfluentdのexec_filter Output Pluginを使って加工、CloudWatch Logsに出力できることが確認できました。
一点注意すべきなのは、ログ加工のオーバーヘッドがあるということです。本番システムで利用する場合には、負荷テストを行って、システムの稼働に悪影響を及ぼさないか、確認することをおすすめします。
こういった注意点はあるものの、CloudWatch Logsではログの加工や条件判断などはあまり柔軟に対応できないため、事前にfluentdで加工することで、監視運用の幅を広げることができるため、うまく活用していきたいです。
最後までお読みいただきありがとうございました。