Linuxにおけるプロセス隔離手法の比較
サーバーからのデータ侵害インシデントの多くは、リモートコード実行(RCE)の脆弱性から始まります。従来のchmodやchownによる任意アクセス制御(DAC: Discretionary Access Control)には致命的な弱点があります。root権限で実行されているプロセスが乗っ取られた場合、攻撃者はサーバー全体の制御権を掌握してしまいます。
現在、最も広く採用されているアプローチは主に以下の3つです。
- SELinux (Security-Enhanced Linux): 米国国家安全保障局(NSA)によって開発された包括的な強制アクセス制御(MAC)機構。SELinuxはすべてのinode、プロセス、ソケットにラベル(Label)を付与します。主にRHEL/CentOS系で標準採用されています。
- AppArmor (Application Armor): ファイルパスベースで動作するMAC機構。UbuntuやSUSE Linuxにデフォルトで組み込まれています。
- コンテナによる隔離 (Docker/Podman): アプリケーションを独立したnamespacesおよびcgroups内にパッケージ化する手法。
各ソリューションの実際のメリット・デメリット
1. SELinux:多層防御を実現するものの設定が複雑
SELinuxはカーネルの各システムコールを厳密に制御します。しかし、バイナリ形式のセキュリティコンテキスト(ラベル)の仕組みにより、デバッグ作業に膨大な時間がかかります。例えば、rsyncでWebファイルをコピーした際にrestorecon -Rの実行を失念すると、パーミッションがchmod 755で正しく設定されていても、Nginxは即座にHTTP 403 Forbiddenエラーを返します。
2. コンテナ化:パッケージングには便利だがホスト層のセキュリティ代替にはならない
Dockerはデプロイ環境の標準化を迅速に行えます。しかし、コンテナはホストサーバーとカーネルを共有しています。runCのエスケープ脆弱性(CVE-2019-5736やCVE-2024-21626など)が発生した場合、攻撃者はコンテナ境界を突破してホストノードを掌握することが可能です。
3. AppArmor:直感的でメンテナンス性が高く、オーバーヘッドが極小
SELinuxとは異なり、AppArmorはバイナリの実行ファイルパス(例: /usr/sbin/nginx)に権限を直接紐付けます。プロファイルファイルはプレーンテキスト形式で記述されるため、複雑なセキュリティラベル体系を学習しなくても、直感的に設定内容を把握・変更できます。実環境におけるパフォーマンスオーバーヘッドも通常1.5%未満に収まります。
UbuntuでAppArmorを有効化すべきユースケース
以下のようなシチュエーションでは、直ちにAppArmorを活用すべきです。
- インターネットにポートを直接公開しているサービスの保護:Nginx、PHP-FPM、MySQL、BIND9など。
- サービスのアクティビティ範囲の厳格な固定。プロセスの
/etc/shadow読み取り防止、/tmpへの書き込み禁止、Webシェル混入時における/bin/bashシェルの起動阻止。 - 本番環境のサービスを停止させることなく、ベアメタルサーバーへゼロトラストセキュリティモデルを導入したい場合。
実践:AppArmorの導入・運用ステップ
1. 稼働状態の確認と関連ツールのインストール
Ubuntu 20.04/22.04/24.04 LTSでは、AppArmorがデフォルトで有効になっています。まず稼働状況を確認します。
sudo aa-status
出力結果には、enforce(違反をブロック)およびcomplain(警告ログのみ記録)モードのプロファイル数が表示されます。プロファイルの自動生成に必要な管理ツール群をインストールします。
sudo apt update && sudo apt install -y apparmor-utils apparmor-profiles
2. 鉄則:Enforceを適用する前に必ずComplainでテストする
本番稼働中の環境でいきなりEnforceモードを有効にしてはいけません。少なくとも24〜48時間はComplainモードでアプリケーションを運用し、定期的なバッチ処理などを含むすべての動作ログを収集してください。
- Complainモード: ルール違反が発生してもプロセスはブロックされず正常に実行を継続し、監査ログ(Audit Log)のみを記録します。
- Enforceモード: プロファイルに明示的に許可されていないすべての動作を即座にブロックします。
特定のサービスに対してモードを切り替えるコマンド:
# 監視(学習)モードへ切り替え
sudo aa-complain /usr/sbin/mysqld
# 強制ブロックモードへ切り替え
sudo aa-enforce /usr/sbin/mysqld
3. aa-genprofによるプロファイルの自動生成
例えば、/usr/local/bin/payment-apiに配置されたGoやPython製の決済APIを保護したいとします。ゼロから手作業で設定を書く代わりに、aa-genprofを使用してアプリケーションの動作を学習させます。
sudo aa-genprof /usr/local/bin/payment-api
このターミナルを開いたまま、別のターミナルウィンドウを開いてHTTPリクエスト送信、DBアクセス、ログ出力など、想定されるテストシナリオを一通り実行します。aa-genprofのターミナルに戻り、Sキーを押してログをスキャンします。ツールが各リソースへのアクセス権限について対話形式で尋ねてきます。
(A)llow: ファイルまたはソケットへのアクセスを許可。(D)eny: アクセスを明示的に拒否。(G)lob: ワイルドカードパターン(例:/var/log/payment/*.log)で許可。
設定が完了したらFキー(Finish)を押し、プロファイルを/etc/apparmor.d/ディレクトリへ保存します。
4. 標準プロファイルの構造解析
AppArmorのすべてのルールは/etc/apparmor.d/配下に格納されます。以下はNginxを保護するための標準的な設定例(抜粋)です。
#include <tunables/global>
/usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/ssl_certs>
# メインバイナリの実行権限
/usr/sbin/nginx mr,
# 設定ファイルおよびSSL証明書の読み取りのみを許可
/etc/nginx/** r,
/etc/ssl/certs/** r,
# ログおよびキャッシュの書き込み範囲を制限
/var/log/nginx/* w,
/var/cache/nginx/** rw,
# Webサーバーに悪意あるコードが注入された場合のシェル実行を完全遮断
deny /bin/sh mrpx,
deny /bin/bash mrpx,
deny /bin/dash mrpx,
deny /usr/bin/python* mrpx,
}
主なアクセス権限フラグの意味:
r: 読み取り権限。w: 書き込みまたは新規ファイル作成権限。m: バイナリのメモリマッピング権限(.so共有ライブラリで必須)。k: ファイルロック権限(データベースやpidファイルで多用)。px: 独立したAppArmorプロファイル配下でのプログラム実行。deny: 明示的な拒否ルール。allowルールに関わらず常に最優先で適用されます。
5. カーネルへの設定リロード
/etc/apparmor.d/内のプロファイルを編集した後は、新しいプロファイルをLinuxカーネルに再読み込みさせます。
# 特定のプロファイルを再読み込み
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
# またはAppArmorサービス全体をリロード
sudo systemctl reload apparmor
6. 誤ブロック発生時のトラブルシューティング
chmod 777で権限を付与したにもかかわらず、アプリケーションが500 Internal Server ErrorやPermission deniedを返していませんか?AppArmorが許可されていないシステムコールをブロックした可能性があります。直ちにカーネルログを確認してください。
sudo dmesg -T | grep -i apparmor
# またはjournalctlを使用してブロックイベントのみを正確に抽出:
sudo journalctl -k -g "apparmor=\"DENIED\"" -n 50
ファイルを直接編集せずにログから自動で権限を追加・更新するには、aa-logprofを使用します。
sudo aa-logprof
このユーティリティは直近の違反ログを読み取ります。プロンプトに従ってA(Allow)を押すだけで正規の操作として承認され、サービスの再起動を伴わずにプロファイルが即座に更新・反映されます。

