Linuxにログインしたユーザーの操作を完全記録!効率的なログ取得方法を徹底解説

Linux

ブログ運営者
さいとう

閲覧いただきありがとうございます!"さいとう"と申します。わたしは異業種・未経験からIT業界に転職し、現在インフラエンジニアとしてクラウド環境の設計や構築・運用の支援を行っています。


Linuxにログインしたユーザーの操作ログをしっかりと記録したい


あなたならどうしますか?


私も最初は、historyやlastコマンドでなんとかなるだろうと考えていました。これらのコマンドを使えば、ある程度ユーザーの操作履歴やログイン情報を確認できるので、それで十分だと思っていたのです。


しかし、今回求められていた操作ログには、以下の要件が含まれていました。


・実行ユーザー名が記録されていること
・実行時刻が明確であること
・実行されたコマンドの結果も記録されていること



historyやlastコマンドでは、上記の要件を完全には満たしていません


historyはコマンドの履歴を残してくれますが、実行されたコマンドの詳細な結果や正確な時刻、また他のユーザーが実行した操作を確認するのは難しいです。


「もっと詳しいログを自動的に取得するにはどうすればいいのか?」と頭を悩ませていたときに、ログインユーザーの操作ログを効率的に取得する方法を見つけました。


今回の記事では、その方法を詳しく紹介します。ユーザーの操作を詳細に記録し、セキュリティ対策やトラブルシューティングに役立つこの手法を、ぜひ取り入れてみてください。


↓【PR】Linuxの入門書はコレ!



ユーザーの操作ログを自動記録する方法

操作ログといえば、わたしは「history」コマンドを思い浮かべました。しかし、historyと叩けばわかるのですが、コマンド自体の記録しか残っておりません。実行結果や実行した時刻が記録されていないので、証跡としては不十分です。


今回わたしが考えた記録方法は、ssh接続したログインユーザーが実行したコマンド・実行結果をscriptコマンドで記録する方法です。


操作ログを漏れなく取得するために、/etc/prfileにスクリプトを追記し、ユーザーログイン時にscriptコマンドが実行されるように設定します。

scriptコマンド

今回の自動記録で利用する"script"コマンドについて説明します。

script は、端末セッションで行われるすべてについて忠実な記録 (タイプスクリプト、typescript) を作成する。端末上のデータは、未加工のまま (in raw form) ログファイルに記録され、 タイミングに関する情報は、(作成する、しないが任意の) 構造化された別のログファイルに記録される。このタイミングのログファイルは、後で scriptreplay(1) を使用して、セッションを再生するためにも、 またセッションに関する補足情報を記録するためにも必要である。(linuxjm.osdn.jpより)



scriptコマンドを打つと、実行したコマンドや実行結果をすべて記録することができるんですよね。


しかし、ユーザーがログインする度にscriptコマンドを打つのは大変ですし、漏れが発生することでしょう。


構築

ログインユーザーの操作ログを自動で記録するために、/etc/prfileにscriptコマンドが実行されるよう追記します。また、操作ログは指定のディレクトリに保存されるように設定しておきましょう。


それでは、構築していきます。

[ec2-user@ip-172-31-20-170 ~]$ sudo su -
[root@ip-172-31-20-170 ~]# mkdir -p /var/log/scripts/opelog/
[root@ip-172-31-20-170 ~]# chmod 733 -R /var/log/scripts/opelog/
[root@ip-172-31-20-170 ~]# cp /etc/profile /etc/profile.`date "+%Y%m%d"`
[root@ip-172-31-20-170 ~]# ls /etc/profile*
/etc/profile  /etc/profile.20230211

/etc/profile.d:
256term.csh  bash_completion.sh  colorgrep.sh  colorls.sh  lang.csh  less.csh  sh.local    which2.sh
256term.sh   colorgrep.csh       colorls.csh   csh.local   lang.sh   less.sh   which2.csh



/etc/profileに以下のスクリプト追記します。

# operationLog
nowProcess=`ps aux | grep $PPID | grep sshd | awk '{ print $11 }'`
if [ "$nowProcess" = sshd: ]; then
  todayDate=`date '+%Y%m%d%H%M'`
  loginUser=`whoami`
  script -afq /var/log/scripts/opelog/${loginUser}_${todayDate}.log
fi



それでは追記します。

[root@ip-172-31-20-170 ~]# vi /etc/profile

# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}


if [ -x /usr/bin/id ]; then
    if [ -z "$EUID" ]; then
        # ksh workaround
        EUID=`/usr/bin/id -u`
        UID=`/usr/bin/id -ru`
    fi
    USER="`/usr/bin/id -un`"
    LOGNAME=$USER
    MAIL="/var/spool/mail/$USER"
fi

# Path manipulation
if [ "$EUID" = "0" ]; then
    pathmunge /usr/sbin
    pathmunge /usr/local/sbin
