ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

ID Mapping/User Namespace再入門 その(2)

シリーズ2回めです。今回もベースは自分のためのまとめであり、調査不足な点はぜひ突っ込んでください...。

前回:

udzura.hatenablog.jp

今回から、User Namespace の各コンテナでの対応状況を見ていく。

コンテナの非特権に対する対応

前提として、前回のUser Namespaceが解決する課題を再掲する。

主に以下の二つの課題が解決できる。

  • もし特権を付与したコンテナをunjailされた場合等に、ホストのファイルシステムを操作されるなどの被害を最低限にしたい
  • 一般ユーザで、なるべく安全にコンテナを作成したい

前者と後者は、関連してはいるが実現方法が少し異なることは留意すべき。rootless Dockerや一般ユーザでのlxc-startは後者に、LXDによるUser Namespaceの分離は前者に属すると考えられそう。その辺りを踏まえて、各種コンテナランタイムでの対応状況をまとめておく。

Docker (rootless mode)

現在のDocker(Moby)には、experimentalという扱いだがrootless modeがある。公式のブログに詳しい:

engineering.docker.com

インストールするとそのユーザーに紐づくsystemdサービスとしてdockerd-rootless.shが立ち上がる。関連する環境変数を設定して、スッと使える。スッとrootlessな環境に入った様子です。

$ export PATH=/home/vagrant/bin:$PATH
$ export DOCKER_HOST=unix:///run/user/1000/docker.sock
$ docker run -ti debian:stretch-slim bash
root@daa6c479988c:/# ls -l
total 64
drwxr-xr-x   2 root   root    4096 Feb  4 00:00 bin
drwxr-xr-x   2 root   root    4096 Jan 22 13:47 boot
drwxr-xr-x   5 root   root     360 Feb 27 10:31 dev
drwxr-xr-x   1 root   root    4096 Feb 27 10:31 etc
drwxr-xr-x   2 root   root    4096 Jan 22 13:47 home
drwxr-xr-x   8 root   root    4096 Feb  4 00:00 lib
drwxr-xr-x   2 root   root    4096 Feb  4 00:00 lib64
drwxr-xr-x   2 root   root    4096 Feb  4 00:00 media
drwxr-xr-x   2 root   root    4096 Feb  4 00:00 mnt
drwxr-xr-x   2 root   root    4096 Feb  4 00:00 opt
dr-xr-xr-x 143 nobody nogroup    0 Feb 27 10:31 proc
drwx------   2 root   root    4096 Feb  4 00:00 root
drwxr-xr-x   3 root   root    4096 Feb  4 00:00 run
drwxr-xr-x   2 root   root    4096 Feb  4 00:00 sbin
drwxr-xr-x   2 root   root    4096 Feb  4 00:00 srv
dr-xr-xr-x  13 nobody nogroup    0 Feb 27 07:44 sys
drwxrwxrwt   2 root   root    4096 Feb  4 00:00 tmp
drwxr-xr-x  10 root   root    4096 Feb  4 00:00 usr
drwxr-xr-x  11 root   root    4096 Feb  4 00:00 var

