Product SiteDocumentation Site

14.4. AppArmor の紹介

14.4.1. 原理

AppArmor は Linux の LSM (Linux Security Modules) インターフェース上に設けられた強制アクセス制御 (MAC) システムです。具体的に言えば、カーネルはそれぞれのシステムコールの前にシステムコールを発行したプロセスが指定された操作に対する権限を与えられているか AppArmor に問い合わせます。このメカニズムを通じて、AppArmor はプログラムがアクセスできるリソースを制限します。
AppArmor はプログラムごとに一連の規則 (これは「プロファイル」として知られています) を適用します。カーネルは実行されたプログラムのインストール先のパスに依存してこのプロファイルを適用します。SELinux とは対照的に (第 14.5 節「SELinux の紹介」で説明されている通り)、このプロファイルはユーザに依存するものではありません。同じプログラムを実行したすべてのユーザは同じプロファイルを適用されます (しかしながら、伝統的なユーザパーミッションが適用されないわけではありません。このため、ユーザごとにプログラムの挙動が異なる可能性もあります!)。
AppArmor プロファイルは /etc/apparmor.d/ に保存され、プロファイルには各プログラムが使うことができるリソースに対するアクセス制御規則のリストが含まれています。プロファイルは apparmor_parser コマンドによってコンパイルされてカーネルに読み込まれます。各プロファイルは enforce または complain モードで読み込みます。enforce モードではポリシーの遵守を強制され、ポリシー違反の試行を報告されます。これに対して、complain モードではポリシーの遵守を強制されませんが、ポリシー違反で拒否されうるシステムコールを記録されます。

14.4.2. AppArmor の有効化と AppArmor プロファイルの管理

AppArmor のサポートは Debian が提供する標準カーネルに組み込まれています。このため AppArmor を有効化するには、いくつかのパッケージをインストールして、一部のパラメータをカーネルコマンドラインに追加します。
# apt install apparmor apparmor-profiles apparmor-utils
[...]
# perl -pi -e 's,GRUB_CMDLINE_LINUX="(.*)"$,GRUB_CMDLINE_LINUX="$1 apparmor=1 security=apparmor",' /etc/default/grub
# update-grub
AppArmor は再起動後に動作します。aa-status を使えば AppArmor の有効化を素早く確認できます。
# aa-status
apparmor module is loaded.
44 profiles are loaded.
9 profiles are in enforce mode.
   /usr/bin/lxc-start
   /usr/lib/chromium-browser/chromium-browser//browser_java
[...]
35 profiles are in complain mode.
   /sbin/klogd
[...]
3 processes have profiles defined.
1 processes are in enforce mode.
   /usr/sbin/libvirtd (1295) 
2 processes are in complain mode.
   /usr/sbin/avahi-daemon (941) 
   /usr/sbin/avahi-daemon (1000) 
0 processes are unconfined but have a profile defined.
それぞれのプロファイルの状態を enforce と complain モードの間で切り替えるには、引数に実行ファイルのパスかポリシーファイルのパスを与えて aa-enforce および aa-complain を呼び出します。さらにプロファイルを完全に無効化するには、aa-disable を使うか aa-audit を使ってプロファイルを audit モード (承認されたシステムコールもログ記録するモード) に切り替えます。
# aa-enforce /usr/sbin/avahi-daemon
Setting /usr/sbin/avahi-daemon to enforce mode.
# aa-complain /etc/apparmor.d/usr.bin.lxc-start
Setting /etc/apparmor.d/usr.bin.lxc-start to complain mode.

14.4.3. 新規プロファイルの作成

AppArmor プロファイルを作成することはかなり簡単な作業であるにも関わらず、ほとんどのプログラムはプロファイルを用意していません。この節では、対象のプログラムを使うことと AppArmor に対象のプログラムが呼び出したシステムコールとアクセスするリソースを監視させることにより、ゼロから新しいプロファイルを作成する方法を示します。
アクセス制限を設ける必要のあるもっとも重要なプログラムはネットワークを取り扱うプログラムです。なぜなら、この種のプログラムは遠隔攻撃者からの標的になるからです。このため好都合なことに AppArmor は aa-unconfined コマンドを提供しています。aa-unconfined コマンドは関連するプロファイルが存在せず開かれたネットワークソケットを公開しているプログラムを表示します。aa-unconfined--paranoid オプションを付けて実行すれば、少なくとも 1 つ以上のアクティブなネットワーク接続を持つ、アクセス制限を設けていないプロセスがすべて表示されます。
# aa-unconfined
801 /sbin/dhclient not confined
890 /sbin/rpcbind not confined
899 /sbin/rpc.statd not confined
929 /usr/sbin/sshd not confined
941 /usr/sbin/avahi-daemon confined by '/usr/sbin/avahi-daemon (complain)'
988 /usr/sbin/minissdpd not confined
1276 /usr/sbin/exim4 not confined
1485 /usr/lib/erlang/erts-6.2/bin/epmd not confined
1751 /usr/lib/erlang/erts-6.2/bin/beam.smp not confined
19592 /usr/lib/dleyna-renderer/dleyna-renderer-service not confined
以下の例では、/sbin/dhclient 用のプロファイルを作成しようとしています。プロファイルを作成するためには aa-genprof dhclient を使います。aa-genprof は、ユーザに別のウィンドウから対象のアプリケーションを開始することを求め、その後ユーザにシステムログ内の AppArmor イベントを走査してこれらのログをアクセス規則に変換するために aa-genprof に戻ることを求めます。それぞれのログ記録されたイベントについて、aa-genprof は 1 つ以上の規則を提案します。ユーザは提案された規則を受け入れるかまたはさまざまな方法で規則を編集することが可能です。
# aa-genprof dhclient
Writing updated profile for /sbin/dhclient.
Setting /sbin/dhclient to complain mode.

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:
http://wiki.apparmor.net/index.php/Profiles

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.

