手当たり次第に書くんだ

飽きっぽいのは本能

SELinux と AppArmor は何が違うのか – 無効化されやすい Linux のアクセス制御を設計思想から理解する

Linux を利用していると、SELinux や AppArmor という名前を目にすることがあります。 RHEL 系ディストリビューションでは SELinux、Ubuntu では AppArmor が標準的に利用されています。どちらも Linux のセキュリティを強化する仕組みですが、運用現場では次のように扱われることも少なくありません。

  • SELinux が原因で動かないため無効化する
  • AppArmor を complain モードにしたまま運用する
  • セキュリティ機能であることは知っているが、何を制御しているかは分からない

これは、単に管理者の知識が不足しているために起きる問題ではありません。 SELinux や AppArmor は、通常の所有者、グループ、パーミッションとは異なる判断基準を Linux へ追加します。そのため、従来のアクセス制御だけを見ていると、拒否された理由が見えにくくなります。 本記事では、Linux のアクセス制御を DAC と MAC から整理した上で、SELinux と AppArmor の違いを解説します。 単なる機能比較ではなく、なぜこれらの仕組みが無効化されやすいのか、その運用上の難しさがどの設計思想から生じているのかまで掘り下げます。

Linux の標準的なアクセス制御は DAC である

Linux で通常利用するファイルパーミッションは、DAC(Discretionary Access Control:任意アクセス制御)に分類されます。 例えば、次のようなパーミッションです。 -rwxr-x--- Linux では、ファイルやディレクトリに対する権限を、主に次の区分で管理します。

  • 所有者
  • グループ
  • その他のユーザー

ACL を利用すれば、特定のユーザーやグループへ、より細かな権限を追加することもできます。 DAC は柔軟で分かりやすい仕組みですが、アプリケーションが侵害された場合には限界があります。 例えば、Web サーバープロセスの脆弱性を悪用され、攻撃者に任意のコードを実行されたとします。 この場合、攻撃者は Web サーバープロセスに付与された DAC 上の権限を利用できます。プロセスから読み取れるファイルは攻撃者からも読み取れ、書き込める場所には不正なファイルを作成される可能性があります。 DAC が判断するのは、主に次の関係です。

  • 実行ユーザーの UID・GID
  • 対象の所有者・グループ・パーミッション・ACL

しかし、DAC だけでは次のような判断は困難です。

DAC だけでは、Web サーバープロセスである以上、DAC 上は読めるファイルであってもアクセスさせない、という用途に基づく制御は困難です。

そこで必要になるのが、DAC とは別の判断基準です。

MAC は DAC を通過したアクセスをさらに制限する

SELinux と AppArmor は、どちらも MAC(Mandatory Access Control:強制アクセス制御)を実現する仕組みです。 DAC では、ファイル所有者などがアクセス権を設定します。 これに対して MAC では、システムに定義されたセキュリティポリシーがアクセスの可否を判断します。 ここで重要なのは、DAC と MAC が完全に並列で評価されるわけではないことです。 Linux では、まず DAC による判定が行われます。DAC で拒否された場合、その時点でアクセスは失敗し、SELinux のポリシー判定まで進みません。

  • アクセス要求
  • DAC による判定
  • 拒否 → アクセス失敗
  • 許可
  • MAC による判定
  • 拒否 → アクセス失敗
  • 許可 → アクセス成功

そのため、SELinux の AVC ログが記録されていない場合、SELinux より前に DAC で拒否されている可能性があります。 MAC は DAC の代わりになるものではありません。 DAC を通過したアクセスに対して、適用されるポリシーとドメインに応じた追加制約を加える仕組みです。 ただし、SELinux が有効であれば、システム上のすべてのプロセスが同じ強度で制約されるわけではありません。 RHEL 系ディストリビューションで標準的に利用される targeted ポリシーでは、主にネットワークサービスなど、保護対象として選ばれたプロセスが個別のドメインへ閉じ込められます。一方、多くの一般的なユーザープロセスや、専用ポリシーが用意されていないプロセスは、unconfined_t などの非制約ドメインで動作します。 概念的には、次のように分かれます。

  • confined なプロセス
  • 例:httpd_t、named_t など
  • 用途ごとに定義された SELinux ポリシーで制約される
  • unconfined なプロセス
  • 例:unconfined_t
  • SELinux は有効だが、広い操作が認められる