細かいところ

  • 中央のデーモン含めて全てユーザ権限でセットアップできる
  • /proc /sys などはnobodyの所属になる(その下の /proc/1/* などは当然rootとして見える)
  • cgroupはruncのcgroup v2対応待ちだそう 。今だと --cpu-period=100000 --cpu-quota=30000 のようなオプションでコンテナを立ち上げても無視される。現在の /proc/$PID/cgroup の様子。
vagrant@ubuntu-bionic:~$ cat /proc/3916/cgroup
12:devices:/user.slice
11:memory:/user.slice
10:cpu,cpuacct:/user.slice
9:freezer:/
8:pids:/user.slice/user-1000.slice/user@1000.service
7:rdma:/
6:net_cls,net_prio:/
5:perf_event:/
4:hugetlb:/
3:blkio:/user.slice
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/user@1000.service/docker.service/6ad64d532692c26bce327e278b7dc8882b606072dba9cb2d184165c60b250c77
0::/user.slice/user-1000.slice/user@1000.service/docker.service

LXC の非特権コンテナ

Ubuntu Bionic(lxc-3.0.3)においては結構前準備が多いのでそれも合わせて。

/home/vagrant/.config/lxc/default.conf を以下のように編集する。idmapの値は、ちゃんと /etc/sub{u,g}id とあっているか確認すること。

lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:11:22:33
lxc.idmap = u 0 165536 65536
lxc.idmap = g 0 165536 65536
## 確認の例
$ grep vagrant /etc/sub{u,g}id
/etc/subuid:vagrant:165536:65536
/etc/subgid:vagrant:165536:65536

/etc/lxc/lxc-usernet も編集する。

# USERNAME TYPE BRIDGE COUNT
vagrant veth lxcbr0 10

/etc/pam.d/common-session{,-noninteractive}pam_cgfs.so の行が含まれるか確認する。入っていない、もしくは有効でないとLXC 3.0.3の場合SEGVしてしまう。場合により再ログインする。

そうしたらようやく lxc-create -t download -n ippanjin-1 -- -d ubuntu -r bionic -a amd64 な感じでイメージを作成できる。

Setting up the GPG keyring
Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs

---
You just created an Ubuntu bionic amd64 (20190227_07:42) container.

To enable SSH, run: apt install openssh-server
No default root or user password are set by LXC.

コンテナに入った様子。

$ lxc-start -n ippanjin-1 -F -- bash                                                                                                                  
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
root@ippanjin-1:/# ls -l /
total 64
drwxr-xr-x   2 root   root    4096 Feb 27 08:11 bin
drwxr-xr-x   2 root   root    4096 Apr 10  2014 boot
drwxr-xr-x   4 root   root     400 Feb 27 12:05 dev
drwxr-xr-x  66 root   root    4096 Feb 27 11:54 etc
drwxr-xr-x   3 root   root    4096 Feb 27 08:12 home
drwxr-xr-x  12 root   root    4096 Feb 27 08:11 lib
drwxr-xr-x   2 root   root    4096 Feb 27 08:10 lib64
drwxr-xr-x   2 root   root    4096 Feb 27 08:07 media
drwxr-xr-x   2 root   root    4096 Apr 10  2014 mnt
drwxr-xr-x   2 root   root    4096 Feb 27 08:07 opt
dr-xr-xr-x 144 nobody nogroup    0 Feb 27 12:05 proc
drwx------   2 root   root    4096 Feb 27 11:55 root
drwxr-xr-x   3 root   root    4096 Feb 27 11:53 run
drwxr-xr-x   2 root   root    4096 Feb 27 08:11 sbin
drwxr-xr-x   2 root   root    4096 Feb 27 08:07 srv
dr-xr-xr-x  13 nobody nogroup    0 Feb 27 07:44 sys
drwxrwxrwt   2 root   root    4096 Feb 27 08:08 tmp
drwxr-xr-x  10 root   root    4096 Feb 27 08:07 usr
drwxr-xr-x  12 root   root    4096 Feb 27 08:10 var

細かいところ

vagrant@ubuntu-bionic:~$ cat /proc/13621/cgroup 
12:devices:/user.slice
11:memory:/user/vagrant/0/lxc/ippanjin-1
10:cpu,cpuacct:/user.slice
9:freezer:/user/vagrant/0/lxc/ippanjin-1
8:pids:/user.slice/user-1000.slice/session-43.scope
7:rdma:/
6:net_cls,net_prio:/
5:perf_event:/
4:hugetlb:/
3:blkio:/user.slice
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-43.scope/lxc/ippanjin-1
0::/user.slice/user-1000.slice/session-43.scope

時間切れ。次回予告は以下。

LXD を利用したコンテナ別のUser Namespaceの割り当て(をすると認識しているんですが、合ってるだろうか?)

Haconiwa の対応状況