RHELおよびRocky LinuxにおけるSELinux完全マスター:コンテキスト管理、ブール値設定、audit2allowによるアクセス拒否のトラブルシューティング

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

本番環境におけるSELinuxアクセス拒否の対処アプローチ比較

深夜2時、監視システムからアラートが発報されます。Rocky Linux 9上に新規デプロイしたNginxリバースプロキシがカスタムディレクトリから静的配信を行えず、403 Forbiddenや500 Internal Server Errorを返しています。従来のPOSIXパーミッションを確認しても、所有者はnginx:nginx、権限は0755で何の問題もありません。それにもかかわらず、デーモンはファイルにアクセスできません。この原因は、SELinux(Security-Enhanced Linux)による強制アクセス制御(MAC: Mandatory Access Control)の制限にあります。

障害発生時、エンジニアがSELinuxの拒否に対処する際にとるアプローチは主に以下の4つです。

  • アプローチ1: SELinuxの無効化(setenforce 0 または /etc/selinux/config の編集) — ホスト全体のMAC保護をすべて無効化する高リスクな近道です。エラーは即座に解消されますが、OSが無防備な状態に晒されます。
  • アプローチ2: SELinuxブール値(Boolean)の切り替え(setsebool -P) — Red Hatによって事前設定されたカーネルレベルのスイッチを切り替えます。リバースプロキシからポート8080のバックエンドソケットへの接続や、ポート5432の外部PostgreSQLインスタンスへのアクセスなど、一般的なワークフローを安全に許可できます。
  • アプローチ3: セキュリティコンテキストの再ラベリング(semanage fcontext + restorecon) — 永続的なファイルおよびディレクトリのラベルを更新し、デーモンが非標準パス(/data/web/ など)のファイル群にアクセスできるようにします。
  • アプローチ4: カスタムポリシーモジュールの生成(audit2allow) — AVC(Access Vector Cache)拒否ログを解析し、独自のデーモンや非標準のシステムコール向けに専用のType Enforcementモジュール(.pp)をコンパイルします。

秒間4,000リクエスト以上を処理する高トラフィックなRocky Linux 9ノードにおいて、SELinuxを無効化することは、コマンド1つでSOC2やPCI-DSSのコンプライアンス要件を損なう行為です。体系的なトラブルシューティングワークフローを実施することで、根本原因を特定し、最小限の適切な修正を適用して、本番環境のセキュリティ境界を安全に維持できます。

SELinux修正アプローチのメリット・デメリット

それぞれの修正方法には運用上の明確なトレードオフが存在します。各手法の比較は以下のとおりです。

手法 メリット デメリット 本番環境リスク
SELinuxの無効化 / Permissiveモード 重大な障害発生時に5秒以内でサービストラフィックを復旧可能。 カーネルレベルの隔離機能が失われ、パーミッションの設定ミスが隠蔽され、監査コンプライアンス(PCI-DSS、SOC2、HIPAAなど)に抵触する。 致命的(Critical)
SELinuxブール値(setsebool -P) ベンダー検証済みで再起動後も永続化され、ポリシーをコンパイルすることなく即時反映される。 アップストリームのポリシーメンテナーによって事前に想定・定義された動作のみに対応。 極小(Minimal)
コンテキストの再ラベリング(semanage + restorecon) 標準のTargetedポリシー定義を利用して、厳格な最小権限アクセスを適用できる。 ファイルコンテキストと正規表現パスパターンの理解が必要。 非常に低い(Very Low)
カスタムモジュール(audit2allow) 組み込みのブール値が存在しない自社製バイナリや独自エージェントのアクセス問題を解決できる。 フィルタリングされていないログから生成すると、意図せず危険な権限(広範なexecmemアクセスなど)を付与してしまうリスクがある。 中程度(Moderate)

推奨構成:段階的なトリアージ手順

本番サーバーをPermissiveモードのまま放置してはいけません。以下の4段階のエスカレーション手順に沿って対処してください。

  1. 監査ログの調査: ausearch を使用して /var/log/audit/audit.log を検索し、ブロックされたシステムコールを特定します。
  2. 既存ブール値の確認: 実行したい処理に対してRed Hatが既にブール値のスイッチを用意していないか確認します。
  3. ディレクトリとファイルのラベル修正: カスタム保存パスに適切なタイプコンテキスト(例:静的Webアセット用の httpd_sys_content_t)が付与されているか確認・修正します。
  4. カスタムモジュールの構築: ブール値やコンテキストの再ラベリングではデーモンの要件を満たせない場合にのみ、audit2allow を使用します。

実践ガイド:SELinuxアクセス拒否の診断と解決手順

ステップ1:AVC(Access Vector Cache)拒否の診断

まず、システムの現在の動作モードを確認します。

getenforce
# 出力: Enforcing

sestatus

エラーの原因が本当にSELinuxであるか確認するために、一時的にPermissiveモードへ切り替えて curl でエンドポイントをテストします。