したがって、SELinux が Enforcing であることと、すべてのプロセスが厳密に閉じ込められていることは同じではありません。 本記事では、主に targeted ポリシーによって明示的に制約されているプロセスを前提として説明します。

SELinux はラベルの関係を基準に判断する

SELinux では、プロセスやファイルなどへセキュリティコンテキストと呼ばれるラベルを付与します。 現在のプロセスへ付与された SELinux ドメインは、次のように確認できます。

ps -eZ

例えば、Apache HTTP Server などのプロセスは、通常、次のようなドメインで動作します。 httpd_t Web コンテンツ用のファイルには、次のようなセキュリティコンテキストが付与されます。 system_u:object_r:httpd_sys_content_t:s0 このうち、一般的な Type Enforcement で特に重要なのが、次のタイプです。 httpd_sys_content_t SELinux の Type Enforcement では、概念的に次の要素を組み合わせてアクセスを判断します。

  • ソースタイプ
  • ターゲットタイプ
  • オブジェクトクラス
  • 要求されたパーミッション

例えば、次のような組み合わせです。

  • ソースタイプ httpd_t
  • ターゲットタイプ httpd_sys_content_t
  • オブジェクトクラス file
  • パーミッション read

この組み合わせに対してポリシー上の許可が存在すれば、読み取りが認められます。 これは無数にあるルールの一例であり、httpd_thttpd_sys_content_t が単純な一対一対応になっているわけではありません。 また、このような細かな Type Enforcement の効果が明確に現れるのは、httpd_t のような confined ドメインで動作するプロセスです。unconfined_t で動作するプロセスに対して、同じ水準の閉じ込めを期待することはできません。 重要なのは、SELinux がファイルパスだけを見て判断しているわけではないことです。 例えば、ファイルが次の場所に存在していたとします。 /var/www/html/index.html 通常の管理者は、このパスを見れば Web コンテンツだと判断するでしょう。 しかし SELinux は、パスそのものではなく、そのファイルへ実際に付与されたラベルを基にポリシーを適用します。 ファイルが /var/www/html に存在していても、ラベルが user_home_t のままであれば、httpd_t で動作する Web サーバープロセスからのアクセスが拒否されることがあります。 SELinux では、ファイルが「どこに置かれているか」だけではなく、何としてラベル付けされているかが重要です。

mv ではパスが変わってもラベルが変わらない

SELinux の設計思想が、運用上の問題として最も分かりやすく現れるのが、mv によるファイル移動です。 例えば、ホームディレクトリで作成した HTML ファイルを、Web コンテンツ用ディレクトリへ移動したとします。

mv /home/user/index.html /var/www/html/index.html

同一ファイルシステム内の一般的な mv では、ファイルの実体を作り直すのではなく、ディレクトリエントリが変更されます。 そのため、移動元のファイルへ付与されていた SELinux ラベルも、そのまま保持されます。 移動前のラベルが次のようなものであったとします。 unconfined_u:object_r:user_home_t:s0 mv 後もこのラベルが残れば、パスは次のように変わっていても、 /var/www/html/index.html SELinux から見たファイルのタイプは、依然として user_home_t です。 その結果、次の条件がすべて成立していても、Apache HTTP Server から読み取れないことがあります。

  • ファイルが /var/www/html に存在する
  • 所有者が正しい
  • パーミッションが 0644 である
  • DAC 上は Web サーバープロセスから読み取り可能である