else
    pathmunge /usr/local/sbin after
    pathmunge /usr/sbin after
fi

HOSTNAME=`/usr/bin/hostname 2>/dev/null`
HISTSIZE=1000
if [ "$HISTCONTROL" = "ignorespace" ] ; then
    export HISTCONTROL=ignoreboth
else
    export HISTCONTROL=ignoredups
fi

export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL

# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
    umask 002
else
    umask 022
fi

for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null
        fi
    fi
done

unset i
unset -f pathmunge

# operationLog
nowProcess=`ps aux | grep $PPID | grep sshd | awk '{ print $11 }'`
if [ "$nowProcess" = sshd: ]; then
  todayDate=`date '+%Y%m%d%H%M'`
  loginUser=`whoami`
  script -afq /var/log/scripts/opelog/${loginUser}_${todayDate}.log
fi



追記が完了しましたら、保存し、ログアウトしましょう。

ESC
:wq
[root@ip-172-31-20-170 ~]# exit
logout
[ec2-user@ip-172-31-20-170 ~]$ exit



構築は以上です。


動作確認

操作ログが記録されるか見ていきましょう。


ssh接続でログインします。


適当なコマンドを実行してみます。

[ec2-user@ip-172-31-20-170 ~]$ pwd
/home/ec2-user
[ec2-user@ip-172-31-20-170 ~]$ whoami
ec2-user
[ec2-user@ip-172-31-20-170 ~]$ uname -a
Linux ip-172-31-20-170.ap-southeast-1.compute.internal 5.10.162-141.675.amzn2.x86_64 #1 SMP Mon Jan 9 22:45:11 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux



ログの中身を見てみます。

[ec2-user@ip-172-31-20-170 ~]$ exit
exit
[ec2-user@ip-172-31-20-170 ~]$ sudo su -
Last login: Sat Feb 11 02:23:29 UTC 2023 on pts/0
[root@ip-172-31-20-170 ~]# ls /var/log/scripts/opelog/
ec2-user_202302110229.log
[root@ip-172-31-20-170 ~]# less /var/log/scripts/opelog/ec2-user_202302110229.log

Script started on 2023-02-11 02:29:39+0000
ESC]0;ec2-user@ip-172-31-20-170:~^GESC[?1034h[ec2-user@ip-172-31-20-170 ~]$ pwd
/home/ec2-user
ESC]0;ec2-user@ip-172-31-20-170:~^G[ec2-user@ip-172-31-20-170 ~]$ whoami
ec2-user
ESC]0;ec2-user@ip-172-31-20-170:~^G[ec2-user@ip-172-31-20-170 ~]$ uname -ESC[Ka
Linux ip-172-31-20-170.ap-southeast-1.compute.internal 5.10.162-141.675.amzn2.x86_64 #1 SMP Mon Jan 9 22:45:11 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
ESC]0;ec2-user@ip-172-31-20-170:~^G[ec2-user@ip-172-31-20-170 ~]$ exit
exit

Script done on 2023-02-11 02:33:03+0000
/var/log/scripts/opelog/ec2-user_202302110229.log (END)



操作ログは取れていますが、人間の目から見ると、いらない文字列が入っていますね、、、


要件は満たしているので、一旦以上にしておきます。

注意点

今回の「ログインユーザーの操作ログを自動で取得する方法」には、いくつか注意点があります。

  • exitを打つとシェルが終了し記録が止まる
  • ログの見た目が汚い
  • 長時間操作した場合、ファイルサイズが大きくなる
  • ログファイルがたまっていく



まとめ

現在、私はログ収集の業務を担当していますが、ログにはさまざまな種類があり、その中でも操作ログのように、適切な方法で取得するために自分で試行錯誤することが求められるケースが少なくありません。


今回の記事で紹介した方法は、実際に現場で役立つ一つのアプローチですが、システムや要件に応じて適切なログの収集方法を見つけていくことが大切です。


ログ収集は、システムのトラブルシューティングやセキュリティ対策において欠かせない作業です。取得できるログの種類や内容を正確に把握し、必要な情報を確実に記録することが求められます。ログ管理がしっかりしていることで、運用の安定性が向上し、問題発生時にも迅速に対応できるようになります。


今回紹介した操作ログの取得方法も、まだまだ改善の余地があります。システムの規模や環境によって、より効率的にログを取得するための設定やツールの導入が必要になるかもしれません。これからも、実際の運用で得た知見をもとに、方法を改善しながら、新たなアイデアやベストプラクティスを追記していく予定です。


今後も継続的に学び、現場での業務に反映させながら、より高度で効果的なログ収集を目指していきましょう。今回の記事が、皆さんの業務に少しでも役立つことを願っています。

↓【PR】Linuxの入門書はコレ!