こんにちは。
株式会社クラスアクト インフラストラクチャ事業部の大塚です。
今回はauditを使ってユーザが実行したコマンドをロギングする環境の作り方を書いていこうと思います。
用語について(AIからの出力)
この辺りをイメージできていると、導入イメージが湧きやすいのかなと個人的には思いました。
とは言いつつ、これをカキカキしながら「難しい・・・」と思っています💦
audit
Linuxの監査ログを管理するデーモンです。システムの重要な操作(ファイルアクセス、ユーザー認証、コマンド実行など)を記録し、不正アクセスや設定ミスの調査に役立ちます。
PAM
PAMフレームワークとは?
PAM(Pluggable Authentication Modules)フレームワークは、Linux/Unix の認証を柔軟に管理する仕組み です。
アプリケーション(例: sshd, login, sudo など)と認証方式(例: パスワード, 生体認証, 2FA)を 分離 し、設定を変更するだけで認証方法を簡単にカスタマイズできます。
PAMフレームワークの仕組み
アプリケーション(sshd, login, sudo など)が認証を要求
PAMライブラリ(libpam.so) が適切な PAMモジュール を呼び出す
PAMモジュール(pam_unix.so, pam_tty_audit.so など)が認証を処理
📌 設定ファイル: /etc/pam.d/ ディレクトリ内の各アプリケーション用の設定ファイル(例: sshd, login, sudo)
PAMの主な構成
- PAMライブラリ (libpam.so)
アプリケーションからの認証リクエストを処理する基盤 - PAMモジュール(/lib/security/*.so)
具体的な認証方式を実装(例: pam_unix.so → パスワード認証, pam_google_authenticator.so → 2FA) - PAM設定ファイル(/etc/pam.d/)
どのアプリケーションがどの認証モジュールを使うかを定義
構築環境
OS:ubuntu22.04
まず、以下のような環境を作っていき、/var/log/audit/audit.logに対してログイン認証のログを取れるようにしたいと思います。
この環境が構築出来た後、追加でルールを定義してユーザが実行したコマンドもログに吐き出すようにしていきたいと思います。
手順
ubuntu22.04はデフォルトでauditがインストールされていない状態であったため、インストールしていきます。
auditdをインストールすると、audit関係のツールであるauditctlやausearch,aureport等をまるっとインストールできます。
インストール後auditctl -s(audit システムにおける現在の監査設定を表示するコマンド)を実行して出力があることを確認します。
root@shota-20f5a2v5jp:~# apt update && apt upgrade -y
root@shota-20f5a2v5jp:~# apt install -y auditd
root@shota-20f5a2v5jp:~# auditctl -s
enabled 1
failure 1
pid 21885
rate_limit 0
backlog_limit 8192
lost 0
backlog 0
backlog_wait_time 60000
backlog_wait_time_actual 0
loginuid_immutable 0 unlocked
インストール確認後、startとenableを実行しておきます。
root@shota-20f5a2v5jp:~# systemctl start auditd
root@shota-20f5a2v5jp:~# systemctl enable auditd
Synchronizing state of auditd.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable auditd
PAMの設定ファイルを編集していきます。
/etc/pam.d/配下にsshというファイルとloginというファイルがあるので、これを編集します。
ここに設定を追記することで、ssh接続およびコンソールログイン(普通のPCみたいなログインの仕方のこと)してきたユーザに対してpam_tty_audit.so(PAMフレームワークのモジュールの1つ)を有効化して、認証等のログを残すように設定します。
root@shota-20f5a2v5jp:~# cd /etc/pam.d/
root@shota-20f5a2v5jp:/etc/pam.d# ls
chfn common-auth cups ppp sddm-autologin sudo
chpasswd common-password login runuser sddm-greeter sudo-i
chrome-remote-desktop common-session newusers runuser-l sshd xrdp-sesman
chsh common-session-noninteractive other samba su
common-account cron passwd sddm su-l
root@shota-20f5a2v5jp:/etc/pam.d# cat sshd
~中略~
# 2025/1 sshでログインしたユーザの認証などをログに残す設定
session required pam_tty_audit.so enable=test,root log_passwd
root@shota-20f5a2v5jp:/etc/pam.d# cat login
~中略~
# 2025/1 コンソールログインしたユーザの認証などをログに残す設定
session required pam_tty_audit.so enable=test,root log_passwd
それぞれのファイルについては以下。
※タイトルのようにssh接続ユーザのコマンド実行ログだけほしいなら不要のはずです。
- SSHログインの監視:
/etc/pam.d/sshd
- ローカルログインの監視:
/etc/pam.d/login
設定内容については以下。
-
session required pam_tty_audit.so
pam_tty_audit.so モジュールがセッション開始時に読み込まれ、ttyを使用したセッションの監視が開始されます。この設定により、ユーザーがログインした際のコマンド実行やセッションの開始が監視される(最もコマンド実行のログに関しては後述のaudit.rulesに記載しないと残らない様子。) -
enable=test,root
この設定により、監査対象としてtestとrootユーザーが指定されています。他のユーザーのセッションは監査対象になっていない。 -
log_passwd
通常、パスワードはセキュリティのためにログに記録されませんが、このオプションを有効にすると、コマンドログにパスワードの入力内容も含めて記録されるようになる。
設定を反映するためにauditdとsshdを再起動していきます。
root@shota-20f5a2v5jp:/etc/pam.d# systemctl restart auditd
root@shota-20f5a2v5jp:/etc/pam.d# systemctl restart sshd
上記の設定を入れておくと、認証系のログが/var/log/audit/audit.logに記載されるようになる。
以下のログはshotaユーザがSSHでログインした際に出力されたものです。
root@shota-20f5a2v5jp:~# cat /var/log/audit/audit.log | grep -i shota
type=USER_AUTH msg=audit(1738140096.263:742): pid=73783 uid=0 auid=4294967295 ses=4294967295 subj=unconfined msg='op=PAM:authentication grantors=pam_permit,pam_cap acct="shota" exe="/usr/sbin/sshd" hostname=192.168.0.24 addr=192.168.0.24 terminal=ssh res=success'UID="root" AUID="unset"
type=USER_ACCT msg=audit(1738140096.334:743): pid=73783 uid=0 auid=4294967295 ses=4294967295 subj=unconfined msg='op=PAM:accounting grantors=pam_permit acct="shota" exe="/usr/sbin/sshd" hostname=192.168.0.24 addr=192.168.0.24 terminal=ssh res=success'UID="root" AUID="unset"
type=CRED_ACQ msg=audit(1738140096.337:744): pid=73783 uid=0 auid=4294967295 ses=4294967295 subj=unconfined msg='op=PAM:setcred grantors=pam_permit,pam_cap acct="shota" exe="/usr/sbin/sshd" hostname=192.168.0.24 addr=192.168.0.24 terminal=ssh res=success'UID="root" AUID="unset"
type=LOGIN msg=audit(1738140096.338:745): pid=73783 uid=0 subj=unconfined old-auid=4294967295 auid=1000 tty=(none) old-ses=4294967295 ses=330 res=1UID="root" OLD-AUID="unset" AUID="shota"
type=SYSCALL msg=audit(1738140096.338:745): arch=c000003e syscall=1 success=yes exit=4 a0=3 a1=7ffdeb9982d0 a2=4 a3=0 items=0 ppid=73718 pid=73783 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=330 comm="sshd" exe="/usr/sbin/sshd" subj=unconfined key=(null)ARCH=x86_64 SYSCALL=write AUID="shota" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root"
type=USER_START msg=audit(1738140096.450:746): pid=73783 uid=0 auid=1000 ses=330 subj=unconfined msg='op=PAM:session_open grantors=pam_selinux,pam_loginuid,pam_keyinit,pam_permit,pam_umask,pam_unix,pam_systemd,pam_mail,pam_limits,pam_env,pam_env,pam_selinux,pam_tty_audit acct="shota" exe="/usr/sbin/sshd" hostname=192.168.0.24 addr=192.168.0.24 terminal=ssh res=success'UID="root" AUID="shota"
type=CRED_ACQ msg=audit(1738140096.454:747): pid=73858 uid=0 auid=1000 ses=330 subj=unconfined msg='op=PAM:setcred grantors=pam_permit,pam_cap acct="shota" exe="/usr/sbin/sshd" hostname=192.168.0.24 addr=192.168.0.24 terminal=ssh res=success'UID="root" AUID="shota"
type=USER_LOGIN msg=audit(1738140096.505:748): pid=73783 uid=0 auid=1000 ses=330 subj=unconfined msg='op=login id=1000 exe="/usr/sbin/sshd" hostname=192.168.0.24 addr=192.168.0.24 terminal=/dev/pts/3 res=success'UID="root" AUID="shot " ID="shota"
今回やりたいことはユーザが実行したコマンドをログのに残すことになるのでaudit.rulesに設定を追加していきます。
まず、auditctl -lを実行して何も出力がされなければ、ルールが何も定義されていないという事を示します。
root@shota-20f5a2v5jp:/etc/pam.d# auditctl -l
No rules
audit.rulesに設定を追加していきます。
登録にあたりユーザのUIDが必要になりますので、それを確認すために/etc/passwdを見て確認します。
今回はrootが0、shotaが1000であることがわかります。
root@shota-20f5a2v5jp:~# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
root@shota-20f5a2v5jp:~# cat /etc/passwd | grep shota
shota:x:1000:1000:shota:/home/shota:/bin/bash
audit.rulesに設定を追記していきます。
execveというのはシステムコール(プログラムの実行)を監視するものです。
root@shota-20f5a2v5jp:~# vi /etc/audit/rules.d/audit.rules
root@shota-20f5a2v5jp:~# cat /etc/audit/rules.d/audit.rules
~中略~
# 2025/1 rootとshotaがどのようなコマンドを実行したかをログに記載するために追記
-a always,exit -F arch=b64 -F euid=0 -S execve -k root_command
-a always,exit -F arch=b32 -F euid=0 -S execve -k root_command
-a always,exit -F arch=b64 -F euid=1000 -S execve -k shota_command
-a always,exit -F arch=b32 -F euid=1000 -S execve -k shota_command
auditctl -Rはauditdに対して、指定したルールファイルの内容を適用するためのコマンドです。
auditctl -lで定義したルールが出力されたことを確認して、auditdにリスタートをかけます。
root@shota-20f5a2v5jp:~# auditctl -R /etc/audit/rules.d/audit.rules
No rules
enabled 1
failure 1
pid 30306
rate_limit 0
backlog_limit 8192
lost 0
backlog 3
backlog_wait_time 60000
backlog_wait_time_actual 0
enabled 1
failure 1
pid 30306
rate_limit 0
backlog_limit 8192
lost 0
backlog 4
backlog_wait_time 60000
backlog_wait_time_actual 0
enabled 1
failure 1
pid 30306
rate_limit 0
backlog_limit 8192
lost 0
backlog 4
backlog_wait_time 60000
backlog_wait_time_actual 0
root@shota-20f5a2v5jp:/etc/audit/rules.d# auditctl -l
-a always,exit -F arch=b64 -S execve -F euid=0 -F key=root_command
-a always,exit -F arch=b32 -S execve -F euid=0 -F key=root_command
-a always,exit -F arch=b64 -S execve -F euid=1000 -F key=shota_command
-a always,exit -F arch=b32 -S execve -F euid=1000 -F key=shota_command
root@shota-20f5a2v5jp:~# systemctl restart auditd
ここまで実行するとユーザとそのユーザが実行したコマンドがログに記載されるようになります。
ausearchでよりわかりやすくどのようにコマンドを実行したかユーザごとに判断することが出来るます。
わかりづらいですがausearchをつかわずとm、/var/log/audit/audit.logにも類似のログが確認できます。
root@shota-20f5a2v5jp:~# ausearch -k root_command
----
time->Mon Jan 27 20:17:43 2025
type=PROCTITLE msg=audit(1737976663.594:810): proctitle=636174002F6574632F61756469742F72756C65732E642F61756469742E72756C6573
type=PATH msg=audit(1737976663.594:810): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=2393191 dev=08:02 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1737976663.594:810): item=0 name="/usr/bin/cat" inode=2359760 dev=08:02 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1737976663.594:810): cwd="/"
type=EXECVE msg=audit(1737976663.594:810): argc=2 a0="cat" a1="/etc/audit/rules.d/audit.rules"
type=BPRM_FCAPS msg=audit(1737976663.594:810): fver=0 fp=0 fi=0 fe=0 old_pp=000001fffffeffff old_pi=0 old_pe=000001fffffeffff old_pa=0 pp=000001fffffeffff pi=0 pe=000001fffffeffff pa=0 frootid=0
type=SYSCALL msg=audit(1737976663.594:810): arch=c000003e syscall=59 success=yes exit=0 a0=5ad440126a40 a1=5ad440126980 a2=5ad440126998 a3=8 items=2 ppid=31777 pid=31782 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="cat" exe="/usr/bin/cat" subj=unconfined key="root_command"
~中略~
----
time->Mon Jan 27 20:19:49 2025
type=PROCTITLE msg=audit(1737976789.017:831): proctitle=6175736561726368002D6B00726F6F745F636F6D6D616E64
type=PATH msg=audit(1737976789.017:831): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=2393191 dev=08:02 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1737976789.017:831): item=0 name="/usr/sbin/ausearch" inode=2366111 dev=08:02 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1737976789.017:831): cwd="/root"
type=EXECVE msg=audit(1737976789.017:831): argc=3 a0="ausearch" a1="-k" a2="root_command"
type=SYSCALL msg=audit(1737976789.017:831): arch=c000003e syscall=59 success=yes exit=0 a0=5c2f788ee7b0 a1=5c2f7888dae0 a2=5c2f788a7c30 a3=5c2f7888dae0 items=2 ppid=30566 pid=31817 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts2 ses=161 comm="ausearch" exe="/usr/sbin/ausearch" subj=unconfined key="root_command"