去年の7月、ステージングサーバーの/etc/sudoersが改ざんされていることに気づいた。通知もなく、メールもなく、何もなかった――ただある午後のデプロイが突然パーミッションエラーで失敗しただけ。誰がいつどのターミナルから変更したのかを突き止めるのに、2時間近くかかった。それ以来、auditdを真剣に使い始めた。
現実の問題:syslogだけでは「誰がやったのか」に答えられない
Fedoraをメインの開発マシンとして2年間使ってきて、パッケージの更新速度にはかなり満足している。しかしFedora Serverを本番環境に持ち込んだとき、journaldとsyslogは次のような質問に答えるように設計されていないことにすぐ気づいた:
- 午前3時に
/etc/passwdを読み込んだのはどのプロセスか? - 昨日、誰が
sudoで何のコマンドを実行したか? - バイナリファイル
/usr/bin/python3が置き換えられていないか?
JournaldはファイルではなくServiceごとにログを記録する。SSHデーモンが接続したことはわかっても、そのユーザーが後でcat /etc/shadowを実行したかどうかはわからない。これは危険な死角だ――特にCIS BenchmarkやSTIGへの準拠を証明する必要がある場合に。
SELinuxはアクセス制御を担当し、auditdは証拠の記録を担当する――全く異なる役割であり、互いに補完し合うもので、どちらかが他方の代わりにはならない。
原因分析:なぜカーネルレベルの監査が必要なのか
Linux Audit SystemはLinux Audit Frameworkを通じて動作する――カーネルバージョン2.6から組み込まれているサブシステムだ。アプリケーションが能動的に報告した内容だけを記録するsyslogとは異なり、auditはシステムコールに直接フックする:
open()、read()、write()――ファイルの読み書きexecve()――コマンドの実行setuid()、setgid()――権限の変更
システムコールレベルでフックするため、回避する方法はない――auditdが動作していてルールが正しく設定されている限り、rootであっても痕跡を残さずに操作を行うことはできない。
Fedoraでは通常auditdがプリインストールされている。インストールされていない場合:
sudo dnf install audit audit-libs -y
sudo systemctl enable --now auditd
# 状態を確認する
sudo auditctl -s
解決策:アドホックから本番運用まで
方法1:auditctlで一時的なルールを追加する
素早くデバッグするだけなら、auditctlでサービスを再起動せずに即座にルールを追加できる:
# /etc/passwdへのすべての書き込み操作を監視する
sudo auditctl -w /etc/passwd -p wa -k passwd_watch
# アクティブなルールを確認する
sudo auditctl -l
# すべての一時ルールを削除する
sudo auditctl -D
フラグ-p wa:write(w)とattribute change(a――chmod、chown)を監視する。キー-k passwd_watchは後でログをフィルタリングするためのラベルだ。
制限事項:ルールはreboot後に消える。デバッグにしか使えず、本番環境には適していない。
方法2:/etc/audit/rules.d/に永続的なルールを設定する
Fedoraはauditd起動時に/etc/audit/rules.d/からアルファベット順で永続ルールを読み込む。管理しやすいように機能別に分けている:
sudo nano /etc/audit/rules.d/10-identity.rules
## ユーザー識別ファイルを監視する
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/gshadow -p wa -k identity
## sudoersを監視する
-w /etc/sudoers -p wa -k sudoers_change
-w /etc/sudoers.d/ -p wa -k sudoers_change
## SSH設定
-w /etc/ssh/sshd_config -p wa -k sshd_config
sudo nano /etc/audit/rules.d/20-priv-commands.rules
## 実ユーザーの特権コマンドを追跡する(auid >= 1000、カーネルプロセスを除外)
-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=4294967295 -k priv_cmd
-a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=4294967295 -k priv_cmd
-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=4294967295 -k priv_cmd
## カーネルモジュールの変更を監視する(rootkitの兆候)
-w /sbin/insmod -p x -k module_insertion
-w /sbin/rmmod -p x -k module_insertion
-w /sbin/modprobe -p x -k module_insertion
書き終えたら、構文チェックとリロードを行う:
sudo augenrules --check
sudo augenrules --load
# Fedoraの場合:systemctl restart auditdは使わない
# auditdはシグナル処理が特殊なため、代わりにこのコマンドを使う:
sudo service auditd restart
方法3:コンプライアンス対応にSCAP/STIGプリセットを使う
コンプライアンスへの対応が必要な場合、一から書く必要はない。FedoraはOpenSCAPをサポートしている:
sudo dnf install openscap-scanner scap-security-guide -y
# プロファイル一覧を確認する
sudo oscap info /usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml | grep profile
# 事前スキャン(ドライラン、システムを変更しない)
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_ospp \
--results /tmp/scan-results.xml \
/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml
OSPPプロファイルは標準に従ったauditルールをすべて生成する。デメリット:必要以上に多くのルールがあるため、調整しないとauditログがすぐに肥大化する可能性がある。
ベストプラクティス:最小限のルールセット+効率的なログ分析
6ヶ月の本番運用を経て、最も効果的なアプローチは最小限から始めて、実際のニーズに基づいて拡張していくことだとわかった。ルールが多すぎる→ログが溢れる→誰も読まない→意味がない。
バッファを制御するためのベースファイルを追加する:
sudo nano /etc/audit/rules.d/00-base.rules
## 既存のルールを削除する
-D
## バッファサイズ(dmesgで「audit: backlog limit exceeded」が出たら増やす)
-b 8192
## 障害モード:1=printk経由でログ、2=カーネルパニック(厳格なコンプライアンスが必要な場合のみ2を使用)
-f 1
/etc/audit/auditd.confでローテーションを設定して、ログがディスクを使い果たさないようにする:
max_log_file = 50 # ファイルあたりのMB
num_logs = 10 # 10ファイルのローテーションを保持(合計約500MB)
max_log_file_action = ROTATE
space_left = 500 # ディスク残量500MBで警告
space_left_action = SYSLOG
admin_space_left = 50
admin_space_left_action = SUSPEND # ディスクが不足しそうな場合はauditを停止
ausearchとaureportによるログ分析
/var/log/audit/audit.logの生ログは人間が読むものではない。付属ツールを使おう:
# 本日の「identity」キーに関連するすべてのイベントを検索
sudo ausearch -k identity --start today
# ユーザーaliceのすべてのsudoコマンドを検索(-iフラグでUIDの代わりにユーザー名を表示)
sudo ausearch -k priv_cmd --uid alice -i
# 今月/etc/shadowを読み書きしたユーザーを確認
sudo ausearch -f /etc/shadow --start this-month -i
# 全体のサマリーレポート
sudo aureport --summary
# 認証レポート(ログイン/ログアウト/sudo)
sudo aureport -au
# 失敗した試みのみ
sudo aureport --failed -au
調査時によく使うトリック:ausearchを--rawオプションと組み合わせてaudispにパイプし、イベントのフルコンテキストを確認する:
# 特定のイベントIDでイベントを確認
sudo ausearch -a 1234567 -i
# オフライン分析用にファイルへエクスポート
sudo ausearch -k sudoers_change --start last-week > /tmp/sudoers-audit.txt
6ヶ月の実運用で学んだこと
第一に、auid!=4294967295のフィルタ(unset値、つまりユーザーログイン前にカーネルが起動したプロセスを意味する)は非常に重要だ。フィルタしないと、無関係なsystemdサービスのイベントでログが溢れ、必要なものを見つけにくくなる。
第二に、ルールセットが正しいと確信するまで-e 2(immutableモード)を有効にしないこと。このモードはaudit設定をロックする――解除するにはrebootしかない。早まってその行を追加したせいで、20分無駄にしたことがある。
第三に、auditdをlogwatchまたはシンプルなSIEMと組み合わせて、毎日のレポートをメールで受け取ること。ログがあっても読まなければ意味がない。次のコマンドをcronで毎日実行するだけで十分な役割を果たす:
## crontabに追加:毎朝7時にauditレポートを送信する
0 7 * * * /usr/sbin/aureport --summary | mail -s "[Audit Report] $(hostname) $(date +%F)" [email protected]
Fedora Serverを管理していてauditdをまだ設定していないなら、SSHのhardeningやfirewallルールよりも先にやるべきことだ――auditログがなければ、それらのセキュリティ対策が実際に機能しているかどうか永遠にわからないし、もっと重要なこととして、インシデントが発生したときに調査する証拠がない。
