【Rootless Docker】 Dockerを安全に一般ユーザで実行する

世の中では,Dockerの利用者がかなり増えてきていますね.ただ,Dockerはまだまだ発展途上?なのかユーザが多くなって開発が盛んになったためか,日々機能が更新されています.

今回は,Dockerのユーザ権限周りに関してのまとめてみました.

Dockerを一般ユーザで実行しよう!

Dockerでは,通常管理者権限(root)を通じて操作します.そのため,Root以外のユーザはDockerを使用することができません.

しかし,一般ユーザであったとしてもDockerを使用したいといった要望は割と多いです.その方法として,以前までは,Dockerの実行許可を与えるユーザにグループに追加する方法が一般的でした.ただ,セキュリティ面に問題があったため,あまり推奨される方法ではありませんでした

そこで,Docker Engine v19.03で実験的にRootlessモードが導入され,Docker Engine v20.10から実験的な機能から卒業しました.今後は一般ユーザでDockerを使用する場合Rootlessモードを導入するべきでしょう

Rootless Dockerでのイメージの保存場所の変更方法も記載しています.

目次

この記事に記載されていること

  • Rootlessモード対応のDockerをインストールと設定
  • 一般ユーザでDockerを使用する(Rootlessモード)
  • Rootless Dockerの運用方法やベストプラクティス
  • Rootless Dockerでのイメージ保存場所,また保存場所の変更方法
  • RootlessユーザでのDocker Composeの扱い

Dockerのインストール

Rootless Dockerの大前提として,Dockerそのものをインストールする必要があります.

Dockerのインストールに関しては公式サイトを参照ください.

Root以外でDockerを実行する以前までの方法

!!!現在,この方法は推奨されていません!!!

Docker利用するユーザをdockerというグループに追加します.この方法を利用すると非常に簡単に一般ユーザでDockerを利用することが可能ですが,セキュリティ上の問題が懸念されます.


gpasswd -a <your_username> docker
chgrp docker /var/run/docker.sock
systemctl restart docker 

Rootlessモードとは

これまでのDockerおよびDockerエンジンの実行には特定の権限が必要となるため,rootが必須でした.

一般ユーザでDockerを起動するために,「Dockerグループにユーザを追加する方法」は実質的にroot権限の一部を与えるとことと同義であると考えられ,セキュリティ上不安視されてきました.

Rootless モードは,名前の通りRootではない一般ユーザがDockerを実行できるようなモードです.デーモンやコンテナ・ランタイムにおける潜在的な脆弱性を軽減することができます.Dockerの実行をユーザの名前空間内で実行するため,より安全性が高くなります

具体的な仕組みとしては,ユーザの名前空間を活用することで,ホスト側のユーザIDとDocker側のユーザIDをマッピングします.マッピングすることにより,一般ユーザをrootとして見せかけることDockerを起動します.

下図が分かりやすかったため引用させてもらいました.

引用元:https://www.docker.com/blog/experimenting-with-rootless-docker/

詳しい説明については下記URLに示されています.

https://docs.docker.com/engine/security/rootless/
https://medium.com/nttlabs/rootless-docker-12decb900fb9
https://www.docker.com/blog/experimenting-with-rootless-docker/

Rootless Dockerの注意点

Rootless Dockerを使用したとしても,Docker周りのセキュリティ問題は完全に解決されるわけれはありません.ただ,少なくとも従来の方法(Dockerグループに追加)と比較するとセキュリティレベルが向上していることは間違いありませんので,従来の方法からは移行したほうがいいと思います.

Rootlessモード対応のDockerのインストールと設定方法

適当なユーザを作成

RootlessモードでDockerを使用するユーザを作成します.すでに作成済みユーザをそのまま使用する場合は不要です.


useradd -m -d /home/docker_user -s /bin/bash docker_user

必要なパッケージのインストール


apt install uidmap

Dockerデーモンを停止します.


systemctl disable --now docker.service docker.socket

Rootless Dockerのインストール

ここから先は,Dockerを使用したい一般ユーザで実行します.ここでは,ユーザ名はdocker_userを使用します.

次のコマンドで,Rootless Dockerをインストールします.


curl -fsSL https://get.docker.com/rootless | sh

下記のような出力が確認されればOKです.


# Installing stable version 20.10.12
...
Client:
 Version:           20.10.12
 API version:       1.41
 Go version:        go1.16.12
 Git commit:        e91ed57
 Built:             Mon Dec 13 11:40:57 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true
Server: Docker Engine - Community
 Engine:
  Version:          20.10.12
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.12
  Git commit:       459d0df
  Built:            Mon Dec 13 11:46:12 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.4.12
  GitCommit:        7b11cfaabd73bb80907dd23182b9347b4245eb5d
 runc:
  Version:          1.0.2
  GitCommit:        v1.0.2-0-g52b36a2d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
