Docker の Rootless を考える
何も考えない場合 Docker は root 権限で動くが、そうしたければ非 root 権限( = Rootless)で動かすこともできる。
Docker の実行権限について

Docker のデーモンとコンテナはプロセスとして動き、それぞれが権限を持つ。
そのため Docker の話をしていて Rootless という単語が出てきたら、何に対して Rootless なのか(デーモンが?コンテナが?)を意識する必要がある。
以下で Docker デーモン・Docker コンテナと root 権限・非 root 権限の組み合わせを考える。
| Docker デーモン |
Docker コンテナ |
説明 |
| root |
root |
デフォルト。何でもできて便利だが脆弱性によってホスト、コンテナともに乗っ取られるかもしれない。 |
| root |
非 root |
デフォルトよりマシだが、ホスト側の脆弱性によってホストを乗っ取られるかもしれない。 |
| 非 root |
root |
デフォルトよりマシだが、コンテナ側の脆弱性によってコンテナを乗っ取られるかもしれない。 |
| 非 root |
非 root |
デフォルトに比べてホスト、コンテナともに被害は抑えられるが、ネットワークやファイル読み書きで問題が出ることがある。 |
権限は安全と利便性の両方を考慮して決めるのが良いと思う。
デーモン・コンテナ共にユーザー権限で間に合うのであればそうすれば良いし、5 分以内にコンテナを立ち上げないと地球が爆発してしまう事態であれば両方 root で済ませてしまってもいいかもしれない。
Rootless モード
Rootless モードについて
Rootless モード(Rootless Docker ともいう)を使うと Docker デーモンを非 root 権限で動作させることができる。
Rootless モードを使うとセキュリティが向上する一方で、以下のようなデメリットも有る。
- 80 や 443 などの Well-known ポートを使うには工夫が必要となる
- 権限が狭まる分、Docker コンテナが上手く起動しないこともある
docker context lsで Docker のコンテキスト(接続先デーモン)の一覧と権限を確認できる。
アスタリスクの行のDOCKER ENDPOINTがunix:///var/run/docker.sockであれば root 権限で動作している。
| $ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
|
Rootless モードをインストールする
Rootless mode | Docker Docs
| $ sudo apt install uidmap
|
従属 UID/GID が 65536 以上であることを確認する。
| $ grep ^$(whoami): /etc/subuid
ユーザー名:100000:65536
$ grep ^$(whoami): /etc/subgid
ユーザー名:100000:65536
|
root 権限の Docker デーモンが動いている場合は止める必要がある。
| # Dockerデーモン(docker.service)とソケット(docker.socket)を停止し、無効化する
$ sudo systemctl disable --now docker.service docker.socket
# Dockerソケットを削除する
$ sudo rm /var/run/docker.sock
|
ユーザーに Rootless Docker をインストールする。ユーザー権限でインストールするので sudo は要らない。
| $ /usr/bin/dockerd-rootless-setuptool.sh install
|
Rootless になっているか確認する。
| $ docker info
Client: Docker Engine - Community
Version: 28.5.0
Context: rootless
# 略
Security Options:
seccomp
Profile: builtin
rootless
cgroupns
|
| $ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
rootless * Rootless mode unix:///run/user/1000/docker.sock
|
| $ systemctl --user restart docker.service
|
Rootless モードを無効にする
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | # Rootless Dockerのデーモンを停止する
$ systemctl --user stop docker.service
$ systemctl --user disable docker.service
# Rootless Dockerのソケットを削除する
$ sudo rm /run/user/1000/docker.sock
# コンテキストを通常に戻す
$ docker context use default
# Dockerを再起動する
$ sudo systemctl enable docker.service docker.socket
$ sudo systemctl restart docker.service docker.socket
$ docker info
Client: Docker Engine - Community
Version: 28.5.0
Context: default
|
Rootless モードを有効にする
| $ sudo systemctl stop docker.service docker.socket
$ sudo systemctl disable docker.service docker.socket
$ sudo rm /var/run/docker.sock
$ docker context use rootless
$ systemctl --user enable docker.service
$ systemctl --user restart docker.service
$ docker info
Client: Docker Engine - Community
Version: 28.5.0
Context: rootless
|
Rootless モードで Well-known ポートを使う
setcap コマンドで特定のバイナリに Well-known ポートのバインド権限を与えることができる。
Rootless Docker はrootlesskitを使ってポートフォワーディングを行うのでrootlesskitにバインド権限を与える。
1
2
3
4
5
6
7
8
9
10
11
12 | # rootlesskitにWell-knownポートのバインド権限を与える
# cap_net_bind_service=ep: Well-knownポートのバインド権限をep(effective+permitted)
$ sudo setcap cap_net_bind_service=ep $(which rootlesskit)
$ systemctl --user restart docker.service
# 権限を確認する
$ getcap $(which rootlesskit)
/usr/bin/rootlesskit cap_net_bind_service=ep
# 権限を削除する
$ sudo setcap -r $(which rootlesskit)
$ systemctl --user restart docker.service
|
コンテナを非 root 権限で動作させる
docker
--user: 1000:1000で Docker を動かしているユーザと同じ権限で動作させることができる。
Dockerfile
USERで root 以外のユーザーを指定することで非 root 権限で動作させることができる。
docker-compose.yml
user: 1000:1000で Docker を動かしているユーザと同じ権限で動作させることができる。
コンテナの実行権限を確認する
コンテナがどの権限で動いているかは以下のコマンドで確認できる。
| $ docker exec $CONTAINER_NAME id
uid=0(root) gid=0(root) groups=0(root)
|
デーモンを常駐させる
systemd のユーザーサービスは SSH セッションを閉じると終了してしまう。
Rootless Docker は~/.config/systemd/user/docker.serviceで起動する。これは systemd のユーザーサービスなので、SSH でログインしてdocker compose up -dを実行してもセッションを閉じるとコンテナが終了してしまう。
以下のコマンドでユーザーに紐づくユーザーサービスを起動し続けることができる。
| # ユーザーサービスの常駐を有効化する
$ sudo loginctl enable-linger $(whoami)
# 常駐の状態を確認する
$ loginctl show-user $(whoami) --property=Linger
Linger=yes
# ユーザーサービスの常駐を無効化する
$ sudo loginctl disable-linger $(whoami)
|