アプローチの比較:DAC vs. SELinux vs. AppArmor
6か月前、私たちのチームはゼロデイ脆弱性からPythonやNode.jsのマイクロサービスを保護するため、45台の本番サーバーに強制アクセス制御(MAC)ポリシーを導入しました。従来のLinuxセキュリティは、標準的なファイル権限(chmod、chown)やユーザーグループによる任意アクセス制御(DAC)にとどまっていました。
しかし、そのモデルには致命的な盲点があります。攻撃者がwww-dataのようなサービスアカウント内でリモートコード実行(RCE)を成功させた場合、DACだけでは封じ込めることができません。攻撃者はそのアカウントが持つすべてのファイル読み取り権限を継承し、/tmpにペイロードスクリプトを書き込み、ローカルのカーネル脆弱性を探索できてしまいます。
最新のLinuxディストリビューションをMACレイヤーで堅牢化する場合、主に2つのフレームワークが有力な選択肢となります。
- SELinux (Security-Enhanced Linux): inodeベースのラベリングを使用し、ファイル、プロセス、ソケットにセキュリティコンテキストを付与します。RHEL、Rocky Linux、Fedora環境で広く使われています。しかし、SELinuxポリシーをゼロから作成するには、難解なマクロ言語の習得や複雑なタイプ遷移のデバッグが必要です。
- AppArmor (Application Armor):
/usr/bin/nginxや/opt/api/serverといった実行可能なファイルシステムパスにセキュリティプロファイルを直接バインドする、パスベースのアクセス制御を採用しています。プロファイルはプレーンテキストであり、/etc/apparmor.d/配下に保存されるため、監査も容易です。
DebianやUbuntu環境において、AppArmorはポリシーをコンパイルするためだけの専任セキュリティチームを必要とせず、デーモンを分離するための最も迅速な手段を提供します。
メリットとデメリット:本番運用6か月の知見
高スループットな本番ノードでAppArmorを運用した結果、確実な封じ込め効果が得られた一方で、把握しておくべき運用上の注意点もいくつか見えてきました。
メリット
- 人間が読みやすいルール:ルールは標準的なグロブ(ワイルドカード)や、
r(読み取り)、w(書き込み)、ix(実行権限の継承)といった明確な権限フラグに基づいています。シェルのワイルドカードに慣れているエンジニアであれば、数分でプロファイルを監査できます。 - 対話型の学習モード:
aa-genprofやaa-logprofなどのユーティリティが監査ログを解析し、実稼働中に検出されたアクセスパスに対して許可、拒否、グロブ化を行う対話型プロンプトを提供します。 - オーバーヘッドがほぼゼロのサンドボックス化:AppArmorはカーネル内のLinux Security Modules(LSM)に直接フックします。
wrkを使用した50,000リクエスト/秒の合成ベンチマークでは、レイテンシのオーバーヘッドは0.8%未満にとどまり、測定可能なメモリフットプリントの増加もありませんでした。
デメリット
- パスへの依存性:AppArmorは絶対パスを対象とするため、シンボリックリンク、バイナリのリネーム、ハードリンク、未マッピングのchroot環境などは、事前に対策を記述しておかないとプロファイルのマッチングを回避されたり破損したりする可能性があります。
- L3/L4ネットワークフィルタリングの非対応:AppArmorはプロトコルファミリの制限(例: rawパケットソケットをブロックしつつ
tcpを許可するなど)は行えますが、IPアドレスや宛先ポートによるフィルタリングはできません。パケットフィルタリングには依然としてnftablesやiptablesが必要です。
推奨セットアップ
Ubuntu 22.04またはDebian 12で信頼性の高いサンドボックス環境を構築するには、コアツールをインストールしてカーネル監査デーモンを有効化します。
# AppArmorユーティリティとauditデーモンのインストール
sudo apt update
sudo apt install -y apparmor apparmor-utils auditd
# AppArmorカーネルモジュールのステータス確認
sudo aa-status
テストされていないプロファイルをいきなり強制適用モード(enforce mode)に投入することは避けてください。厳格すぎるポリシーは、深夜3時のバックグラウンドログローテーションを停止させたり、ヘルスチェックプローブを強制終了させたり、一時ファイルの作成を妨害したりすることがよくあります。新しいプロファイルは、強制適用する前に通常のトラフィック下で少なくとも48〜72時間はcomplainモード(警告モード)で運用してください。
実践ガイド:カスタムAppArmorプロファイルの作成
実践的なデプロイ例として、/opt/api/server.pyに配置されたカスタムFastAPIワーカーのサンドボックス化を考えてみましょう。このアプリケーションは、JSON設定の読み取り、TCPソケットへのバインド、ログフォルダへの書き込みを行う必要があります。一方で、/etc/shadowへのアクセス、ユーザーのホームフォルダの参照、対話型シェルの起動などは絶対に許可してはなりません。
ステップ1:アプリケーションの起動スクリプト(スタブ)の定義
サービスが/usr/local/bin/myapiなどの固定されたエントリポイントスクリプト経由で実行されるようにします。
sudo chmod +x /usr/local/bin/myapi
ステップ2:aa-genprofによるプロファイルの初期化
プロファイルジェネレーターをcomplainモードで起動し、カーネルの監査イベントを監視します。
sudo aa-genprof /usr/local/bin/myapi
このターミナルを開いたままにしておきます。別のセッションから、実際のHTTPリクエスト送信、テストスイートの実行、ログのローテーション、バックグラウンドタスクの実行など、通常のアプリケーションワークフローを発生させます。AppArmorはすべてのシステムコールをキャプチャし、要求されたパスを/var/log/audit/audit.logに記録します。
ステップ3:プロファイル構文の確認と精査
aa-genprofのセッションに戻り、Sキーを押して監査ログをスキャンします。ユーティリティに対話型プロンプトが表示され、検出されたファイルパスに対して許可、拒否、グロブ化を選択できます。生成された設定ファイルは/etc/apparmor.d/usr.local.bin.myapiに保存されます。
以下は、本番環境向けに整理・堅牢化されたプロファイルの例です。
# /etc/apparmor.d/usr.local.bin.myapi
#include <tunables/global>
/usr/local/bin/myapi {
# ベースの抽象化設定
#include <abstractions/base>
#include <abstractions/python>
#include <abstractions/nameservice>
# ネットワークアクセス
network inet tcp,
network inet udp,
# インタープリタとエントリポイント
/usr/bin/python3* ix,
/usr/local/bin/myapi r,
# アプリケーションソースと設定ファイル
/opt/api/ r,
/opt/api/** r,
/opt/api/config.json r,
# ログおよび一時実行用ストレージ
/var/log/myapi/ w,
/var/log/myapi/** rw,
/tmp/myapi_*.tmp rw,
# 機密パスとシェル起動の明示的なブロック
deny /etc/shadow* rwklx,
deny /etc/gshadow* rwklx,
deny /root/** rwklx,
deny /home/** rwklx,
deny /bin/dash rx,
deny /bin/bash rx,
deny /usr/bin/sh rx,
}
ステップ4:プロファイルの再読み込みと強制適用の有効化
更新したルールをカーネルに直接反映させ、厳格な強制適用(enforce)モードを有効にします。
# プロファイルルールを解析して再読み込み
sudo apparmor_parser -r /etc/apparmor.d/usr.local.bin.myapi
# プロファイルをenforceモードに切り替え
sudo aa-enforce /usr/local/bin/myapi
# 強制適用が有効になっていることを確認
sudo aa-status | grep myapi
ステップ5:サンドボックス化と封じ込めのテスト
アプリケーションのコンテキスト内から不正な操作を試みることで、サンドボックスがラテラルムーブメント(侵入拡大)を阻止できることを検証します。
# カーネルログでアクセス拒否を確認
sudo dmesg | grep -i "apparmor.*denied"
# またはauditd経由で直近のAVC拒否ログを照会
sudo ausearch -m AVC -ts recent
攻撃者がRCEの脆弱性を悪用した場合でも、/bin/bashの起動や機密ディレクトリの参照を試行すると、カーネルレベルで即座にEACCES(Permission Denied)エラーが発生します。攻撃は即座に阻止され、root認証情報を危険にさらすことなく監査ログに記録が残ります。