Profiling: /sbin/dhclient

[(S)can system log for AppArmor events] / (F)inish
Reading log entries from /var/log/audit/audit.log.

Profile:  /sbin/dhclient 1
Execute:  /usr/lib/NetworkManager/nm-dhcp-helper
Severity: unknown

(I)nherit / (C)hild / (P)rofile / (N)amed / (U)nconfined / (X) ix On / (D)eny / Abo(r)t / (F)inish
P
Should AppArmor sanitise the environment when
switching profiles?

Sanitising environment is more secure,
but some applications depend on the presence
of LD_PRELOAD or LD_LIBRARY_PATH.

(Y)es / [(N)o]
Y
Writing updated profile for /usr/lib/NetworkManager/nm-dhcp-helper.
Complain-mode changes:
WARN: unknown capability: CAP_net_raw

Profile:    /sbin/dhclient 2
Capability: net_raw
Severity:   unknown

[(A)llow] / (D)eny / (I)gnore / Audi(t) / Abo(r)t / (F)inish
A
Adding capability net_raw to profile.

Profile:  /sbin/dhclient 3
Path:     /etc/nsswitch.conf
Mode:     r
Severity: unknown

  1 - #include <abstractions/apache2-common> 
  2 - #include <abstractions/libvirt-qemu> 
  3 - #include <abstractions/nameservice> 
  4 - #include <abstractions/totem> 
 [5 - /etc/nsswitch.conf]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
3

