大柳です。
前回記事では、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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
$ vi /home/ec2-user/fluent.py # coding=utf-8 import json import logging import logging.config import sys import traceback import msgpack import re import time from datetime import datetime logging.config.fileConfig('/home/ec2-user/logger.conf') logger = logging.getLogger() logger.propagate = False #ログを変換して返す def log_filter(line): log_datetime="" log_username="" lists=line.split() #空白文字でスプリット for record in lists: if re.match(r'^msg=audit\(',record): match = re.match(r'^msg=audit\(([\d\.]+)',record) ##時刻部分を取り出し log_datetime=datetime.fromtimestamp(float(match.group(1))).strftime('%Y-%m-%d %H:%M:%S.%f') continue elif re.match(r'uid=',record): log_username="unknown" match = re.match(r'^uid=([\d]+)',record) # idを取り出し ld = open("/etc/passwd") uid_lists = ld.readlines() ld.close() for list in uid_lists: x=list.split(":") if x[2]==match.group(1): log_username = x[0] return log_datetime + " : " + log_username + " : " + line def main(): stdin = sys.stdin output(convert(parse(readline(stdin)))) def readline(stdin): for line in stdin: yield line def parse(lines): for line in lines: yield json.loads(line) def convert(rows): for row in rows: row['message']=log_filter(row['message']) yield row def output(rows): for row in rows: sys.stdout.write(msgpack.packb(row)) if __name__ == '__main__': logger.info('Start main') try: main() except Exception as e: logger.error(traceback.format_exc()) raise e logger.info('End main') |
ロギング設定(logger.conf)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$ vi /home/ec2-user/logger.conf [loggers] keys=root [handlers] keys=fileHandler [formatters] keys=simpleFormatter [logger_root] level=DEBUG handlers=fileHandler [handler_fileHandler] class=FileHandler formatter=simpleFormatter args=('/home/ec2-user/root.log','a') [formatter_simpleFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt= |
fluentd設定
次にfluentdの設定です。
sourceブロックでaudit.logを読み込み、audit_log_filterブロックでPythonスクリプトで加工、audit_log_filter_outputブロックでCloudWatch Logsに連携しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ sudo vi /etc/td-agent/td-agent.conf <source> type tail path /var/log/audit/audit.log pos_file /var/log/td-agent/audit.log.pos tag audit_log_filter format none </source> <match audit_log_filter> type exec_filter command /usr/bin/python /home/ec2-user/fluent.py in_format json out_format msgpack tag audit_log_filter_output </match> <match audit_log_filter_output> type cloudwatch_logs log_group_name DevServer/audit/audit_log log_stream_name fluentd_audit_log_filtered auto_create_stream true </match> |
稼働確認
ログ加工用のPythonスクリプトの配置、設定ファイル更新が完了したら、fluentdを再起動します。
1 |
$ sudo /etc/init.d/td-agent start |
psコマンドを打つとPythonスクリプトが稼働しているのが確認できます。
1 2 |
$ ps -ef | grep python root 2373 2355 0 12:25 ? 00:00:00 /usr/bin/python /home/ec2-user/fluent.py |
Pythonスクリプトに問題があってスクリプトが異常終了した場合は以下のようなメッセージが出力されます。loggingログを利用してデバッグして問題を修正してください。
1 2 |
2017-03-24 12:10:31 +0000 [warn]: exec_filter Broken pipe, child process maybe exited. command="/usr/bin/python /home/ec2-user/fluent.py" |
CloudWatch Logsのコンソールを確認すると、メッセージの先頭に時刻とユーザIDが表示できているのが確認できます。
まとめ
監査ログをfluentdのexec_filter Output Pluginを使って加工、CloudWatch Logsに出力できることが確認できました。
一点注意すべきなのは、ログ加工のオーバーヘッドがあるということです。本番システムで利用する場合には、負荷テストを行って、システムの稼働に悪影響を及ぼさないか、確認することをおすすめします。
こういった注意点はあるものの、CloudWatch Logsではログの加工や条件判断などはあまり柔軟に対応できないため、事前にfluentdで加工することで、監視運用の幅を広げることができるため、うまく活用していきたいです。
最後までお読みいただきありがとうございました。