AWS
EC2
AmazonLinux
Docker
rootless

Docker CEからRootless Dockerへ移行してみる on EC2


概要

現在、EC2上でDocker CEを利用している。先日↓の記事を見かけたので、Rootless Dockerへの移行(といっても、Volumeのみ)を試してみる。

RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium


Rootless Docker?


Rootlessモードは,Dockerデーモン及びコンテナを,非rootユーザで実行する技術です.Rootlessモードを用いることにより,万一Dockerに脆弱性や設定ミスがあっても,攻撃者にホストのroot権限を奪取されることを防ぐことが出来ます.


参考: RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium

:thinking:Amazon Linuxでいうところのec2-userユーザだけで、Dockerデーモンの起動からdockerコマンドの利用までできるということ。

普通にDockerを起動すると、rootユーザでコンテナを起動する必要があるから、rootを乗っ取られる可能性がある。

よくある一般ユーザをdockerグループに属させて、一般ユーザでdockerコマンドを利用できるようにさせても、Docker自体はrootユーザで起動させているから、rootを乗っ取られる可能性がある。

Rootless Dockerは、一般ユーザだけで完結できるから、rootを取られる可能性が限りなく0に近づくってことですかね。


試した環境

少しOSやDocker CEが古いが...:expressionless:


OS

[ec2-user@localhost ~]$ cat /etc/os-release

NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"


DockerCE

[ec2-user@localhost ~]$ docker version

Client:
Version: 18.06.1-ce
API version: 1.38
Go version: go1.10.3
Git commit: e68fc7a215d7133c34aa18e3b72b4a21fd0c6136
Built: Mon Mar 4 21:25:23 2019
OS/Arch: linux/amd64
Experimental: false

Server:
Engine:
Version: 18.06.1-ce
API version: 1.38 (minimum version 1.12)
Go version: go1.10.3
Git commit: e68fc7a/18.06.1-ce
Built: Mon Mar 4 21:26:49 2019
OS/Arch: linux/amd64
Experimental: false



移行前のコンテナ環境

まずは、移行を試す環境を作る。

docker volume createでボリュームを作り、centosコンテナにマウントさせて起動する。

起動したコンテナ上で、1GBほどのファイルを作っておく。

[root@localhost ~]# docker volume create test

test

[root@localhost ~]# docker run -itd -v test:/mnt centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:b5e66c4651870a1ad435cd75922fe2cb943c9e973a9673822d1414824a1d0475
Status: Downloaded newer image for centos:latest
d1256d1226bcd445616f13a0e73bbb322056c9151c7adbc7c7d84011e2afe4eb
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1256d1226bc centos "/bin/bash" 7 seconds ago Up 6 seconds romantic_bell
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 9f38484d220f 8 weeks ago 202MB
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
local test
[root@localhost ~]# docker exec -it romantic_bell bash
[root@d1256d1226bc /]# cd /mnt
[root@d1256d1226bc mnt]# dd if=/dev/zero of=zerofile bs=1024 count=1000000
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB) copied, 2.46405 s, 416 MB/s
[root@d1256d1226bc mnt]# ls -lh
total 977M
-rw-r--r-- 1 root root 977M May 12 08:49 zerofile
[root@d1256d1226bc mnt]# exit


移行前準備

Rootless Dockerをインストール(Docker CEを削除)する前に、ホスト側から前項で作成したボリュームを退避させる。

退避前にコンテナも止めておく。

退避したボリュームは、Rootless Dockerを実行するユーザ、グループに予め変更しておく。

[root@localhost ~]# docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1256d1226bc centos "/bin/bash" 7 seconds ago Up 6 seconds romantic_bell
[root@localhost ~]# docker stop romantic_bell
romantic_bell
[root@localhost ~]# cp -rp /var/lib/docker/volumes /tmp/
[root@localhost ~]# chown -R ec2-user:ec2-user /tmp/volumes/
[root@localhost ~]# docker rm romantic_bell
romantic_bell


Docker CEのアンインストール

Rootless Dockerを入れる前に、Docker CEをアンインストールする。

アンインストールをしないと、何故かRootless DockerがDocker CEの/var/run/docker.sock等を使って起動しなかった:innocent:

[root@localhost ~]# yum -y remove docker

Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package docker.x86_64 0:18.06.1ce-8.28.amzn1 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

==============================================================================================================================================
Package Arch Version Repository Size
==============================================================================================================================================
Removing:
docker x86_64 18.06.1ce-8.28.amzn1 @amzn-updates 150 M

Transaction Summary
==============================================================================================================================================
Remove 1 Package

