Linuxのセキュリティはとにかくややこしい。
古典的なパーミッションやACLは「DAC」という分類に入る。
rootにすら権限を与えない「MAC」という方式もある。ただ、具体的なコマンドとして提供されるわけではなく、AppArmorやSELinuxといったフレームワークで表現されることが多い。フレームワーク化したMACのことをまとめてLSMと呼ぶ
DACとMACは共存できる。そして今回はAppArmorの話。
AppArmorの運用
基本的な操作
AppArmorの有効/無効
有効/無効の状態を確認するにはaa-enableコマンドを使う
$ aa-enabled
yes ・・・有効
- 無効化(設定を削除する)
- aa-teardown ・・・現在のプロファイルをアンロードする
- systemctl disable apparmor ・・・起動時にプロファイルを読み込まない
- 有効化する
- systemctl enable apparmor ・・・起動時にプロファイルを読み込む
動作モード
AppArmorはシステム全体に影響を及ぼすため、部分的に無制限にしたり学習モードにしたりできる。
- unconfined(非制限)モード:何も制限しない
- enforced(適用)モード:プロファイルで許可されていない処理を行おうとした場合は、エラー扱いにしログに残す
- complaining(学習)モード:プロファイルで許可されていない処理を行う場合、ログに残すものの、エラー扱いにはしない
動作モードは専用のコマンドで設定する
- 非制限モード・・・aa-uncomfined プログラムのパス
- 適用モード・・・aa-enforce プログラムのパス
- 学習モード・・・aa-complain プログラムのパス
動作モードを確認するにはaa-statusコマンドを使う
$ aa-status
apparmor module is loaded.
113 profiles are loaded.
xxprofiles are in <動作モード> mode
AppArmorの設定
AppArmorの設定はファイルに対する設定とプロセスに対する設定がある。
設定ファイルについて
ファイルパス
通常のプログラムに関する設定は/etc/apparmor.d/にあるが、snapのプロファイルは/var/lib/snapd/apparmor/profiles/にある
/etc/apparmor.d/の中にはいくつかのフォルダがあり、disableフォルダの下にあるプロファイルは読み込まないなどの制御ができる
apparmor.d
├disable ・・・この下のプロファイルは起動時に読み込まれない
├force-complain ・・・この下のシンボリックリンクはcomplainingモードで動作する
設定ファイルの有効化
通常は起動時にプロファイルを読み込むが、設定を変更した場合は特定のプロファイルだけ読み込むことができる。
$ sudo apparmor_parser -r プロファイル
設定ファイルの作り方
aa-genprof
設定ファイルを作る最も簡単なやり方。
「aa-genprof 起動プロセス」を実行すると対話的にプロファイルを作成してくれる方法。一般にはこちらが楽。
complainingで雛形を作る
通常はcomplaining(学習モード)で動作させて、その結果を雛形にしながら設定ファイルを作成する方法。修正はこちらが楽。
作成手順
$ sudo aa-genprof firefox
(対話形式で設定)
$ プロファイルが作成されるので編集する
設定ファイルの書き方
ab i <abi/バージョン> | AppArmorのバージョン |
include <機能> | プロファイルがあるディレクトリ。 <tubables/global>と記載すると必要と思われるディレクトリをすべて読み込んでくれる |
サブコマンドのパス { include <機能> ファイルパス 権限, ファイルパス/* 権限, ファイルパス/** 権限, : } | プログラムがファイルに対して実行できる権限を記載する。 /*はディレクトリ直下のファイル。/**は再起的にサブフォルダのファイル。 |
includeで指定できる機能
<tunables/global > | すべてのプロファイルでロードしたほうが良いもの |
<abstractions/base > | 一般的なLinuxコマンドならまず必要になるであろう設定 |
<abstractions/consoles > | 標準入出力を使うコマンドに必要な設定 |
<abstractions/opencl-pocl > | OpenCLを使う際に必要な設定 |
権限で指定できるパーミッション
r | 読み込み |
w | 書き込み |
?x | 実行 |
m | mmap() |
l | リンク |
k | ファイルロック |
設定の反映と動作確認
- sudo apparmor_parser -r プロファイル でプロファイルを更新する。
- もしくはrcapparmor reloadでも読み込める
- 1つ目のターミナルで$sudo aa-genprof プロセス を実行し、他のターミナルでコマンドを実行する。
- aa-genprofターミナルでSを入力してスキャンするとエラーが表示されるので、設定を追加していく。
もしくは学習モードにして結果を読み込ませる方法でも良い。この方法はsnapの場合はおそらくうまく機能しない。
$ aa-complain プログラムのパス
$ プログラムを実行
$ aa-logprof プログラムのパス
設定に関するもっと詳細な情報
https://manual.geeko.jp/ja/part.apparmor.html
デバッグの方法
一般的な権限不正はsyslogで確認できる
snapのfirefoxが起動に失敗した際、/var/log/syslogには以下のメッセージが出力されていた。
2025-01-17T21:20:24.403046+09:00 workpc kernel: audit: type=1400 audit(1737116424.401:213): apparmor="DENIED" operation="exec" class="file" profile="/usr/bin/snap" name="/snap/snapd/23545/usr/bin/snap" pid=4352 comm="firefox" requested_mask="x" denied_mask="x" fsuid=1000 ouid=0
apparmorの診断結果。拒否した。 | |
operation="exec" class="file" profile="/usr/bin/snap" name="/snap/snapd/23545/usr/bin/snap" | /usr/bin/snapが/snap/snapd/23545/usr/bin/snapを実行しようとした。 |
comm="firefox" | snapで操作しようとしたコマンドはfirefox |
requested_mask="x" denied_mask="x" | 要求した権限はxで、拒否された権限はx |
fsuid=1000 ouid=0 | 実行しようとしたファイルのfsuid(使用しようとしたユーザー)は1000で、本来のファイルの持ち主のouidは0(root) |
対面でデバッグするならaa-genprof
1つの画面でaa-genprofを開いておき、別の画面でコマンドを実行する方法。snapの様に親プロセス(snap)が子プロセス(firefox)を起動するような複雑な動作をする場合はこのやり方が望ましい。
ここではsnapでインストールされたfirefoxを起動する例を紹介する
まずスキャンを始める。プロファイルを編集するためsudoを忘れないこと。
$ sudo aa-genprof /usr/bin/snap
Updating AppArmor profiles in /etc/apparmor.d.
Before you begin, you may wish to check if a
profile already exists for the application you
wish to confine. See the following wiki page for
more information:
https://gitlab.com/apparmor/apparmor/wikis/Profiles
Profiling: /usr/bin/snap
Please start the application to be profiled in
another window and exercise its functionality now.
Once completed, select the "Scan" option below in
order to scan the system logs for AppArmor events.
For each AppArmor event, you will be given the
opportunity to choose whether the access should be
allowed or denied.
[(S)can system log for AppArmor events] / (F)inish
次にfirefoxを起動する。今回は前述のエラーを出して停止している。
この状態でSを押すとエラーログを解析してどう処理すべきか選択できるようになる。
[(S)can system log for AppArmor events] / (F)inish
Reading log entries from /var/log/syslog.
Profile: /usr/bin/snap
Execute: /snap/snapd/23545/usr/bin/snap
Severity: unknown
(I)nherit / (C)hild / (P)rofile / (N)amed / (U)nconfined / (X) ix On / (D)eny / Abo(r)t / (F)inish
重要度(Severity)は不明だが何らかの権限不正が起きたようです。この問題をどう扱うかを選択します
Inherit | 親プロセスのプロファイルを継承して子プロセスを実行する |
Child | 親プロファイル内にある子プロセスのプロファイルを使用する |
Profile | 子プロセスが持つプロファイルを適用する |
Named | 既存の他のプロファイルを指定して適用する |
Unconfined | 子は制限なしで実行されます。これにより、セキュリティ上のリスクが発生する可能性があります。 |
X ix On | 子は独自のプロファイルを持つことができますが、独自のプロファイルが存在しない場合は、親のプロファイルをフォールバックとして使用します。 |
Deny | プログラムの起動を拒否する |
Abort | aa-genprofを強制終了する。これまでの記録は破棄される。 |
Finish | aa-genprofを正常終了する。これまでの記録は保存される。 |
通常はInheritを選択する。するとこの設定を保存するか聞いてくるのでSで保存する。
(I)nherit / (C)hild / (P)rofile / (N)amed / (U)nconfined / (X) ix On / (D)eny / Abo(r)t / (F)inish
Complain-mode changes:
Enforce-mode changes:
= Changed Local Profiles =
The following local profiles were changed. Would you like to save them?
[1 - /usr/bin/snap]
(S)ave Changes / Save Selec(t)ed Profile / [(V)iew Changes] / View Changes b/w (C)lean profiles / Abo(r)t
するとプロファイルを編集して再びスキャンモードに戻る。
Allow Deny Igunore といった選択肢が出る場合もあるが、基本的にはAllowを選択する。
これを目的のプログラムが起動するまで繰り返す。