SELinux 入門 - 拒否ログを読み解く第一歩
SELinux とは何か?
SELinux(Security-Enhanced Linux)は、Linux カーネルに組み込まれた強制アクセス制御(MAC)機構で、通常の Unix ファイル権限(DAC)の上にもう一層のセキュリティを追加する。RHEL / CentOS / Fedora 系では標準で有効になっており、Apache・PostgreSQL などのプロセスが想定外のファイルにアクセスしようとすると自動的にブロックする。
通常の chmod / chown(DAC)では「このファイルの所有者か?グループに属しているか?」しか問わない。SELinux は加えて「このプロセスタイプがこのファイルタイプにこの操作を行ってよいか?」をポリシーで制御する。
動作モード
| モード | 動作 |
|---|---|
| Enforcing | ポリシー違反を拒否してログに記録。通常運用はこのモード |
| Permissive | 拒否せずログのみ記録。トラブルシュート時に使用 |
| Disabled | SELinux 完全無効。再起動が必要 |
Disabled への変更は /etc/selinux/config の編集と再起動が必要。再び Enforcing に戻す際はファイルコンテキストの再ラベル付けが必要になる場合がある。
動作モードを確認する
現在のモードを確認するには getenforce が最速。詳細を確認したい場合は sestatus を使う。
$ getenforce Enforcing
$ sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux mount point: /sys/fs/selinux Loaded policy name: targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: actual (secure) Max kernel policy version: 33
Current mode と Mode from config file の両方を見ると、現在の状態と再起動後の状態を確認できる。
Permissive モードに一時切り替え
再起動せずにモードを切り替えたい場合は setenforce を使う。再起動すると設定ファイルの値に戻る。
$ sudo setenforce 0 # Permissive に変更 $ sudo setenforce 1 # Enforcing に戻す
トラブルシュートの鉄則: まず setenforce 0 で Permissive にして問題が再現しなくなれば、SELinux が原因と確定できる。本番環境では確認後すぐ Enforcing に戻すこと。
AVC 拒否ログを読む
SELinux がアクセスを拒否すると AVC(Access Vector Cache)ログを記録する。主な記録先は /var/log/audit/audit.log。
type=AVC msg=audit(1748780400.123:1234): avc: denied { read } for pid=1122 comm="httpd" name="app.conf" dev="sda1" ino=56789 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0
各フィールドの意味:
| フィールド | 意味 | 上記の例 |
|---|---|---|
denied { read } |
拒否された操作 | 読み取りを拒否 |
comm="httpd" |
プロセス名 | Apache |
name="app.conf" |
アクセス対象のファイル名 | app.conf |
scontext=...httpd_t... |
ソースコンテキスト(プロセス側) | httpd_t タイプ |
tcontext=...user_home_t... |
ターゲットコンテキスト(ファイル側) | user_home_t タイプ |
tclass=file |
リソースの種類 | 通常ファイル |
permissive=0 |
Enforcing モードで発生 | 実際に拒否 |
scontext と tcontext のタイプ部分(_t で終わる)がミスマッチしているときが最も多い原因。httpd(httpd_t)がホームディレクトリのファイル(user_home_t)にアクセスしようとすると拒否される。
ファイルのコンテキストを確認する
$ ls -Z /var/www/html/app.conf unconfined_u:object_r:user_home_t:s0 /var/www/html/app.conf
このファイルのタイプが user_home_t になっているため、httpd_t からアクセスできない。本来は httpd_sys_content_t であるべき。
ausearch で拒否ログを絞り込む
/var/log/audit/audit.log を直接 grep するよりも、ausearch を使うほうが効率的に絞り込める。
# 最近(直近10分)の AVC 拒否ログを確認 $ sudo ausearch -m AVC -ts recent # 今日の AVC 拒否ログをすべて確認 $ sudo ausearch -m AVC --start today # 特定のプロセス名で絞り込む $ sudo ausearch -m AVC -ts recent -c httpd # 特定のファイル名で絞り込む $ sudo ausearch -m AVC --start today | grep "app.conf"
-ts recent は直近10分間のログを表示する。--start today は当日0時以降のすべてのログを対象にする。
audit2why で原因を特定する
audit2why は AVC ログを人間が読みやすい形式で解説してくれるツール。ausearch の出力をパイプで渡す。
$ sudo ausearch -m AVC -ts recent | audit2why
type=AVC msg=audit(1748780400.123:1234): avc: denied { read } for pid=1122 comm="httpd" ...
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
出力に "Missing type enforcement (TE) allow rule." とあれば、ポリシーに許可ルールが定義されていないことが原因。
audit2why は原因を説明するだけで、修正は行わない。修正方法の提案が必要な場合は audit2allow を使う(本番環境での安易な使用は避けること)。
よくある対処パターン
ファイルのコンテキストを正しいタイプに戻す
ファイルを別ディレクトリからコピーした場合などに元のコンテキストが引き継がれる問題が起きる。restorecon でデフォルトのコンテキストに戻すのが最初の選択肢。
# 単一ファイルのコンテキストを復元 $ sudo restorecon -v /var/www/html/app.conf Relabeled /var/www/html/app.conf from unconfined_u:object_r:user_home_t:s0 to system_u:object_r:httpd_sys_content_t:s0 # ディレクトリ配下を再帰的に復元 $ sudo restorecon -Rv /var/www/html/
手動でコンテキストタイプを設定する
一時的にコンテキストを変更したい場合は chcon を使う。ただし restorecon や再ラベル付けで上書きされる点に注意。
$ sudo chcon -t httpd_sys_content_t /var/www/html/app.conf
Boolean でポリシーを切り替える
SELinux ポリシーには Boolean という on/off スイッチが多数用意されている。例えば Apache がユーザーホームディレクトリを配信する場合は以下の Boolean を有効にする。
# httpd 関連の Boolean 一覧を確認 $ getsebool -a | grep httpd # Boolean を永続的に変更(-P で再起動後も維持) $ sudo setsebool -P httpd_enable_homedirs on
ポリシーを無効化する方向(Disabled への変更や過度な Boolean 有効化)よりも、ファイルのコンテキストを正しく設定する方向を優先すること。
まとめ:トラブルシュートの手順
getenforceでモードを確認 → Enforcing であることを確認setenforce 0で Permissive にして問題が消えるか確認 → 消えれば SELinux が原因sudo ausearch -m AVC -ts recent | audit2whyで拒否の原因を特定ls -Zでファイルのコンテキストを確認restorecon -vでコンテキストを復元、またはsetseboolで Boolean を調整setenforce 1で Enforcing に戻す
SELinux は無効化しない
"selinux disabled" という解決策をよく見かけるが、これはセキュリティを完全に無効化する最終手段。ほとんどのケースはコンテキスト修正か Boolean の設定で解決できる。