管理者がパスとパーミッションだけを確認していると、設定に問題がないように見えます。 しかし、SELinux 上では次の関係になっています。

  • httpd_t
  • ↓ read
  • user_home_t
  • ポリシー上で許可されていない

ラベルは次のコマンドで確認できます。

ls -lZ /var/www/html/index.html

想定されるラベルへ戻す場合は、restorecon を使用します。

restorecon -v /var/www/html/index.html

ディレクトリ以下を再帰的に確認・修正する場合は、次のように実行します。

restorecon -Rv /var/www/html

cp では移動先の規則に従ってラベルが付与される

cp は、一般的な同一ファイルシステム内の mv とは異なります。

cp /home/user/index.html /var/www/html/index.html

cp では、移動先に新しいファイルが作成されます。 セキュリティコンテキストを明示的に保持するオプションを指定していない場合、新しいファイルには、作成元プロセスと移動先ディレクトリに対する SELinux のラベル付与規則に基づいたコンテキストが設定されます。 そのため、/var/www/html に対する標準的なラベル規則が正しければ、コピーされたファイルには httpd_sys_content_t が付与されます。 基本的な違いは次のとおりです。

操作ファイルの扱いSELinux ラベルの典型的な挙動
同一ファイルシステム内の mv既存ファイルの配置を変更移動元のラベルを保持する
通常の cp移動先に新しいファイルを作成移動先のラベル付与規則に従う
cp --preserve=contextラベルを保持してコピーコピー元のコンテキストを保持する
restorecon標準ラベルへ修正ポリシー上のパス定義に基づいて再設定する

別ファイルシステムへの mv は、内部的にコピーと元ファイルの削除に相当する動作になる場合があるため、同一ファイルシステム内の mv と同じとは限りません。 ただし、SELinux 運用で頻発する典型的な問題は、同一ファイルシステム内で mv した結果、移動元のラベルが意図せず残ることです。

独自ディレクトリには永続的なラベル規則を定義する

Web コンテンツを標準の /var/www/html ではなく、独自のディレクトリへ配置する場合もあります。 例えば、次のディレクトリを利用するとします。 /opt/www 一時的にラベルを変更するだけであれば、chcon を利用できます。

chcon -R -t httpd_sys_content_t /opt/www

しかし、chcon による変更は、restorecon の実行やファイルシステムの再ラベル付けによって失われる可能性があります。 独自の配置先を恒久的に利用する場合は、semanage fcontext でラベル規則を定義します。

semanage fcontext -a -t httpd_sys_content_t '/opt/www(/.*)?'
restorecon -Rv /opt/www

ここで行っているのは、現在存在するファイルへ一時的にラベルを付けることではありません。 そのパスに存在するファイルを、今後どのタイプとして扱うかをシステムの規則として定義することです。

AppArmor はプログラムのプロファイルとパスを中心に制御する

