なぜ標準的なLinux権限だけでは不十分なのか
標準的なLinuxのセキュリティは、任意アクセス制御(DAC)を使用しています。このシステムは、ユーザー、グループ、および基本的な権限(rwx)に依存しています。Webサーバーのプロセスがwww-dataとして実行されている場合、そのユーザーが所有するすべてのファイルにアクセスできてしまいます。これは大きな死角となります。もし攻撃者がPHPコードの脆弱性を突いた場合、それらの権限をそのまま引き継いでしまいます。その結果、設定ファイルを盗み見られたり、ソースコードを読み取られたり、一時ディレクトリから機密データを持ち出されたりする可能性があります。
数年前、自身のサーバーが深夜にSSHのブルートフォース攻撃を受けた際、サーバーの強化戦略を考え直す必要性を感じました。玄関を閉めるだけでは不十分だと気づいたのです。侵入者が中に入ったとしても、小さな何もない部屋に閉じ込めておく必要があります。これが強制アクセス制御(MAC)です。Ubuntuにおいて、AppArmorはこの役割を担う主要なツールです。
AppArmorは、プログラムが何にアクセスできるかを正確に定義します。/etc/passwdを読み取れるか? /tmpに書き込めるか? ネットワークソケットを開けるか? アクションがAppArmorプロファイルで明示的に許可されていない場合、カーネルがそれをブロックします。これは、プロセスを実行しているユーザーがそのアクションを実行する完全な権限を持っていたとしても行われます。
AppArmorのプロファイルとモードを理解する
AppArmorはプロファイルを使用します。これらは/etc/apparmor.d/に保存されるプレーンテキストファイルです。複雑なラベルを使用するSELinuxとは異なり、AppArmorはパスベースです。例えば、Nginx用のプロファイルは/etc/apparmor.d/usr.sbin.nginxに配置されます。
設定を変更する前に、2つの主要なモードを理解しておく必要があります:
- Enforce(強制): カーネルがポリシーを厳格に適用します。許可されていない試行はすべてブロックされ、ログに記録されます。
- Complain(不平): ポリシーは強制されません。アプリケーションは制限なく動作しますが、AppArmorはブロックされるはずだったすべてのアクションをログに記録します。このモードは、本番サービスを停止させることなく新しいプロファイルをテストするために不可欠です。
現在のセキュリティステータスの確認
Ubuntu 22.04や24.04のインストールの多くでは、デフォルトでAppArmorが有効になっています。通常、すでに30〜50のプロファイルがアクティブになっています。次のコマンドでステータスを確認してください:
sudo aa-status
これにより、ロードされているプロファイルの概要と、現在制限されているプロセスを把握できます。
実践:カスタムPythonアプリケーションの保護
理論的なシステムサービスの話はここまでにして、実際にシンプルなPythonスクリプトを保護して、その仕組みを見ていきましょう。設定ファイルを読み込み、ログを追記するだけのスクリプトを想定します。
1. ツールキットのインストール
Ubuntuにはコアエンジンが含まれていますが、プロファイル生成ツールは追加のパッケージにあります。作業を簡単にするために、これらをインストールしましょう:
sudo apt update
sudo apt install apparmor-utils apparmor-profiles
2. 対象アプリケーションの作成
このスクリプトを/usr/local/bin/myapp.pyに保存します:
#!/usr/bin/python3
# 特定の設定ファイルを読み込み、ログに書き込むスクリプト
with open("/data/config.txt", "r") as f:
print(f.read())
with open("/var/log/myapp.log", "a") as log:
log.write("アクセスが記録されました\n")
実行権限を設定します:sudo chmod +x /usr/local/bin/myapp.py
3. プロファイルの自動生成
aa-genprofユーティリティを使用すると、作成プロセスが簡略化されます。これはプロファイルをComplainモードに設定し、アプリケーションの動作を監視します。
sudo aa-genprof /usr/local/bin/myapp.py
ツールが実行されている間に、別のターミナルを開いてスクリプトを実行します:/usr/local/bin/myapp.py。その後、最初のターミナルに戻り、Sキーを押してログをスキャンします。ユーティリティは、検出されたアクションを許可するか拒否するかを尋ねてきます。このスクリプトの場合、Pythonインタプリタ、設定ファイル、およびログファイルへのアクセスを許可してください。
4. プロファイルの微調整
自動ツールでは範囲が広すぎることがあります。/etc/apparmor.d/usr.local.bin.myapp.pyにあるファイルを直接編集できます。整理されたプロファイルは以下のようになります:
#include <tunables/global>
/usr/local/bin/myapp.py {
#include <abstractions/base>
#include <abstractions/python>
/usr/bin/python3.[0-9]* ix,
/data/config.txt r,
/var/log/myapp.log w,
}
各フラグの意味は以下の通りです:
r: 読み取りアクセス。w: 書き込みアクセス。ix: ファイルを実行し、現在のセキュリティプロファイルを継承する。
管理とトラブルシューティング
プロファイルをいきなりEnforceモードに移行するのは避けましょう。少なくとも24時間はComplainモードで運用することをお勧めします。これにより、週次のcronジョブやログローテーションスクリプトなど、誤検知を引き起こす可能性のあるエッジケースを把握できます。
モードの切り替え
テストのためにComplainモードに切り替えるには:
sudo aa-complain /etc/apparmor.d/usr.local.bin.myapp.py
アプリケーションが正しく動作することが確実になったら、制限を適用します:
sudo aa-enforce /etc/apparmor.d/usr.local.bin.myapp.py
ログの解釈
AppArmorのブロックはカーネルレベルで発生します。ファイル権限が正しく見えても、アプリケーションは単に「Permission Denied(権限がありません)」と表示する場合があります。本当の原因を突き止めるには、システムログを確認してください:
sudo tail -f /var/log/syslog | grep -i apparmor
DENIEDというメッセージを探します。正当なアクションがブロックされているのを見つけた場合は、aa-logprofを実行してください。これはログを読み取り、プロファイルルールを自動的に更新するよう促してくれます。
本番環境でのベストプラクティス
セキュリティポリシーの管理を苦行にする必要はありません。以下の3つのルールに従ってください:
- アブストラクション(抽象化)を活用する:
#include <abstractions/base>ディレクティブを使用しましょう。これらは一般的なシステムライブラリ用の事前定義されたスニペットです。これにより、プロファイルが数百行に膨れ上がるのを防げます。 - 露出部分に集中する: すべてのバイナリをサンドボックス化する必要はありません。Nginx、メールサーバー、カスタムAPIなど、インターネットに公開されているサービスを優先してください。これらは攻撃者にとって最も可能性の高い侵入経路です。
- バックアップを取ってから更新する:
aa-logprofを実行する前に、既存のプロファイルをコピーしておきましょう。自動ツールは時として寛容すぎるルールを提案することがありますが、バックアップがあれば簡単に元に戻せます。
最後に
AppArmorは強力な多層防御戦略を提供します。単純なファイル権限を超えてアプリケーションをサンドボックス化することで、攻撃者が与えるダメージを最小限に抑えることができます。プロファイルの洗練には時間がかかりますが、それだけの価値があるセキュリティが得られます。Webサーバーが物理的にバックアップフォルダに触れることができないと知っていることは、計り知れない安心感をもたらします。

