AppArmor

AppArmor とは、Linux で一般的に使われている user / group を使ったセキュリティ機能(DAC)に加えて、実行ファイルごとにより細かく権限を設定する仕組みです。AppArmor を使うと、パス名で指定されたある実行ファイルがアクセス出来るファイルやネットワークなどのリソースを正確に指定する事ができます。

ここで Armor という単語が使われているので、まるで AppArmor が外部からアプリを守るための装甲板のように思いがちですが、実は機能としては逆です。むしろ AppArmor はアプリ本来の力を私達が抑え込む為の拘束具であり、将来未知の脆弱性が見つかり侵入者に任意のコードの実行を許しても無関係のリソースを開放しないためのものです。

## 基本的な使い方

例えばある実行ファイル /tmp/cat に一つのファイル /tmp/white.txt へのアクセスだけを許可してみます。準備として以下のように実行して必要なファイルを作ります。

```
cp /bin/cat /tmp/cat
echo Hello white > /tmp/white.txt
echo Hello black > /tmp/black.txt
```

次に AppArmor の設定ファイル(profile) である tmp.cat を用意します。

```
/tmp/cat {                          # この profile が /tmp/cat を制御するものである事を示します。
  /tmp/white.txt r,                 # /tmp/cat に /tmp/white.txt の読み込み(r 権限)を許可します。
  /etc/ld.so.cache r,               # /tmp/cat の実行に必要なファイルの読み込みを許可します。
  /lib/x86_64-linux-gnu/* mr,       # /tmp/cat の実行に必要な共有ライブラリを許可します。メモリマップに m 権限が必要です。

  /dev/pts/[0-9]* rw,               # 無くても動く時がありますが、あとで説明する他のプロファイルのサブプロセスになってると必要です。
  /tmp/cat rm,                      # 無くても動く時がありますが、あとで説明する他のプロファイルのサブプロセスになってると必要です。
}
```

これを AppArmor の設定ファイル置き場である /etc/apparmor.d にコピーして aa-enforce コマンドで有効にします。

```
sudo cp tmp.cat /etc/apparmor.d
sudo aa-enforce /etc/apparmor.d/tmp.cat
```

試してみます。

```shell
$ /tmp/cat /tmp/white.txt 
Hello white
$ /tmp/cat /tmp/black.txt 
/tmp/cat: /tmp/black.txt: Permission denied
```