Profile:  /sbin/dhclient
Path:     /etc/nsswitch.conf
Mode:     r
Severity: unknown

  1 - #include <abstractions/apache2-common> 
  2 - #include <abstractions/libvirt-qemu> 
 [3 - #include <abstractions/nameservice>]
  4 - #include <abstractions/totem> 
  5 - /etc/nsswitch.conf 
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding #include <abstractions/nameservice> to profile.

Profile:  /sbin/dhclient
Path:     /proc/7252/net/dev
Mode:     r
Severity: 6

  1 - /proc/7252/net/dev 
 [2 - /proc/*/net/dev]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /proc/*/net/dev r to profile

[...]
Profile:  /sbin/dhclient 4
Path:     /run/dhclient-eth0.pid
Mode:     w
Severity: unknown

 [1 - /run/dhclient-eth0.pid]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
N

Enter new path: /run/dhclient*.pid

Profile:  /sbin/dhclient
Path:     /run/dhclient-eth0.pid
Mode:     w
Severity: unknown

  1 - /run/dhclient-eth0.pid 
 [2 - /run/dhclient*.pid]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /run/dhclient*.pid w to profile

[...]
Profile:  /usr/lib/NetworkManager/nm-dhcp-helper 5
Path:     /proc/filesystems
Mode:     r
Severity: 6

 [1 - /proc/filesystems]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /proc/filesystems r to profile

= Changed Local Profiles =

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

 [1 - /sbin/dhclient]
  2 - /usr/lib/NetworkManager/nm-dhcp-helper 
(S)ave Changes / Save Selec(t)ed Profile / [(V)iew Changes] / View Changes b/w (C)lean profiles / Abo(r)t
S
Writing updated profile for /sbin/dhclient.
Writing updated profile for /usr/lib/NetworkManager/nm-dhcp-helper.

Profiling: /sbin/dhclient

[(S)can system log for AppArmor events] / (F)inish
F
Setting /sbin/dhclient to enforce mode.
Setting /usr/lib/NetworkManager/nm-dhcp-helper to enforce mode.

Reloaded AppArmor profiles in enforce mode.

Please consider contributing your new profile!
See the following wiki page for more information:
http://wiki.apparmor.net/index.php/Profiles

Finished generating profile for /sbin/dhclient.
aa-genprof プログラムはユーザが入力した操作文字を再表示しないという点に注意してください。しかし、上に挙げた例では説明を明確に行うために、ユーザが入力した操作文字をその直後に含めています。

1

最初に別のプログラムの実行イベントが検出されています。この場合、ユーザに対していくつかの選択肢が示されます。ユーザは親プロセスのプロファイルを適用してプログラムを実行したり (「Inherit」を選んだ場合)、専用のプロファイルを適用してプログラムを実行したり (「Profile」と「Named」を選んだ場合、両者の違いは任意のプロファイル名を使用する可能性があるか否かです)、親プロセスのサブプロファイルを適用してプログラムを実行したり (「Child」を選んだ場合)、プロファイルを適用せずにプログラムを実行したり (「Unconfined」を選んだ場合)、プログラムを実行させない (「Deny」を選んだ場合) ことも可能です。
まだ存在しない専用プロファイルを適用してプログラムを実行することが可能であるという点に注意してください。aa-genprof ツールは不足しているプロファイルを作成し、さらにこのプロファイルに対する規則を提案します。

2

カーネルレベルで root ユーザの特権は「capability」に分割されます。システムコールが特別な機能を要求する場合、AppArmor はプロファイルの中でプログラムがその機能を使うことを許可されているかを確認します。

3

ここでプログラムは /etc/nsswitch.conf の読み込み権限を求めています。aa-genprof は複数の「abstraction」がこの権限を承認していることを検出しました。そして代替選択肢としてこの権現を承認する「abstraction」を挙げています。abstraction とは通常同時に使われる複数のリソースをまとめた一連のアクセス規則を再利用できる形で提供するものです。今回の場合、/etc/nsswitch.conf ファイルは一般に C 言語ライブラリのネームサービスに関連する関数を通じてアクセスされます。ここでは最初に「3」を入力して「#include <abstractions/nameservice>」を選択し、その後に「A」を入力してこれを許可しました。

4

プログラムが /run/dhclient-eth0.pid ファイルを作成することを求めています。このファイルだけの作成を許可した場合、ユーザが他のネットワークインターフェースに対してこのプログラムを実行する際に、プログラムは動作しなくなるでしょう。このため、「New」を選択してファイル名をより一般的な「/run/dhclient*.pid」に変更した後、「Allow」を選択してこの規則を適用します。

5

このアクセス要求は dhclient プロファイルの一部ではなく、/usr/lib/NetworkManager/nm-dhcp-helper の実行時にこれに対するプロファイルを適用することを許可する際に作成される新しいプロファイルの一部であることに注意してください。
ログ記録されたすべてのイベントを検討した後、aa-genprof プログラムは実行中に作成されたすべてのプロファイルを保存することを提案します。今回の場合、2 つのプロファイルを「Save」を使って一度に保存した後 (一つづづ保存することも可能です)、「Finish」でプログラムを終了しています。
実際のところ aa-genprofaa-logprof の洗練されたラッパーに過ぎません。aa-genprof は空のプロファイルを作成し、complain モードでそのプロファイルを読み込み、aa-logprof を実行します。aa-logprof はログ記録されたプロファイル違反に基づいてプロファイルを更新するツールです。このため、たった今作成したプロファイルを改良するために aa-genprof を改めて再実行することが可能です。
完全なプロファイルを作成したい場合、対象のプログラムに対するすべての合法的な使い方を試してみるべきです。dhclient の場合、Network Manager を介して実行したり、ifupdown を介して実行したり、手作業で実行することを意味します。こうすることで最終的に作成される /etc/apparmor.d/sbin.dhclient は完全なプロファイルに近いものとなるでしょう。
# Last Modified: Tue Sep  8 21:40:02 2015
#include <tunables/global>

/sbin/dhclient {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  capability net_bind_service,
  capability net_raw,

  /bin/dash r,
  /etc/dhcp/* r,
  /etc/dhcp/dhclient-enter-hooks.d/* r,
  /etc/dhcp/dhclient-exit-hooks.d/* r,
  /etc/resolv.conf.* w,
  /etc/samba/dhcp.conf.* w,
  /proc/*/net/dev r,
  /proc/filesystems r,
  /run/dhclient*.pid w,
  /sbin/dhclient mr,
  /sbin/dhclient-script rCx,
  /usr/lib/NetworkManager/nm-dhcp-helper Px,
  /var/lib/NetworkManager/* r,
  /var/lib/NetworkManager/*.lease rw,
  /var/lib/dhcp/*.leases rw,

  profile /sbin/dhclient-script flags=(complain) {
    #include <abstractions/base>
    #include <abstractions/bash>

    /bin/dash rix,
    /etc/dhcp/dhclient-enter-hooks.d/* r,
    /etc/dhcp/dhclient-exit-hooks.d/* r,
    /sbin/dhclient-script r,

  }
}