OSの操作ログを取得したい(しなければならない)という要求は、まぁけっこうあるだろう*1。
セキュアOSではない従来のLinuxの機能で、比較的容易に実現可能な典型的な方式として、(1) scriptコマンド、(2) sudoコマンド、(3) acctコマンドを用いる3通りがある。この解説は、次の記事がいけてる。
http://www.atmarkit.co.jp/fsecurity/rensai/unix_sec06/unix_sec02.html
いずれも、特権ユーザのログを厳密に取得するものではないが、お手軽なので(感覚的には)けっこう使われているのではないかと思う。
で、ただ今、基盤チームのスミッコメンバなので、めでたく初実装することになった。今回は、シェルの起動時にscriptコマンドを実行することで*2、操作ログを自動的に取得することに。
どこにscriptコマンドを記載すればよいかは、次の記事を参考にすればわかる。
http://www.itmedia.co.jp/enterprise/articles/0803/10/news012.html
今回は、ログインシェル以外のシェル(“SSH”や“sudo -s”などで起動されるシェル)についてもscriptコマンドを実行する必要があるため、/etc/profile や ~/.bash_profile ではなく、/etc/bashrc ファイルや、ユーザごとの ~/.bashrc ファイルに、scriptコマンドを記載してみた。
# 無限ループに陥ります。 script /var/log/history/op_`whoami`_`date '+%Y%m%d%H%M%S'`_$$.log exit
ところ、、無限ループに。どうも、2006年に同じ目にあっている人がいた(ちょっとうれしい)。が、根本解決はされなかった模様(ちょっとかわいそう)。確かに、実際にやってみないと気がつかないかも。上記のように、単純にscriptコマンドを記載してしまうと、scriptコマンドが起動するシェルも、さらにscriptコマンドを実行し、無限ループになってしまう。そこで、親プロセスがscriptコマンドでない場合(例えば“sshd”や“bash”の場合)にのみ、scriptコマンドを実行するように制御しなければならない。
_script="/usr/bin/script" _p_proc=`ps aux | grep "${PPID}" | awk '{print $11}'` # この分岐がポイントです。 if [ "x${_p_proc}" != "x${_script}" ]; then ${_script} -q /var/log/history/op_`whoami`_`date '+%Y%m%d%H%M%S'`_$$.log exit fi unset _script unset _p_proc
おっけ。
2011/05/24追記
もう少しきちんとしたスクリプトにしないと、バグると判明。例えば、他のプロセスの起動引数に、親プロセスIDと同じ文字列が入ってしまっている場合など。確かに“ps aux | grep "${PPID}"”だけでは弱すぎる(“grep -v grep”すら入れてなかった)。
ちょっときたないが、次のように判定すればよいのかな(先に grep で絞っているのは、パフォーマンスがよいから)。
# 親プロセスが script ではない場合に 0 を返す。 # 例えば、bash や su や sshd などの場合。 is_parent_not_script(){ while read _pid _p_proc do if [ "x${_pid}" = "x${PPID}" ] && \ [ "x${_p_proc}" != "x${_script}" ]; then return 0 fi done << __EOC__ `ps aux | grep "${PPID}" | awk '{ print $2 " " $11 }'` __EOC__ return 1 }