成功です。これで /tmp/cat は /tmp/white.txt しか読めなくなってしまいました。
ただ、これでは共有ファイル名などにプラットフォーム固有の情報が入ってしまうので include で出来合いの設定を読み込みます。(昔は #include のように # を付けていたが、今は付けない方がよいらしい)

```
include <tunables/global>     # /etc/apparmor.d/tunables/global 変数定義を読みます。abstractions/base で使います。
/tmp/cat {
  include <abstractions/base> # /etc/apparmor.d/abstractions/base にある共有ライブラリの設定などを読みます。
  /tmp/white.txt r,
}
```

これでスッキリしました。設定ファイルを入れ替えるには apparmor_parser -r を使います。

    sudo apparmor_parser -r /etc/apparmor.d/tmp.cat

また、Profile の削除には apparmor_parser -R を使います。

```shell
sudo apparmor_parser -R /etc/apparmor.d/tmp.cat
sudo rm /etc/apparmor.d/tmp.cat
```

## profile を半自動で作る

動作確認のために手動で profile を作る方法を最初にご説明しましたが、実行ファイルがどのリソースにアクセスするのかは自明で無いため、最初はツールの力を借りて半自動で作成した方が良いです。それには aa-genprof コマンドを使います。

```
$ sudo aa-genprof /tmp/cat
Writing updated profile for /tmp/cat.
Setting /tmp/cat to complain mode.
...
Please start the application to be profiled in
another window and exercise its functionality now.
...
[(S)can system log for AppArmor events] / (F)inish
```

ここで、aa-genprof は /tmp/cat のための profile を /etc/apparmor.d/tmp.cat に作成し complain モードに設定します。complain モードでは、アクセス制限をかけないで監視だけを行い、結果を kernel log に記録します。そこで、別のターミナルで /tmp/cat を動かします。

```
$ /tmp/cat /tmp/white.txt 
Hello white
```

元のターミナルに戻り s キーを押すと aa-genprof はログを解析します。

```
Reading log entries from /var/log/syslog.
Updating AppArmor profiles in /etc/apparmor.d.
Complain-mode changes:

Profile:  /tmp/cat
Path:     /tmp/white.txt
New Mode: owner r
Severity: unknown

 [1 - #include <abstractions/user-tmp>]
  2 - owner /tmp/white.txt r, 
(A)llow / [(D)eny] / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Audi(t) / (O)wner permissions off / Abo(r)t / (F)inish
```

このように質問に答えながら profile を作っていきますが、このように選択肢が複数出ることがあります。ここで (A)llow を選択すると、1 番の `#include <abstractions/user-tmp>` が選ばれてしまいます。これは `/tmp` や `~/tmp` など、テンポラリファイル内を全てアクセス可能にする設定で、実態は `/etc/apparmor.d/abstractions/user-tmp` にあります。`/tmp/white.txt` だけを許可したい場合は 2 を押してから a を押します。

```
The following local profiles were changed. Would you like to save them?

 [1 - /tmp/cat]
(S)ave Changes / Save Selec(t)ed Profile / [(V)iew Changes] / View Changes b/w (C)lean profiles / Abo(r)t
```

すると確認されるので、s で保存して f で終了します。

## コマンド

ログを解析して profile(設定ファイル)を半自動で作る。ログはデフォルトで `/var/log/syslog` を読みます。`-f` オプションで指定もできます。

    sudo aa-genprof コマンド

この後実際にコマンドを動かした後、S でログをスキャンしながら profile を作る。

Complain モード(アクセス制限なし、ログあり)に入る。

    sudo aa-complain コマンド又は profile 

ログを解析して profile を修正する。

    sudo aa-logprof

Enforce モードにする。

    sudo aa-enforce コマンド又は profile 

一つの profile をリロード

    sudo apparmor_parser -r /etc/apparmor.d/profile.name

一つの profile を削除

    sudo apparmor_parser -R /etc/apparmor.d/profile.name

一つの profile を無効 (apparmor_parser -R との違いは要調査)

    sudo aa-diable -R /etc/apparmor.d/profile.name

## profile の名前

 profile を置くディレクトリは二通りある。いずれもドキュメントでは ${APPARMOR.D} として記載する。

* /etc/apparmor.d/
* ${HOME}/.apparmor.d/ (実は自分では試していない)

よく使われるディレクトリ

* ${APPARMOR.D}/abstractions/ 共通で使うファイル
* ${APPARMOR.D}/abstractions/なんとか.d/ インテグレータが独自に入れるファイル。
* ${APPARMOR.D}/cache/ コンパイル済みプロファイル。
* ${APPARMOR.D}/tunables/ @{HOME} などの便利な変数が定義されている。

プロファイルのファイルの名前の付け方。一つのファイルは複数のプロファイルを含んでも良い。

* ${APPARMOR.D}/usr.sbin.smbd プロファイル名が / から始まるとき。
* ${APPARMOR.D}/profile_example1 プロファイル名が / から始まらないとき。

## 普通の UNIX パーミッション (DAC) との違い。

* DAC
    * ファイルの作成と削除には親ディレクトリの wx 権限が必要。
    * ディレクトリの検索にはディレクトリの x 権限が必要。
* AppArmor
    * ファイルの作成と削除にはファイルの w 権限が必要。
    * ディレクトリの検索にはディレクトリの r 権限が必要。

## 文法

* 一つのファイルに複数のプロファイルを書ける。
* プロファイルの順序は問わない。
* 一つのプロファイルは プロファイル名 { ルール } の形式を取る。
* 単純な場合プロファイル名は実行ファイルの名前を表す。プロファイルはルールは実行ファイルが持つ権限を表す。
* ルールに何も書かないと実行ファイルは何も出来ない。ルールを足すと権限が増える(ホワイトリスト形式)
* `#` 以降はコメント
* `#include` はコメントっぽいが他のファイルを取り込む命令。新しい AppArmor では `include` と書く。
* プロファイル名に * などのグロブを使って複数の実行ファイルにマッチするプロファイルを書ける。
* ある実行ファイルが複数のプロファイル名にマッチする時は次の優先順序で一つが選ばれる。
    * 正確に実行ファイルにマッチするプロファイル名
    * 左から数えて最も長いパターンがマッチするプロファイル名
    * 参照: https://gitlab.com/apparmor/apparmor/-/wikis/AppArmor_Core_Policy_Reference の Profile names with globbing 
* もしもグロブ無しで実行ファイルにマッチするプロファイルを２つ作ってしまったら、AppArmor は全く効かない(???)
* ファイルアクセスを制御するルール `tmp/white.txt r` は `file tmp/white.txt r` を略した物。
* `file` 以外に `capability`, `network` など様々なルールと文法がある。ルールのみを指定するとデフォルトで全許可なので、例えば `file` だけのようにルール名だけを記述するとファイルアクセス全許可と解釈される。

```
# Preamble section。include 変数定義、rewrite ルールなどを書く。
include <tunables/global>

# Profile section。関連した Profile を連続して複数書けるが順序は関係無い。
profile_header {
    rule
    rule
    ...
}
```

profile_header には以下の種類がある

* /から始まる時 (attachment specification)
    * 実行ファイルの名前
* キーワード `profile` から始まる時
    * 他の profile から参照できる名前になる。

globbing が使える。

```
 /bin/** {
    #profile body
 }
```

## 参考

* [AppArmor - Community Help Wiki](https://help.ubuntu.com/community/AppArmor)
    * 短くまとまっててよい
* [Documentation · Wiki · AppArmor / apparmor · GitLab](https://gitlab.com/apparmor/apparmor/-/wikis/Documentation)
    * 公式ドキュメント。各種コマンドのマニュアルなど。
* [QuickProfileLanguage · Wiki · AppArmor / apparmor · GitLab](https://gitlab.com/apparmor/apparmor/-/wikis/QuickProfileLanguage)
    * Profile 言語を学ぶのに一番おすすめ
* [AppArmor\_Core\_Policy\_Reference · Wiki · AppArmor / apparmor · GitLab](https://gitlab.com/apparmor/apparmor/-/wikis/AppArmor_Core_Policy_Reference)
    * 細かい
* [manpage\_apparmor.d.5 · Wiki · AppArmor / apparmor · GitLab](https://gitlab.com/apparmor/apparmor/-/wikis/manpage_apparmor.d.5)
    * Wiki よりこちらの方が正確なようだ。