+ systemctl --user enable docker.service
Created symlink /home/docker_user/.config/systemd/user/default.target.wants/docker.service → /home/docker_user/.config/systemd/user/docker.service.
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger docker_user`
[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Make sure the following environment variables are set (or add them to ~/.bashrc):
export PATH=/home/docker_user/bin:$PATH
export DOCKER_HOST=unix:///run/user/1002/docker.sock

設定

上記の出力の末尾に記載されている内容を$HOME/.bashrcの末尾に以下のように記述します


...
+ export PATH=/home/docker_user/bin:$PATH
+ export DOCKER_HOST=unix:///run/user/1002/docker.sock

下記コマンドで,設定を反映します.


source $HOME/.bashrc

Dockerデーモンの起動

デーモンを起動します.


systemctl --user start docker

システム起動時にデーモンが起動するように設定します.


systemctl --user enable docker
sudo loginctl enable-linger $(whoami)

ユーザにsudo権限がない場合は,rootでloginctl enable-linger <ユーザ名>を実行してください.

動作確認

hello-worldのイメージを起動します.


docker run hello-world

下記のようなメッセージが出ればOKです.


Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:97a379f4f88575512824f3b352bc03cd75e239179eea0fecc38e597b2209f49a
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/
For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Rootless Dockerの学習方法

Rootless Dockerを使用する場合も,通常のDocker(Rootful Docker)とコマンドは基本的に同じなので,一般的なDockerの学び方で十分です.

Rootless Docker運用とベストプラクティス

Rootful Dockerとはすべてが同じわけではなく,操作感が多少異なる点があります.

それに関して,運用方法と個人的ベストプラクティスをまとめておきます.

Docker Imageの保存場所

通常のDocker(rootful docker)であれば,Dockerイメージの保存場所は/var/lib/docker/overlay2/に保存されています.

Rootless Dockerは当然ながらユーザごとにDockerデーモンが起動しているため,通常のDockerとは異なる場所にイメージが保存されています.

Rootless Dockerでのイメージの保存場所は~/.local/share/docker/overlay2に保存されています.

Dockerイメージの保存場所を変更する

~/.config/docker/daemon.jsonを編集して,Dockerイメージの保存場所を変更します.このファイルが見つからない場合新たに作成する必要があります.


{"data-root":"/path/to/image"}

Dockerデーモンを再起動して設定を反映します.


systemctl --user restart docker

Docker Compose

Rootlessモードにおいても,Docker Composeは利用できます.

インストール方法は公式サイトのものを少し変更して,下記のように行います.


curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o ~/bin/docker-compose

実行権限を与えます.


chmod +x ~/bin/docker-compose

任意のバージョンを使用したい場合,公式のGitHubから最新バージョンを確認して,適宜URLを変更してください.

https://github.com/docker/compose/releases

変更点は,インストール先のディレクトリのみです.~/bin/はすでにパスが通っているので,そのまま利用可能です.

通常のDocker Composeとの違いや注意点としては,ルートレスではユーザの権限の問題でポートを1024以上にする必要があるようです.ポート81を使おうしたときに下記のようなエラーが発生しました.

ERROR: for xxxxxx Cannot start service pgadmin: driver failed programming external connectivity on endpoint xxxxxx (YYYYYYYYYYYYY): Error starting userland proxy: error while calling PortManager.AddPort(): cannot expose privileged port 81, you can add 'net.ipv4.ip_unprivileged_port_start=81' to /etc/sysctl.conf (currently 1024), or set CAP_NET_BIND_SERVICE on rootlesskit binary, or choose a larger port number (>= 1024): listen tcp4 0.0.0.0:81: bind: permission denied

管理者視点のメリット・デメリット

「従来のグループに追加する方法」では,各ユーザに対してグループ追加をする必要がありました.Rootlessモードを使用する場合,Rootless Dockerに必要なパッケージを予めインストールする作業のみで済みます.あとは,使用したいユーザが各自設定を行うので,管理者としては作業が低減されます.(とはいえ,セキュリティ上重要なサーバにはDockerの使用を許可しないという場合が多いがほとんどだと思いますが...)

デメリットは,管理者の知らぬところでユーザがコンテナイメージをPullしすぎてディスク容量を圧迫してしまうことでしょうか...

一般ユーザとしてサーバ機能を構築する

Rootless Dockerを使用すると興味深いことに,一般ユーザとしてサーバ機能を持つコンテナを起動することができます.管理者があえて一般ユーザとしてコンテナサーバを起動することで,権限を切り離し安全性を確保するということができます.注意点としては,ポートはランダムポートである1024以上のみが使用可能です.

まとめ

Rootlessモードは,従来のDockerグループにユーザを追加する方法と比較して,より安全な方法になります.

この記事では,Rootless Dockerの導入方法,Dockerイメージの保存場所を変更する方法などを記載しました.

よかったらシェアしてね!
目次