Ubuntu Weekly Recipe

第798回Ubuntuのセキュリティを支えるAppArmor入門

Ubuntuではセキュリティ対策の一環としてAppArmorを採用しています。AppArmorを使えば、任意のプログラムに対して、意図しないファイルやデバイスのアクセスを阻害したり、サブプロセスに対するセキュリティ制約をかけたりできます。今回はあまり意識することのないものの、知っておくといつか役に立つかもしれない、実際に役に立つ時はあまり来てほしくないAppArmorについて紹介しましょう。

AppArmorとMACとLSMと

AppArmor名前ベースの強制アクセス制御で、LSMを用いて実装されている仕組みと紹介されることがあります。これはどういう意味でしょうか。

まずはAppArmorの特徴となる名前ベース(もしくはパス名ベース)についてですが、これは「セキュリティ設定を対象となるファイルパスを元に設定する」ことを意味します。つまりファイルパスごとに、何を許可し何を許可しないかの設定一式(プロファイル)を設定できるようになっているのです。このプロファイルを適用することでファイルごとに異なる設定を適用できます。たとえばPDFビューワーであるEvinceのプロファイル/etc/apparmor.d/usr.bin.evinceの一部を抜粋すると、次のような内容が記述されています。

/usr/bin/evince {
  (中略)
  / r,
  /**/ r,
  (中略)
  owner @{HOME}/** rw,
  owner /media/**  rw,

いちばん最初の/usr/bin/evinceがこのプロファイルを適用する対象の「名前(ファイルパス⁠⁠」です。ブロックの中にいろいろな制約を記述していくことになります。たとえば上記の例の前半には、⁠ルートファイルシステムのディレクトリについては読み込みのみ許可」を書いています。これはEvinceでファイルを開いたり保存したりする時に、ファイルダイアログでルートファイルシステムからたどれるようにするためです。後半では「特定のファイルパスについて自分が所有者になっているのであれば、読み込みだけでなく書き込みもできる」ことを意味します。

このように「このファイルパスやそこから起動するプロセスについて、特定の処理・機能を許可する・許可しない」をプロファイルとして定義できるのがAppArmorの最大の特徴です。それに対して、AppArmorとよく対比されるSELinuxの場合は「ファイルやプロセスのオブジェクトに対して、設定(ラベル)を適用する」形を取ります[1]

次にAppArmorが提供する強制アクセス制御(MAC:Mandatory Access Control)について説明しましょう。まずはじめに、UbuntuをはじめとするLinux/Unixの従来のアクセス制御のシステムでは、ファイルやディレクトリに対して「パーミッション」を設定することで、誰が読み込み・書き込み・実行を許可するかを設定できるようになっています。この場合、パーミッション設定の正しさは、そのファイルやディレクトリの所有者かその上位の権限を持つユーザーに委ねられます。端的に言うと管理者(rootやsudoでroot相当の権限を得られるユーザー)であれば、⁠なんでもできる」ようになっているのです。このような所有者がアクセス制御を設定する方式を任意アクセス制御(DAC:Discretionary Access Control)と呼びます[2]

AppArmorの「強制アクセス制御(MAC⁠⁠」とは、⁠任意アクセス制御(DAC⁠⁠」における「任意」の部分が「強制」になったもので、管理者ですら強制的にアクセス制御の影響を受ける仕組みです。たとばあるファイルfoo.txtが、所有者だけが読み込みだけできる設定になっていたとします。パーミッションで言うところのr--------になっているケースです。DACの場合は所有者以外の他のユーザーがless foo.txtすると権限がないと怒られますが、その人がsudoで任意のコマンドを実行できる場合はsudo less foo.txtとすれば読めてしまいます。AppArmorでは適切なプロファイルを設定することで、管理者すら読み込み不可なファイルを作成できます[3]

最後のLSM(Linux Security Module)は、AppArmorやSELinuxのような機能を実現するためのLinuxカーネルのフレームワークです。これはAppArmorやSELinuxだけでなく、lockdownやcapabilities機能でも利用されています。AppArmorを使う上でLSMを意識することはありませんが、そういうものがあるという点だけ覚えておくと良いでしょう。

enforcedとcomplainingとステータス

AppArmorには主に次のような3種類のモードが存在します。

  • enforced(適用)モード:プロファイルで許可されていない処理を行おうとした場合は、エラー扱いにしログに残す
  • complaining(学習)モード:プロファイルで許可されていない処理を行う場合、ログに残すものの、エラー扱いにはしない
  • unconfined(非制限)モード:何も制限しない

実際には上記以外にも、拒否した際にそのタスクを終了させるkillモードや、拒否した処理だけではなく許可した処理もすべてログに残すauditモード存在しますが、UbuntuでAppArmorを使うだけなら上記の3種類だけ覚えておけば十分です。

complainingモードについては、⁠ログに残すだけ」です。よって実態としては「DACの範囲内でなんでもできる」状態である点に注意が必要です。主にプロファイルの作成時に、とりあえずログを残すようにして、プロファイルで許可されていない処理を行ったログが出るようなら随時プロファイルを更新することを目的としています。

これらのモードはプロファイル単位で設定します。つまりプロファイルのロード時に、enforcedモードかcomplainingモードを指定するわけです。ちなみにapparmor-utilsパッケージに含まれる、aa-enforceaa-complainコマンド、aa-unconfinedを利用すると、バイナリ・プロファイル単位で任意にenforced/complaining/unconfinedモードを切り替えることも可能です。

Ubuntuの場合、システムの起動時に設定済みのプロファイルを一通りロードするようになっています。具体的に関係するファイルやディレクトリは次のとおりです。

  • /etc/apparmor.d
  • /usr/sbin/apparmor_parser
  • /etc/apparmor/parser.conf
  • /usr/lib/apparmor/
  • /usr/bin/aa-enabled
  • /usr/bin/aa-exec
  • /usr/bin/aa-features-abi
  • /usr/sbin/aa-remove-unknown
  • /usr/sbin/aa-status
  • /usr/sbin/aa-teardown

まず最初に/etc/apparmor.dには各種プロファイルが保存されます[4]。プロファイルは基本的に「コマンドパスのスラッシュをドットにしたもの」をファイル名としますが、それ以外の名前になる場合もあったり、共通処理をまとめてプロファイルからincludeされるものなども置かれています。またforce-complain以下に、プロファイル本体へのシンボリックリンクを置いておくと、そのプロファイルはcomplainingモードで動作することになります。同じようにdisable以下にプロファイル本体のシンボリックリンクを置くと、起動時に読み込まれなくなります。

このプロファイルを起動時にロードするのが/usr/sbin/apparmor_parserコマンドです。このコマンドの挙動はparser.confで変更できますが、挙動を変えることはあまりありません。/usr/lib/apparmorなどにはsystemdのapparmor.serviceが起動時に/usr/sbin/apparmor_parserコマンドを呼び出すための便利なスクリプト群が配置されています。

aa-FOOなコマンドは、AppArmorの挙動を確認したり、稼働中に変更したりするコマンドです。またapparmor-utilsパッケージをインストールするとさらにいくつかのコマンドが追加されます。たとえばAppArmorが有効化されているかは次のコマンドで確認できます。

$ aa-enabled
Yes

さらにファイルやプロセスのプロファイルへの適用状態はaa-statusで確認できます。

$ sudo aa-status
apparmor module is loaded.
113 profiles are loaded.
55 profiles are in enforce mode.
   /snap/snapd/20290/usr/lib/snapd/snap-confine
   /snap/snapd/20290/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /snap/snapd/20671/usr/lib/snapd/snap-confine
   /snap/snapd/20671/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/bin/evince
   (中略)
1 profiles are in complain mode.
   /usr/sbin/sssd
0 profiles are in prompt mode.
0 profiles are in kill mode.
57 profiles are in unconfined mode.
   /bin/toybox
   (中略)
13 processes have profiles defined.
13 processes are in enforce mode.
   /usr/sbin/cups-browsed (2092)
   /usr/sbin/cupsd (1392)
   (中略)
0 processes are in complain mode.
0 processes are in prompt mode.
0 processes are in kill mode.
0 processes are unconfined but have a profile defined.
0 processes are in mixed mode.

aa-statusの実行結果には、上から順番に次のような情報が含まれています。

  • カーネルのapparmor機能が有効化されているかどうか
  • プロファイルの総数
  • enforcedなプロファイルの対象となっているコマンドのファイルパス
  • complainingなプロファイルの対象となっているコマンドのファイルパス
  • prompt/killモードになっているプロファイルのコマンドのファイルパス(基本的に0になる)
  • unconfinedモード(プロファイルが用意されていない)コマンドのファイルパス
  • プロファイルが設定されているプロセスの数
  • enforcedなプロファイルの対象となっているプロセスの実行パス
  • complainingなプロファイルの対象となっているプロセスの実行パス
  • prompt/killモードになっているプロファイルのプロセスの実行パス(基本的に0になる)
  • プロファイルが設定されているけれどもunconfinedなプロセスの実行パス
  • mixedモードになっている(complainingとenforcedが混じり合っている)プロセスの実行パス

基本的にはenforce/complain/unconfinedになっているところだけ確認すれば良いでしょう。それ以外については通常のUbuntu環境だと、0になっているようです[5]

AppArmorの有効化・無効化

Ubuntuの場合、AppArmorは最初から有効化されています。前の項目にあるように、起動時に必要なプロファイルをロードすることで、適切な設定がされた状態になっています。普通にUbuntuを使う限りにおいて、これを変更する必要はありません。しかしながら、何らかの理由でどうしても無効にしたい場合があるでしょう。AppArmorを無効化するにはいくつかの方法が存在します。

もし常に無効化したい場合は、systemdのapparmor.serviceを止めてしまうのが確実です。

$ sudo systemctl stop apparmor.service
$ sudo systemctl disable apparmor.service

これにより次回の起動時からプロファイルはロードされなくなり、すべてのプロセスがunconfinedモードとして動作します。ただしカーネル側のAppArmorの機能自体は存在するため、任意のプロファイルをあとからロードすることは可能です。

もしカーネルの機能も含めて無効化したいのであれば、/etc/default/grubGRUB_CMDLINE_LINUX_DEFAULTapparmor=0を追加して、sudo update-grubを実行して再起動してください。この場合は/sys/kernel/security/apparmor/も作成されなくなります。

特定のプロファイルのみを無効化したい場合は、apparmor_parserコマンドでプロファイルをアンロードできます。

$ sudo apparmor_parser -R /etc/apparmor.d/プロファイル名

たとえば/etc/apparmor.d/usr.bin.tcpdumpには次のような設定があります。

  audit deny @{HOME}/.* mrwkl,

これはホームディレクトリのドットファイルのmmap・読み込み・書き込み・ロック・リンクを許可しないことを意味して、たとえばホームディレクトリのドットファイルにパケットキャプチャを書き込もうとすると、エラーとなりますし、ログにもその旨が記録されます。

$ sudo tcpdump -w ~/.test.log -i eno1
tcpdump: /home/shibata/.test.log: Permission denied

$ journalctl -r | grep apparmor| head -1
(略) apparmor="DENIED" operation="mknod" class="file" profile="tcpdump" name="/home/shibata/.test.log" (略)

上記のようにsudo apparmor_parser -R /etc/apparmor.d//etc/apparmor.d/usr.bin.tcpdumpを実行した上で、再度tcpdumpを実行すると、エラーにならないことから、プロファイルがアンロードされたことがわかるでしょう。再ロードはsudo apparmor_parser /etc/apparmor.d//etc/apparmor.d/usr.bin.tcpdumpを実行するだけです。

単にプロファイルの中身を書き換えてそれを反映したいのであれば、次のように実行してください。

$ sudo apparmor_parser -r /etc/apparmor.d/プロファイル名

大文字の-R(remove⁠⁠」から小文字の-r(replace⁠⁠」になったのがポイントです。ちなみにsudo systemctl reload apparmor.serviceを実行すると、すべてのプロファイルを再読込します[6]


ここまでUbuntuにおいてはAppArmorとその設定(プロファイル)によって、パーミッションとは別に各種アクセスや操作が拒否されうること、さらには拒否された結果はシステムのログに残ることがわかりました。また、プロファイルを一時的に無効化する方法も存在しうることがわかりました。次回はこのAppArmorのプロファイルの作成方法について紹介しましょう。

おすすめ記事

記事・ニュース一覧