Docker 向け AppArmor セキュリティプロファイル

読む時間の目安: 3 分

AppArmor (Application Armor) は Linux におけるモジュールの一つであり、オペレーティングシステムやアプリケーションをセキュリティの脅威から保護するものです。 これを利用するには、システム管理者が各プログラムに対して AppArmor セキュリティプロファイルを関連づけます。 Docker は、AppArmor ポリシーがロードされ適用されているかどうかを調べます。

Docker はコンテナーに対するデフォルトプロファイルとしてdocker-defaultというものを、自動的に生成してロードします。 Docker 実行モジュールがtmpfsにこのプロファイルを生成してカーネルにロードします。

メモ

このプロファイルはコンテナーが利用するものであって、Docker デーモンが利用するものでは ありません

Docker Engine のデーモン用のプロファイルというものが存在していますが、それは現時点においてdebパッケージからはインストールされません。 デーモン用のプロファイルソースに興味のある方は、Docker Engine のソースディレクトリ内の contrib/apparmor にあるので参照してください。

ポリシーの理解

docker-defaultプロファイルは、コンテナーを起動させるためのデフォルトとなるものです。 これは幅広くアプリケーションとの互換性を提供しつつ、適度なセキュリティ保護を実現します。 このプロファイルは Go 言語のテンプレート から生成されます。

コンテナーを起動するとき、通常は docker-default ポリシーが適用されます。 ただしsecurity-optオプションを指定すれば、それがオーバーライドされま たとえば以下に示すのは、明示的にデフォルトポリシーを指定する例です。

$ docker run --rm -it --security-opt apparmor=docker-default hello-world

プロファイルのロード、アンロード

コンテナーが利用できるように、AppArmor 内に新たなプロファイルをロードします。

$ apparmor_parser -r -W /path/to/your_profile

そして--security-optを利用して、ユーザー独自のプロファイルを実行します。

$ docker run --rm -it --security-opt apparmor=your_profile hello-world

AppArmor からプロファイルをアンロードするには、以下のようにします。

# unload the profile
$ apparmor_parser -R /path/to/profile

プロファイル記述のための情報

AppArmor におけるワイルドカード検索(globbing)の文法は、他のワイルドカード検索とは多少異なります。 AppArmor プロファイルの文法に関しては、以下に示す情報を確認することを強くお勧めします。

Nginx 用のプロファイル例

ここに示す例では、Nginx 用に AppArmor プロファイルをカスタマイズします。 以下がそのカスタムプロファイルです。

#include <tunables/global>


profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network inet tcp,
  network inet udp,
  network inet icmp,

  deny network raw,

  deny network packet,

  file,
  umount,

  deny /bin/** wl,
  deny /boot/** wl,
  deny /dev/** wl,
  deny /etc/** wl,
  deny /home/** wl,
  deny /lib/** wl,
  deny /lib64/** wl,
  deny /media/** wl,
  deny /mnt/** wl,
  deny /opt/** wl,
  deny /proc/** wl,
  deny /root/** wl,
  deny /sbin/** wl,
  deny /srv/** wl,
  deny /tmp/** wl,
  deny /sys/** wl,
  deny /usr/** wl,

  audit /** w,

  /var/run/nginx.pid w,

  /usr/sbin/nginx ix,

  deny /bin/dash mrwklx,
  deny /bin/sh mrwklx,
  deny /usr/bin/top mrwklx,


  capability chown,
  capability dac_override,
  capability setuid,
  capability setgid,
  capability net_bind_service,

  deny @{PROC}/* w,   # deny write for all files directly in /proc (not in a subdir)
  # deny write to files not in /proc/<number>/** or /proc/sys/**
  deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,
  deny @{PROC}/sys/[^k]** w,  # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
  deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w,  # deny everything except shm* in /proc/sys/kernel/
  deny @{PROC}/sysrq-trigger rwklx,
  deny @{PROC}/mem rwklx,
  deny @{PROC}/kmem rwklx,
  deny @{PROC}/kcore rwklx,

  deny mount,

  deny /sys/[^f]*/** wklx,
  deny /sys/f[^s]*/** wklx,
  deny /sys/fs/[^c]*/** wklx,
  deny /sys/fs/c[^g]*/** wklx,
  deny /sys/fs/cg[^r]*/** wklx,
  deny /sys/firmware/** rwklx,
  deny /sys/kernel/security/** rwklx,
}
  1. このカスタムプロファイルを/etc/apparmor.d/containers/docker-nginxというファイルに保存します。

    この例におけるファイルパスは必須のものではありません。 本番環境においては別のものにすることができます。

  2. プロファイルをロードします。

    $ sudo apparmor_parser -r -W /etc/apparmor.d/containers/docker-nginx
    
  3. このプロファイルを使ってコンテナーを起動します。

    nginx をデタッチモードで起動します。

    $ docker run --security-opt "apparmor=docker-nginx" \
         -p 80:80 -d --name apparmor-nginx nginx
    
  4. exec により実行中のコンテナーに入ります。

    $ docker container exec -it apparmor-nginx bash
    
  5. 適当な操作を通じてプロファイルを確認します。

    root@6da5a2a930b9:~# ping 8.8.8.8
    ping: Lacking privilege for raw socket.
    
    root@6da5a2a930b9:/# top
    bash: /usr/bin/top: Permission denied
    
    root@6da5a2a930b9:~# touch ~/thing
    touch: cannot touch 'thing': Permission denied
    
    root@6da5a2a930b9:/# sh
    bash: /bin/sh: Permission denied
    
    root@6da5a2a930b9:/# dash
    bash: /bin/dash: Permission denied
    

おめでとうございます。 カスタムな AppArmor プロファイルを利用した、セキュアなコンテナーがデプロイできました。

AppArmor のデバッグ

dmesgを使ってデバッグすることができます。 またaa-statusを使えば、ロード済みプロファイルを確認することができます。

dmesg の利用

AppArmor に関して問題が発生したとしても、デバッグに役立つヒントをここに示します。

AppArmor はdmesgに対して極めて詳細なメッセージ出力を行います。 通常 AppArmor の出力は以下のようなものです。

[ 5442.864673] audit: type=1400 audit(1453830992.845:37): apparmor="ALLOWED" operation="open" profile="/usr/bin/docker" name="/home/jessie/docker/man/man1/docker-attach.1" pid=10923 comm="docker" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0

上の例ではprofile=/usr/bin/dockerという記述があります。 これはユーザーが、docker-engine(Docker Engine のデーモン)をロードしていることを意味します。

メモ

Ubuntu のバージョンが 14.04 より新しい場合は、何も問題はありませんが Trusty を利用している場合、docker container execを実行することで問題が発生する場合があります。

別のログ行を見てみます。

[ 3256.689120] type=1400 audit(1405454041.341:73): apparmor="DENIED" operation="ptrace" profile="docker-default" pid=17651 comm="docker" requested_mask="receive" denied_mask="receive"

この場合、プロファイルはdocker-defaultであり、privilegedモードでない限り、デフォルトでコンテナー上に実行されているものです。 このログ行は、AppArmor がコンテナー内のptraceを拒否していることがわかります。 これはまさに期待どおりの動作です。

aa-status の利用

どのプロファイルがロードされているかを確認するにはaa-statusを使います。 出力は以下のようになります。

$ sudo aa-status
apparmor module is loaded.
14 profiles are loaded.
1 profiles are in enforce mode.
   docker-default
13 profiles are in complain mode.
   /usr/bin/docker
   /usr/bin/docker///bin/cat
   /usr/bin/docker///bin/ps
   /usr/bin/docker///sbin/apparmor_parser
   /usr/bin/docker///sbin/auplink
   /usr/bin/docker///sbin/blkid
   /usr/bin/docker///sbin/iptables
   /usr/bin/docker///sbin/mke2fs
   /usr/bin/docker///sbin/modprobe
   /usr/bin/docker///sbin/tune2fs
   /usr/bin/docker///sbin/xtables-multi
   /usr/bin/docker///sbin/zfs
   /usr/bin/docker///usr/bin/xz
38 processes have profiles defined.
37 processes are in enforce mode.
   docker-default (6044)
   ...
   docker-default (31899)
1 processes are in complain mode.
   /usr/bin/docker (29756)
0 processes are unconfined but have a profile defined.

上の出力からわかることは、docker-defaultプロファイルがさまざまなコンテナー PID 上において実行していて、enforceモードにより動作しているということです。 つまりdocker-defaultプロファイルの範囲外のところで AppArmor は、dmesgにおいてブロックと監査を効果的に行っているということです。

さらに /usr/bin/docker(Docker Engine デーモン)プロファイルはcomplainモードにより動作していることもわかります。 これは AppArmor がプロファイルの範囲外にて、dmesgに対して のみ ログ出力を行っているということです。 (Ubuntu Trusty の場合は例外で、enforceモードにより動作するものがあります。)

Docker 向け AppArmor コードの提供

上級ユーザーやパッケージ管理者は、/usr/bin/docker(Docker Engine デーモン)に対するプロファイルを、Docker Engine ソースリポジトリ内の contrib/apparmor から検索し利用しています。

コンテナー向けのdocker-defaultプロファイルは profiles/apparmor にあります。

AppArmor, security, docker, documentation