【Dockerの最新機能を使ってみよう】Dockerコンテナで利用できるリソースや権限を制限する 2ページ

ホスト−コンテナ間でのユーザー/グループの分離

 続いては、Dockerが持つ権限分離機構について紹介していこう。Dockerのデフォルト設定ではコンテナ内のプロセスはroot権限で実行される。Dockerではgroupやnamespaceといった機構を使ってコンテナ内のプロセスをほかのプロセスからアクセスできないよう分離しているが、コンテナ外から見るとコンテナ内のプロセスは特権を持っているように見えてしまうのだ。コンテナ内のプロセスがコンテナ内のファイルシステムにのみアクセスするのであれば問題は無いが、ボリュームなどの機構を使ってホストのディレクトリをマウントする場合、コンテナ内のプロセスはroot権限でマウントしたディレクトリにアクセスできてしまう。

 たとえば、以下のように-vオプションを利用してホストのルートディレクトリをコンテナの/hostrootディレクトリにマウントした場合、コンテナ内から/hostrootディレクトリ経由でDockerホストのすべてのディレクトリにアクセスできてしまう。

# docker run -ti -v /:/hostroot busybox

 通常このような設定を行うことはないだろうが、設定ミス等で意図しないディレクトリをコンテナ内にマウントしてしまうことは考えられる。そこでDocker 1.10では、コンテナ内におけるユーザー/グループをコンテナ外のユーザー/グループと分離する「User Namespaces」という機構が導入された。これによってコンテナ内のrootユーザーをDockerホスト上では別のユーザーとして扱うことが可能になり、Dockerホストへの無制限のアクセスを防ぐことができるようになる。

 User Namespacesを有効にするには、Dockerデーモンの起動時に「–userns-remap」オプションを指定すれば良い。このオプションでは、以下の書式でコンテナ内のrootユーザー/rootグループに対応させるユーザー/グループを指定できる。

--userns-remap=<ユーザーID>
--userns-remap=<ユーザーID>:<グループID>
--userns-remap=<ユーザー名>
--userns-remap=<ユーザー名>:<グループ名>
--userns-remap=default

 ユーザーIDもしくはユーザー名のみが指定された場合、コンテナ内のrootユーザーはコンテナ外では指定したユーザーとして認識される。また、グループIDやグループ名が指定された場合は、コンテナ内のrootグループが指定されたグループとして認識される。なお、「default」が指定された場合は「dockermap」というユーザー/グループが指定されたものとして認識される。

 たとえばfedoraの場合、Dockerデーモン実行時に与えるオプションは/etc/sysconfig/docker内の「OPTIONS=」行で指定できるので、ここに以下のように「–userns-remap=」オプションを追加すれば良い。

OPTIONS='--userns-remap=default --selinux-enabled'

 また、コンテナ内とコンテナ外でのユーザーID/グループIDの対応付けを設定するため、/etc/subuidおよび/etc/subgidファイルの設定も必要となる。ここでは、以下のような形でIDの対応付けを記述する。

<ユーザー名/グループ名>:<コンテナ内でrootユーザーとして使用するUID/GID):65536

 たとえば/etc/subuidファイルに以下のように記述すると、コンテナ内のroot(UID:0)はコンテナ外ではUIDが300000のユーザーとして扱われる。

dockremap:300000:65536

 同様に/etc/subgidファイルにも同じ内容を記述し、Dockerデーモンを再起動すると設定が有効になる。

 それでは、この設定が実際に有効になっているかを確認してみよう。まず、通常通りbusyboxコンテナを起動し、コンテナ外からpsコマンドでプロセスを確認してみると、コンテナ内のプロセスは先ほど設定した「300000」というユーザーIDで実行されていることが分かる。

↓コンテナを起動する
# docker run -ti --rm busybox
↓別のシェル上でpsコマンドを実行する
# ps aux
  
root      3311  0.2  2.9 125100 29736 pts/1    Sl+  22:06   0:00 docker run -ti --rm -v /var/testdata:/testdata busybox
  
↓コンテナ内のプロセスが先ほど設定した「300000」というユーザーで実行されている
300000    3327  0.4  0.0   1208     4 pts/0    Ss+  22:06   0:00 sh
  

 また、Dockerホストのroot権限で/var/testdataというディレクトリを作成し、それをコンテナにボリュームとしてマウントしてアクセスしてみると、パーミッションがないとして書き込みなどの操作が行えないことが分かる。

↓ディレクトリを作成する
# mkdir /var/testdata
# ls -ld /var/testdata
drwxrwxr-x. 2 root root 17  5月 12 21:33 /var/testdata

↓このディレクトリをボリュームとして/testdataにマウントしたコンテナを起動する
# docker run -ti --rm -v /var/testdata:/testdata busybox

↓ディレクトリのオーナー/グループがrootではなく「65534」に設定されている
/ # ls -ld /testdata
drwxrwxr-x    2 65534    65534           17 May 12 12:33 /testdata

↓ディレクトリへの書き込みや所有者変更といった操作は拒否される
/ # touch /testdata/foo
touch: /testdata/foo: Permission denied
/ # chown root:root /testdata
chown: /testdata: Operation not permitted

 いっぽう、ホスト上でこのディレクトリの所有者を/etc/subuidファイルで指定した「300000」に指定すると、コンテナ内でこのディレクトリへのアクセスが可能になる。

↓ホスト上で/var/testdataディレクトリの所有者を変更する
# chown 300000 /var/testdata
# ls -ld /var/testdata
drwxrwxr-x. 2 300000 root 17  5月 12 21:33 /var/testdata

↓このディレクトリをボリュームとして/testdataにマウントしたコンテナを起動する
# docker run -ti --rm -v /var/testdata:/testdata busybox

↓/testdataディレクトリの所有者がrootになっている
/ # ls -ld /testdata
drwxrwxr-x    2 root     65534           17 May 12 12:33 /testdata

↓ディレクトリへの書き込みも行える
/ # touch /testdata/foo