AppArmor も MAC を実現しますが、SELinux とは制御モデルが異なります。 AppArmor では、主にプログラムごとのプロファイルを作成し、そのプログラムがアクセスできるパスや実行できる操作を定義します。 例えば、概念的には次のようなルールを記述します。

  • /var/www/html/** r,
  • /var/www/html/uploads/** rw,

これは、対象プロセスに対して次の操作を許可することを意味します。

  • /var/www/html 以下は読み取り可能
  • /var/www/html/uploads 以下は読み書き可能

SELinux との違いを単純化すると、次のように整理できます。

SELinux

  • プロセスのラベル
  • 対象のラベル
  • オブジェクトクラス
  • 操作

AppArmor

  • プログラムのプロファイル
  • 対象パス
  • 操作

AppArmor は、管理者が普段利用しているパスの概念をポリシーへ直接記述しやすいため、初期理解は比較的容易です。 一方、パス名やマウント構成を変更した場合には、プロファイルとの整合性を確認する必要があります。 SELinux が対象へ付与されたラベルを中心に考えるのに対し、AppArmor は制約対象となるプログラムとアクセス先のパスを中心に考えます。 AppArmor でも、プロファイルが存在しないプロセスや、プロファイルが適用されていないプロセスは、すべてが自動的に厳密な制約下へ置かれるわけではありません。 SELinux の unconfined_t と完全に同一の仕組みではありませんが、MAC が有効であることと、全プロセスが個別ポリシーで閉じ込められていることは別問題という点は共通しています。

SELinux と AppArmor はポリシーモデルが異なる

SELinux と AppArmor は、どちらも Linux Security Module の仕組みを利用して MAC を実現しますが、ポリシーの表現方法が異なります。

項目SELinuxAppArmor
主な判断基準プロセスや対象へ付与されたラベルプログラムのプロファイルとパス
基本的な管理単位ドメイン、タイプ、クラス、権限プログラムごとのプロファイル
配置変更の影響パスが変わってもラベルが残る場合があるパス変更に応じてプロファイル確認が必要
ポリシー表現Type Enforcement、ロール、ユーザー、MLS/MCS などパス、Capability、ネットワークなどをプロファイルへ記述
初期理解ラベルとポリシーの関係を理解する必要があるパス中心で比較的追いやすい
主な採用例RHEL、Fedora、CentOS StreamUbuntu、SUSE

SELinux の特徴は、単に細かな設定ができることではありません。 プロセスドメイン、オブジェクトタイプ、オブジェクトクラス、操作権限など、複数の属性を組み合わせてアクセス制御を表現できます。 一方、AppArmor は、アプリケーション単位のプロファイルへ、そのプログラムがアクセス可能なパスや操作を記述します。 したがって、単純にどちらが強力かを比較するよりも、システム全体をラベル関係として表現するか、アプリケーションの振る舞いをパス中心に記述するかという違いとして捉える方が適切です。

なぜ SELinux は無効化されやすいのか

SELinux が無効化されやすい最大の理由は、セキュリティ機能として厳しすぎるからではありません。 管理者が確認している状態と、SELinux が判定に利用している状態が異なるためです。 先ほどの mv の例では、管理者は次の項目を確認します。

  • パス
  • 所有者
  • グループ
  • パーミッション
  • Web サーバーの設定

しかし、SELinux はさらに次の情報を確認しています。

  • プロセスのドメイン
  • ファイルのタイプ
  • オブジェクトクラス
  • 要求された操作
  • ポリシー上の許可関係

そのため、次の流れが起きます。

  • ファイルを正しい場所へ mv した
  • パスとパーミッションは正しい
  • ラベルだけが user_home_t のまま残った
  • SELinux がアクセスを拒否した
  • Permissive にすると動作した
  • SELinux そのものが原因だと誤認した
  • 無効化した

ここで重要なのは、Permissive に変更して動作したことです。 これは SELinux を無効化すべき証拠ではありません。 SELinux のポリシー判定がアクセス拒否に関係していることを切り分けられたという意味です。 mv によるラベル不整合は具体的な一例ですが、その背後にはより一般的な構造があります。 Linux のアクセス可否を決める状態が、DAC だけでなく MAC によって増えているということです。

  • DAC
  • UID
  • GID
  • パーミッション
  • ACL
  • MAC
  • プロセスのドメインまたはプロファイル
  • 対象のラベルまたはパス
  • 要求された操作
  • ポリシールール

ただし、SELinux の targeted ポリシーでは、すべてのプロセスが同じ粒度で制約されているわけではありません。 実際にどの程度の追加制約が適用されるかは、そのプロセスが httpd_t などの confined ドメインで動作しているか、unconfined_t などの非制約ドメインで動作しているかによって異なります。 問題は、状態が増えたこと自体ではありません。 増えた状態と、その適用範囲が、監視、設計書、構築手順、障害対応手順へ取り込まれていないことです。 パスとパーミッションしか確認しない運用手順では、ラベルやプロファイルの不整合は見つかりません。 反対に、SELinux が Enforcing であることだけを確認して、対象プロセスが実際には unconfined_t で動作している事実を見落とせば、存在しない閉じ込め効果を期待することになります。 SELinux の有効・無効だけではなく、どのプロセスへ、どのポリシーが、どのドメインとして適用されているかまで確認する必要があります。

調査では Disabled ではなく Permissive を利用する

SELinux には、主に次の状態があります。

状態・モードポリシー適用拒否ログ
Enforcing拒否する記録する
Permissive拒否しない記録する
Disabledポリシーを読み込まないSELinux による拒否ログを取得できない

問題調査では、恒久的に Disabled へ変更するのではなく、まず Permissive で挙動と AVC ログを確認します。 一時的に Permissive へ変更する場合は、次のように実行します。

setenforce 0

Enforcing へ戻す場合は、次のように実行します。

setenforce 1

現在の状態は、次のコマンドで確認できます。

getenforce

SELinux 全体ではなく、特定のドメインだけを Permissive にすることもできます。

semanage permissive -a httpd_t

全システムの強制を解除せず、対象アプリケーションだけを調査できるため、本番環境ではこちらが適する場合もあります。 AppArmor にも、SELinux の Enforcing と Permissive に近いモードがあります。

AppArmor のモードポリシー適用違反ログ
enforce拒否する記録する
complain拒否しない記録する

例えば、次のコマンドでプロファイルのモードを変更できます。

aa-complain /usr/sbin/apache2
aa-enforce /usr/sbin/apache2

どちらの仕組みでも、まず強制を一時的に緩めて違反を観察し、原因を修正してから再び強制する、という流れが基本です。

AVC ログを確認して原因を分類する

SELinux による拒否は、AVC メッセージとして audit ログなどへ記録されます。 最近の拒否を確認する場合は、例えば次のように実行します。

ausearch -m AVC,USER_AVC -ts recent

特定のプロセス名で絞り込む場合は、次のように実行します。

ausearch -m AVC -c httpd -ts recent

ただし、AVC ログが存在しない場合は、SELinux が原因ではない可能性があります。 先に DAC で拒否されていれば、SELinux の判定まで進まないためです。 また、対象プロセスが想定した confined ドメインではなく、unconfined_t などで動作している場合、期待していた SELinux ポリシーそのものが適用されていない可能性もあります。 そのため、障害解析では次の順序で確認する必要があります。

  1. 所有者、グループ、パーミッション、ACL に問題がないか
  2. 対象プロセスがどの SELinux ドメインで動作しているか
  3. SELinux の AVC 拒否が記録されているか
  4. ファイルやディレクトリのラベルが正しいか
  5. 標準の配置先や標準ラベルを利用できないか
  6. SELinux Boolean で想定された機能を有効化できないか
  7. 本当に新しいポリシーが必要か

対象プロセスのドメインは、次のように確認できます。

ps -eZ

特定のプロセスだけを確認する場合は、例えば次のように絞り込みます。

ps -eZ | grep httpd

audit2allow は自動修復コマンドではない

audit2allow は、SELinux の拒否ログを解析し、その拒否を許可する Type Enforcement ルールを生成するツールです。 例えば、ルール候補を確認する場合は次のように実行します。

ausearch -m AVC -ts recent | audit2allow

ローカルポリシーモジュールを生成することもできます。

ausearch -m AVC -ts recent |
    audit2allow -M local-policy

しかし、audit2allow は、アプリケーションに本当に必要な権限を設計してくれるわけではありません。 ログに記録された拒否を、許可ルールへ変換しているだけです。 例えば、ラベルが誤っているために拒否されたアクセスへ audit2allow を適用すると、本来は restorecon で直すべき問題に対して、誤ったラベルのままアクセスを許可するポリシーを追加することになります。

  • 本来の問題
  • ファイルのラベルが誤っている
  • 誤った対応
  • 誤ったラベルへのアクセスを許可する
  • 結果
  • 動作はするが、ポリシーの意味が崩れる

audit2allow を利用する場合は、少なくとも次の確認が必要です。

  • 生成されたルールを読む
  • なぜそのアクセスが必要なのか確認する
  • ラベルや Boolean で解決できないか先に検討する
  • 必要最小限の操作だけを許可する
  • 正常系だけでなく異常系も含めて検証する

拒否ログが消えることと、適切なセキュリティポリシーが設計されたことは同じではありません。

コンテナでも SELinux と AppArmor は利用される

コンテナは仮想マシンではなく、Linux カーネル上で動作するプロセスです。 そのため、コンテナの分離は一つの仕組みだけで実現されているわけではありません。

機構主な制御対象
namespacesプロセス、ネットワーク、マウントなどの可視範囲
cgroupsCPU、メモリーなどのリソース
Linux Capabilitiesroot 権限に含まれる特権の細分化
seccomp実行可能なシステムコール
SELinux/AppArmorプロセスがアクセスできる対象や操作

例えば、コンテナ内のプロセスが root として動作していても、次の制限を重ねられます。

  • Capabilities
  • 特権操作を制限
  • seccomp
  • システムコールを制限
  • SELinux / AppArmor
  • ファイル、ソケット、デバイスなどへのアクセスを制限

コンテナを利用しているから SELinux や AppArmor が不要になるわけではありません。 複数のワークロードが同じカーネルを共有するため、プロセスが侵害された後の影響範囲を制限する仕組みとして、むしろ重要になります。 ただし、ここでも単に SELinux や AppArmor が有効であるだけでは不十分です。 どのプロファイルやラベルが実際にコンテナへ適用されているかを確認しなければ、期待した分離が成立しているとは限りません。

まとめ

SELinux と AppArmor は、どちらも Linux の MAC を実現し、DAC だけでは制限できないプロセスの振る舞いを制御します。 両者の違いを単純化すると、次のように整理できます。

  • SELinux は、プロセスや対象へ付与されたラベルの関係を中心に判断する
  • AppArmor は、プログラムへ適用されるプロファイルとアクセス先のパスを中心に判断する

SELinux の mv 問題は、この設計思想を理解する上で象徴的です。

  • パスは変わった
  • ラベルは変わっていない

この状態では、パスとパーミッションだけを確認しても拒否理由が分かりません。 Permissive にすると動作するため、SELinux そのものが問題であるように見えます。 しかし、本来行うべきことはアクセス制御を取り除くことではありません。

  • DAC で拒否されていないか
  • 対象プロセスはどのドメインで動作しているか
  • MAC による拒否が記録されているか
  • ラベルやプロファイルが正しいか
  • 既存のポリシーで表現できるか
  • 新しい許可が本当に必要か

という順序で確認することです。 また、SELinux が Enforcing であることと、システム上の全プロセスが厳密に閉じ込められていることは同じではありません。

  • SELinux が有効
  • 全プロセスが厳密に制約されている
  • SELinux が有効
  • 対象プロセスが confined ドメインで動作
  • 適切なポリシーが適用されている
  • Type Enforcement による閉じ込めが機能する

SELinux や AppArmor が扱いにくく見えるのは、Linux へ余計な制約を追加しているからではありません。 従来は暗黙だった「どのプロセスが、どの対象へ、何をしてよいか」という設計を、明示的なポリシーとして管理対象にしたためです。 その状態と適用範囲を運用設計へ取り込めなければ、MAC は障害の原因に見えます。 一方、ラベル、ドメイン、プロファイル、ログ、調査手順まで含めて管理できれば、アプリケーションが侵害された後の被害範囲を制限する、Linux の重要な防御層として機能します。

参考資料

関連する記事
SELinux と AppArmor は何が違うのか – 無効化されやすい Linux のアクセス制御を設計思想から理解する

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トップへ戻る