SELinux/AppArmorによる強制アクセス制御(MAC)の極意:カーネル空間で侵入者を封じ込める防衛アーキテクチャ
インフラストラクチャのセキュリティ設計において、私たちは長年にわたり「境界防御」の幻想と戦ってきた。ファイアウォールを固め、WAFを配置し、IDS/IPSでシグネチャを監視する。しかし、ひとたびWebアプリケーションのゼロデイ脆弱性や、依存ライブラリのRCE(リモートコード実行)によって初期侵入を許した瞬間、従来のDAC(自主的アクセス制御:オーナー・グループ・その他)の世界は崩壊する。攻撃者はwww-dataやnginxといったプロセス権限を奪い取り、その権限の範囲内で自由に動き回る。 /etc/passwdを読み漁り、内部ネットワークへのピボット(踏み台)の足がかりを探すのだ。
ここでDACの限界が露呈する。root権限でなければ安全、という神話はすでに過去のものだ。プロセスのUIDが非特権であっても、カーネル空間におけるリソースへのアクセスを制御できなければ、システム全体の陥落は時間の問題である。
だからこそ、我々セキュリティアーキテクトは強制アクセス制御(MAC:Mandatory Access Control)、すなわち SELinux(Security-Enhanced Linux) や AppArmor の実装に立ち返らなければならない。これは「侵入されることを前提とした多層防御」の最後の砦であり、カーネルの奥底でプロセスを縛り上げる鉄の枷である。
—
DACの限界とMAC(強制アクセス制御)の本質
従来のDACは、ファイルやソケットの「誰が所有しているか」に基づいてアクセスを許可する。プロセスがどのコンテキストで実行されているか、どのような経路で起動されたかは考慮されない。例えば、Apacheが何者かによって改ざんされ、任意のシェルコードを実行させられた場合、そのプロセスはapacheユーザーがアクセスできるすべてのファイル(設定情報やデータベースの認証情報を含む)にアクセス可能になる。
一方、MACであるSELinuxやAppArmorは、プロセス(Subject)とリソース(Object)のすべてのインタラクションを、セキュリティポリシーに基づいて強制的に仲介する。
- SELinux (Type Enforcement): プロセスごとに「ドメイン」、ファイルやポートごとに「タイプ(コンテキスト)」を割り当て、ドメインがアクセスしてよいタイプを厳密にマトリクス定義する。たとえroot権限を持つプロセスであっても、ポリシーで許可されていない限り、特定のファイルを読むことはできない。
- AppArmor (Path-based MAC): プロセスが使用する実行ファイルの「パス」をベースにして、アクセス可能なファイルパスやネットワーク操作をプロファイルとして定義する。SELinuxに比べて学習コストが低く、Debian系ディストリビューションで広く採用されている。
現場のインフラエンジニアから「SELinuxは面倒だから無効化する(setenforce 0)」という声を未だに聞くが、それは施錠された頑丈な金庫の扉を開け放ち、「誰も盗まないはずだ」と祈るようなものだ。本稿では、実務の現場で直面するトラブルシューティングを踏まえつつ、このMACを本番環境で確実に稼働させるための実践知を共有する。
—
Red Hat系におけるSELinux要塞化とポリシーチューニング
RHELやCentOS、AlmaLinuxなどのEnterprise Linux環境では、SELinuxが標準の防壁として機能する。しかし、デフォルトのポリシー(targetedなど)だけでは、カスタムアプリケーションや特殊なストレージ構成に対応しきれず、監査ログ(/var/log/audit/audit.log)が拒否ログの嵐になることがある。
ここで、インシデントハンドリングの現場で役立つ、SELinuxの監査とポリシー生成のワークフローを示す。
1. 現在のステータスとモードの確認
まずはシステムが本当にEnforcingモードで稼働しているかを確認する。
# SELinuxの全体ステータスを確認
sestatus
# 期待される出力例:
# SELinux status: enabled
# SELinuxfs mount: /sys/fs/selinux
# Current mode: enforcing <-- ここが enforcing であること
# Mode from config file: enforcing
# Policy version: 33
# Policy from loaded types: targeted
2. 拒否ログの解析とカスタムポリシー(モジュール)の生成
もしアプリケーションが予期せぬ動作でブロックされた場合、audit2allowツールを用いて原因を特定し、必要最小限の許可ルール(カスタムポリシーモジュール)を作成する。
# 直近のSELinux拒否イベントを抽出して人間が読める形式に変換
grep AVC /var/log/audit/audit.log | audit2why
# 出力された拒否理由をもとに、許可ルール(.teファイル)のドラフトを自動生成する
grep httpd /var/log/audit/audit.log | audit2allow -M my_httpd_custom
# 生成されたモジュールファイルの内容(my_httpd_custom.te)を確認
cat my_httpd_custom.te
生成された.teファイル(Type Enforcementファイル)の中身は、以下のような構造になっている。セキュリティレビューを行う際は、この定義が広すぎないか(例:過剰なrw_file_permsの付与がないか)を必ず精査すること。
“`type-enforcement
module my_httpd_custom 1.0;
require {
type httpd_t;
type var_log_t;
class dir { add_name write };
class file { create open write };
}
警告: 以下のルールはhttpdドメインに独自のログディレクトリへの書き込みを許可する例
必要最小限のパスに限定されているか、コンテキストが正しく付与されているかを必ず確認すること
allow httpd_t var_log_t:dir { add_name write };
allow httpd_t var_log_t:file { create open write };
作成したカスタムポリシーをシステムにロードする。
bash
バイナリポリシーパッケージ(.pp)をロードする
semodule -i my_httpd_custom.pp
ロードされたカスタムモジュールがリストに含まれているか確認
semodule -l | grep my_httpd_custom
### 3. ファイルコンテキストの永続的な修正(Fcontext)
カスタムアプリケーションが非標準のディレクトリ(例:`/opt/myapp/data`)にデータを配置する場合、単にパーミッションを合致させるだけでは不十分で、SELinuxのファイルコンテキスト(ラベル)を正しく設定する必要がある。
bash
/opt/myapp/data 配下のファイルに httpd_sys_content_t コンテキストを再帰的に割り当てる
semanage fcontext -a -t httpd_sys_content_t “/opt/myapp/data(/.*)?”
実際のファイルシステムにラベルを適用(レストア)する
restorecon -R -v /opt/myapp/data
---
## Debian/Ubuntu系におけるAppArmorプロファイルの実装
UbuntuやDebian環境では、AppArmorがデフォルトのMACとして動作する。SELinuxが「タイプ」ベースであるのに対し、AppArmorは「ファイルパス」ベースで制御するため、開発者やインフラエンジニアにとって直感的に理解しやすいというメリットがある。
例えば、NginxやPHP-FPM、あるいは特定のコンテナランタイムに対して厳格なプロファイルを作成し、ファイルシステムの特定領域へのアクセスを完全に遮断する手順を見ていこう。
### 1. AppArmorのステータス確認
bash
現在稼働しているプロファイルのステータスを確認
aa-status
出力例(一部抜粋):
50 profiles are loaded.
36 profiles are in enforce mode.
14 profiles are in complain mode. <-- 警告モード(ログのみ出力しブロックしない)
### 2. プロファイルの作成とコンプレイン(学習)モードの活用
新規に導入したカスタムバイナリ(例:`/usr/local/bin/secure-api-server`)に対するプロファイルをゼロから書くのは容易ではない。そのため、まずは**コンプレインモード**で稼働させ、実際の挙動を学習させるアプローチをとる。
bash
プロファイルを作成し、コンプレインモード(違反を検知してもブロックしない)で有効化
aa-complain /usr/local/bin/secure-api-server
アプリケーションを稼働させ、通常業務のトラフィックを流し込んだ後、ログからプロファイルを生成する
aa-genprof /usr/local/bin/secure-api-server
### 3. プロファイルの記述例と実務上の注意点
生成された、あるいは手動でチューニングされたAppArmorプロファイル(`/etc/apparmor.d/usr.local.bin.secure-api-server`)の実例を以下に示す。
apparmor
include
/usr/local/bin/secure-api-server のためのAppArmorプロファイル
/usr/local/bin/secure-api-server flags=(attach_disconnected) {
#include
#include
# 実行バイナリ自体の読み込みと実行を許可
/usr/local/bin/secure-api-server mr,
# 設定ファイルは読み込みのみ許可(書き込みは絶対に禁止)
/etc/secure-api/config.json r,
# ログ出力先への書き込みを許可
/var/log/secure-api/ w,
/var/log/secure-api/** rw,
# 一時ファイル領域の利用を許可(ただし実行権限は剥奪)
/tmp/sec-api-* rw,
deny /tmp/*.sh x, # 万が一シェルスクリプトが生成されても実行させない
# ネットワーク通信の許可(TCP/UDPソケットの作成)
network tcp,
network udp,
# システム全体の不要な領域へのアクセスを明示的に拒否(Deny rule)
deny /etc/shadow r,
deny /root/** rwk,
}
作成したプロファイルをEnforcing(強制)モードに切り替えるには、以下のコマンドを実行する。
bash
プロファイルを強制モードへ移行
aa-enforce /usr/local/bin/secure-api-server
設定を即時リロード
systemctl reload apparmor
---
## インシデントレスポンスとトラブルシューティングの極意
本番環境でMACを有効化した直後に、アプリケーションが突然エラーを吐き出す光景は、すべてのセキュリティエンジニアが通る道である。その際、パニックになって「とりあえずSELinuxを無効化する」という選択肢を取ってはならない。プロフェッショナルは、的確なログ解析から原因を即座に特定し、ポリシーを修正する。
### 1. 監査ログのリアルタイム監視
問題切り分けの際、別ターミナルで以下のコマンドを立ち上げてリアルタイムに拒否イベントを監視するのが鉄則だ。
* **SELinuxの場合:**
bash
tail -f /var/log/audit/audit.log | grep AVC
# または sealert ツールで詳細な原因と対処法を表示
sealert -a /var/log/audit/audit.log
* **AppArmorの場合:**
bash
journalctl -k -f | grep DENIED
# または
tail -f /var/log/syslog | grep apparmor=”DENIED”
### 2. コンテナ環境におけるMACの重要性
KubernetesやDockerなどのコンテナ環境においても、SELinux(sVirt)やAppArmorはコンテナエスケープ攻撃を防ぐための極めて強力な防衛線となる。
例えば、KubernetesのPod定義(SecurityContext)において、特定のAppArmorプロファイルやSELinuxオプションを強制することで、ホストカーネルへの不正なアクセスを根絶できる。
yaml
apiVersion: v1
kind: Pod
metadata:
name: hardened-api-pod
annotations:
container.apparmor.security.beta.kubernetes.io/api-container: k8s-apparmor-custom-profile
spec:
containers:
- name: api-container
image: my-secure-api:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# SELinuxOptionsを用いたプロセスごとのコンテキスト分離
seLinuxOptions:
level: “s0:c123,c456”
role: “system_r”
type: “container_t”
user: “system_u”
“`
—
結びに代えて:侵入を前提とした強靭なアーキテクチャへ
ゼロトラストセキュリティの基本原則は「境界の内側も信用しない」ことである。Webアプリケーションの脆弱性やサプライチェーン攻撃により、いつ、どこから侵入されるかを完全に防ぐことは現代のサイバー脅威のトレンドにおいて不可能に近い。
しかし、「侵入された後、攻撃者が何ができるか」をカーネルレベルで完全にコントロールすることは可能である。SELinuxやAppArmorによる強制アクセス制御(MAC)の実装は、単なる「設定作業」ではない。それは、システム全体の脆弱性リスクを計算に入れ、最悪のシナリオ(RCEや権限昇格)が発生した瞬間に被害を最小限に抑え込むための、最高峰の防衛アーキテクチャそのものである。
面倒なエラーログに怯えるのではなく、カーネルの文脈を掌握し、プロセスを緻密に縛り上げる。それこそが、真のインフラストラクチャ・セキュリティを担保するプロフェッショナルの姿勢である。
コメント