Installed size: 150 M
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Erasing : docker-18.06.1ce-8.28.amzn1.x86_64 1/1
Verifying : docker-18.06.1ce-8.28.amzn1.x86_64 1/1

Removed:
docker.x86_64 0:18.06.1ce-8.28.amzn1

Complete!
[root@localhost ~]#


Rootless Dockerのインストール&実行

インストールといっても、コマンド1つで終わるらしい。:thinking:

[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh

# Missing system requirements. Please run following commands to
# install the requirements and run this installer again.
# Alternatively iptables checks can be disabled with SKIP_IPTABLES=1

cat <<EOF | sudo sh -x
curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
yum install -y shadow-utils46-newxidmap
EOF

パッケージが足りない。:frowning2:

[ec2-user@localhost ~]$ cat <<EOF | sudo sh -x

> curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
> yum install -y shadow-utils46-newxidmap
> EOF
~省略~
[ec2-user@localhost ~]
$ curl -fsSL https://get.docker.com/rootless | sh
Could not find records for the current user ec2-user from /etc/subuid . Please make sure valid subuid range is set there.
For example:
echo "ec2-user:100000:65536" >> /etc/subuid

/etc/subuid,/etc/subgidがない。

そもそも見た記憶がない。作る。:rolling_eyes:

[root@localhost ~]$ sudo su -

[root@localhost ~]# echo "ec2-user:1000:65536" >> /etc/subuid
[root@localhost ~]# echo "ec2-user:1000:65536" >> /etc/subgid
[root@localhost ~]# exit
[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh
# systemd not detected, dockerd daemon needs to be started manually

/home/ec2-user/bin/dockerd-rootless.sh --experimental --storage-driver vfs

# Docker binaries are installed in /home/ec2-user/bin
# WARN: dockerd is not in your current PATH or pointing to /home/ec2-user/bin/dockerd
# Make sure the following environment variables are set (or add them to ~/.bashrc):\n
export XDG_RUNTIME_DIR=/tmp/docker-500
export DOCKER_HOST=unix:///tmp/docker-500/docker.sock

言われた通りに、.bashrcに追加する。

また、binディレクトリもできていたので、合わせて追加する。

/tmp/docker-500配下にdocker.sockができるので、嫌な場合はこれらの環境変数を変えておけばよさそう。

[ec2-user@localhost ~]$ echo "export XDG_RUNTIME_DIR=/tmp/docker-500" >> ~/.bashrc

[ec2-user@localhost ~]$ echo "export DOCKER_HOST=unix:///tmp/docker-500/docker.sock" >> ~/.bashrc
[ec2-user@localhost ~]$ echo 'PATH=$PATH:$HOME/bin' >> .bashrc
[ec2-user@localhost ~]$ source .bashrc

インストールが終わったので、言われたとおりにサーバを起動する。

起動し続けておく必要があるので、screenで起動する。デタッチは、デフォルトはCtrl-a押してd

[ec2-user@localhost ~]$ screen

[ec2-user@localhost ~]$ /home/ec2-user/bin/dockerd-rootless.sh --experimental --storage-driver vfs
INFO[2019-05-12T08:08:51.179358654Z] Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address
INFO[2019-05-12T08:08:51.330646070Z] Loading containers: done.
INFO[2019-05-12T08:08:51.344736419Z] Docker daemon commit=3998dff graphdriver(s)=vfs version=master-dockerproject-2019-05-11
INFO[2019-05-12T08:08:51.344855472Z] Daemon has completed initialization
INFO[2019-05-12T08:08:51.362135829Z] API listen on /tmp/docker-500/docker.sock
[detached]
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker version
Client:
Version: master-dockerproject-2019-05-11
API version: 1.40
Go version: go1.12.5
Git commit: 53fc2572
Built: Sat May 11 23:39:34 2019
OS/Arch: linux/amd64
Experimental: false

Server:
Engine:
Version: master-dockerproject-2019-05-11
API version: 1.40 (minimum version 1.12)
Go version: go1.12.5
Git commit: 3998dff
Built: Sat May 11 23:46:26 2019
OS/Arch: linux/amd64
Experimental: true
containerd:
Version: v1.2.6
GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
runc:
Version: 1.0.0-rc8
GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f
docker-init:
Version: 0.18.0
GitCommit: fec3683


適当なコンテナを起動してみる

dockerコマンドはパスを通したので今までどおり使える。

[ec2-user@localhost ~]$ docker run -d -p 8080:80 nginx

Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
743f2d6c1f65: Pull complete
6bfc4ec4420a: Pull complete
688a776db95f: Pull complete
Digest: sha256:23b4dcdf0d34d4a129755fc6f52e1c6e23bb34ea011b315d87e193033bcd1b68
Status: Downloaded newer image for nginx:latest
a26c026eddf0f0d92db01e6cd6984f83904ffc5b4d69dd245a3a88081cdc6db5
[ec2-user@localhost ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a26c026eddf0 nginx "nginx -g 'daemon of…" 4 seconds ago Up 3 seconds 0.0.0.0:8080->80/tcp xenodochial_khayyam
[ec2-user@localhost ~]$ curl http://localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[ec2-user@localhost ~]$

Rootless Docker動いた:relaxed:


ボリュームの移行

そもそもvolumesディレクトリはどこにあるのか。:thinking:

[ec2-user@ip-172-31-47-41 ~]$ ll /tmp/docker-500/

total 12
drwx-----T 7 ec2-user ec2-user 4096 May 12 08:58 docker
-rw-r--r-T 1 ec2-user ec2-user 5 May 12 08:58 docker.pid
srw-rw---T 1 ec2-user 1496 0 May 12 08:58 docker.sock
drwx-----T 2 ec2-user ec2-user 4096 May 12 08:08 runc
[ec2-user@ip-172-31-47-41 ~]$ find . -name 'docker'
./.vim/plugged/ultisnips/docker
./.local/share/docker
~省略~
[ec2-user@ip-172-31-47-41 ~]$ ll .local/share/docker/
total 56
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 builder
drwx------ 4 ec2-user ec2-user 4096 May 12 08:08 buildkit
drwx------ 3 ec2-user ec2-user 4096 May 12 08:08 containerd
drwx------ 4 ec2-user ec2-user 4096 May 12 09:11 containers
-rw------- 1 ec2-user ec2-user 36 May 12 08:08 engine_uuid
drwx------ 3 ec2-user ec2-user 4096 May 12 08:08 image
drwxr-x--- 3 ec2-user ec2-user 4096 May 12 08:08 network
drwx------ 4 ec2-user ec2-user 4096 May 12 08:08 plugins
drwx------ 2 ec2-user ec2-user 4096 May 12 08:58 runtimes
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 swarm
drwx------ 2 ec2-user ec2-user 4096 May 12 09:11 tmp
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 trust
drwx------ 3 ec2-user ec2-user 4096 May 12 08:15 vfs
drwx------ 3 ec2-user ec2-user 4096 May 12 09:08 volumes
[ec2-user@ip-172-31-47-41 ~]$

ホームディレクトリの.local/share/docker配下にあった

[ec2-user@ip-172-31-47-41 ~]$ ll .local/share/docker/volumes

total 24
-rw------- 1 ec2-user ec2-user 32768 May 12 09:08 metadata.db

メタデータがあるので、ディレクトリだけ移動

でも移動だけだと認識されないので、同名でdocker volume create

[ec2-user@localhost ~]$ mv /tmp/volumes/test ~/.local/share/docker/volume/

[ec2-user@localhost ~]$ docker volume ls
DRIVER VOLUME NAME
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker volume create test
test

[ec2-user@localhost ~]$ docker volume ls
DRIVER VOLUME NAME
local test

あとは、Docker CEのときと同じようにコンテナを作成する。

[ec2-user@localhost ~]$ docker run -itd  -v test:/mnt centos

Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:b5e66c4651870a1ad435cd75922fe2cb943c9e973a9673822d1414824a1d0475
Status: Downloaded newer image for centos:latest
cfbadb0e2e67047bf25e23a2ce73835dfb9557e8341e4aead1cf658d69eacf9a
[ec2-user@localhost ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cfbadb0e2e67 centos "/bin/bash" About a minute ago Up About a minute jolly_fermi
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker inspect jolly_fermi | grep volume
"Type": "volume",
"Source": "/home/ec2-user/.local/share/docker/volumes/test/_data",
[ec2-user@localhost ~]$ docker exec jolly_fermi /bin/ls /mnt -l
total 1000004
-rw-r--r-- 1 root root 1024000000 May 12 08:49 zerofile
[ec2-user@ip-172-31-47-41 ~]$ docker exec jolly_fermi bash -c "echo 'hello' >> /mnt/hello.txt"
[ec2-user@ip-172-31-47-41 ~]$ cat .local/share/docker/volumes/test/_data/hello.txt
hello
[ec2-user@ip-172-31-47-41 ~]$

どうやらボリュームの移行はちゃんとできたようだ:clap:

[参考]

moby/rootless.md at master · moby/moby

RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium


最後に

気が向いたらdocker-composeで作成したものも試しておきたい。