# テスト用に一時的にPermissiveモードへ設定
setenforce 0

# 即座にアプリケーションをテスト。HTTP 200が返ればSELinuxが原因
curl -I http://127.0.0.1:80/

# 直ちにEnforcingモードへ戻す
setenforce 1

次に、監査ログから拒否の詳細を抽出します。

# 直近10分以内のAVC拒否ログを検索
ausearch -m AVC,USER_AVC -ts recent

# audit2whyで監査ログを解析し、根本原因の分かりやすい説明を出力
ausearch -c 'nginx' --raw | audit2why

audit2why は、難解なAVCメッセージを人間が理解できる具体的なアドバイスへと変換します。ブール値を有効化すべきか、ファイルラベルを修正すべきかを分かりやすく提示してくれます。

ステップ2:ファイルコンテキストの不一致の修正(semanage fcontext & restorecon)

サイトのデータを標準の /var/www/html ではなく /data/web/app1 などのカスタムパスに配置すると、ディレクトリには汎用的な default_t や var_t ラベルが継承されます。Nginxは httpd_t ドメインで動作するため、これらのラベルを持つファイルを読み取ることができません。

現在のセキュリティ属性を確認します。

ls -lZ /data/web/app1
# 出力: -rw-r--r--. 1 nginx nginx unconfined_u:object_r:default_t:s0 index.html

管理ツールをインストールし、SELinuxポリシーデータベースに適切なコンテキストルールを登録して、ファイルシステムに適用します。

# semanageが見つからない場合はpolicycoreutilsをインストール
dnf install -y policycoreutils-python-utils

# カスタムディレクトリに対する永続的なコンテキスト定義を登録
semanage fcontext -a -t httpd_sys_content_t "/data/web/app1(/.*)?"

# ディレクトリツリー全体にコンテキストを再帰的かつ詳細出力(verbose)で適用
restorecon -Rv /data/web/app1

# 更新されたコンテキストを確認
ls -lZ /data/web/app1
# 出力: -rw-r--r--. 1 nginx nginx unconfined_u:object_r:httpd_sys_content_t:s0 index.html

ステップ3:ブール値によるネットワーク通信の管理

デフォルトでは、Webデーモンはバックエンドのアプリケーションサーバー(ポート9000のPHP-FPMやポート8000のGunicornなど)やリモートデータベースへのネットワーク接続を開くことができません。SELinuxの初期設定では、これらのソケット操作が拒否されます。

Webサービスを制御する関連ブール値を検索します。

getsebool -a | grep httpd

必要なネットワークアクセス経路を有効化します。変更をディスク上の設定に永続化するため、必ず -P フラグを付与してください。

# Nginx/Apacheからアップストリームのネットワークバックエンドへのプロキシ接続を許可
setsebool -P httpd_can_network_connect 1

# Nginx/Apacheからデータベースサーバーへの直接接続を許可
setsebool -P httpd_can_network_connect_db 1

ステップ4:audit2allowによるカスタムポリシーモジュールの作成

独自のマイクロサービスや社内監視エージェント、サードパーティ製ソフトウェアは、デフォルトのブール値ではカバーされていない正当なシステムコールを実行する場合があります。このようなシナリオでは、audit2allow を使用して必要最小限のスコープに絞ったType Enforcementポリシーモジュールを作成します。

まず、コンパイル前に人間が読める形式のType Enforcement(.te)ルールをプレビューします。

# audit2allowが提案する正確な許可ルール(allow rules)を確認
ausearch -c 'custom_agent' --raw | audit2allow -m custom_agent

出力を慎重に確認し、サービスが真に必要としている特定のファイルアクセスやケーパビリティのみが許可されていることを確認してください。問題がなければ、Type Enforcementファイルとコンパイル済みバイナリパッケージ(.pp)の両方を生成します。

# custom_agent.te と custom_agent.pp を生成
ausearch -c 'custom_agent' --raw | audit2allow -M custom_agent

# ソースルールを最終確認
cat custom_agent.te

# コンパイルされたポリシーモジュールを稼働中のカーネルにロード
semodule -i custom_agent.pp

ステップ5:再起動後のポリシー永続性の検証

新しいポリシーモジュールがシステムのポリシーストアでアクティブになっていることを確認します。

semodule -l | grep custom_agent

通常のアプリケーション運用中に監査ログをリアルタイム監視し、すべての拒否エラーが解消されたことを確認します。

tail -f /var/log/audit/audit.log | grep -E "type=AVC.*denied"

永続的なファイルコンテキスト(semanage)、永続ブール値(setsebool -P)、および対象を絞ったポリシーパッケージ(semodule)を適切に組み合わせることで、RHELやRocky Linuxシステムはカーネルアップデートやシステムの再起動を経ても、強固なセキュリティ、安定性、完全なコンプライアンスを維持できます。

Share: