Dockerの実行ユーザ

Docker でコンテナを起動するとき、root ユーザでプロセスを起動してしまうと危険です。

参考: Dockerコンテナを本番環境で使うためのセキュリティ設定 - Qiita

公開されている Docker イメージの多くは何もしなければ root で実行するようになっているので、実行ユーザを変更する設定が必要になります。

最も簡単で効果が高いのは、Dockerfile 内でユーザを作成して実行ユーザに指定する方法です。 コンテナ起動時に docker run -u <uid> で UID を指定する方法や、Kubernetes の SecurityContext を使う方法などもあります。

例えば、次のような感じになります。

FROM debian

RUN useradd docker
USER docker

CMD ["bash"]

これで bash が docker ユーザで実行されます。

これだけでもまあいいのですが、useradd にはいろいろオプションがあり、どのオプションを指定すればいいのか考えてみました。

Dockerfile でよく指定されるオプションには次のようなものがあります。

  • -g: name or ID of the primary group of the new account
  • -l: do not add the user to the lastlog and faillog databases
  • -m: create the user’s home directory
  • -M: do not create the user’s home directory
  • -r: create a system account
  • -s: login shell of the new account
  • -u: user ID of the new account
  • -U: create a group with the same name as the user

それぞれについてみていきます。

-g はグループを指定します。グループの gid も uid と同じにしていたほうがわかりやすいので -g で指定することになります。

-l ですが、lastlog と faillog はほぼ意味がないのでつけといて思います。

-m/-M は、例えばそのユーザでシェルを起動して運用することが想定される場合はホームディレクトリは作成しておいた方が便利です。

-r を指定するとシステムアカウントとしてユーザが作成されます。/etc/login.defs に定義されているシステムアカウントの範囲で uid が設定されます。また、ホームディレクトリが作成されません。-u で uid を指定し、ホームディレクトリについては -m/-M で指定するのでこのオプションは不要です。

-s /bin/false でリモートログインを禁止できます。/bin/false や /sbin/nologin が指定してあっても、docker exec -u <uid> sh や sudo -u <user> sh によってそのユーザでシェルを実行できます。防げない攻撃がないこともないのでセキュリティ向上のために指定しておいてもいいでしょう。

-u で明示的に uid を設定できます。これを指定しない場合は自動で番号を割り振られます。コンテナ外でユーザを指定するときは uid が必要になったりするので、明示的に設定しておいたほうがいいです。

-U でユーザと同じ名前のグループを作成しますが、gid が uid と同じになるとは限らないのでグループは -g で指定した方がいいです。

つまり、次のようにユーザを作成するといいと思います。

RUN groupadd -g 61000 docker
RUN useradd -g 61000 -l -M -s /bin/false -u 61000 docker

ユーザでシェルを起動して運用が発生する場合1は、次のように -M ではなく -m を使ってホームディレクトリを作成した方が便利です。

RUN groupadd -g 61000 docker
RUN useradd -g 61000 -l -m -s /bin/false -u 61000 docker

uid が 61000 なのは、だいたい自動で生成される uid が 1000〜60000 に設定されている2ので、その範囲から外しているからです。ちなみに GKE のホスト VM は 5000〜60000 になっていて、uid を 5000 とかにすると GKE が作ったユーザと uid がかぶる可能性があります。

Footnotes

  1. 例えば、bundle exec rails console による運用があるとか ↩

  2. /etc/login.defs に書いてある ↩