- 最近、Dockerのコンテナの実行ユーザーと権限の関係について調べ直したので、内容をまとめました。
- 検証対象のDockerのバージョンは
20.10.12
です。 - 何かお気づきの点があればコメントいただけるとありがたいです
前提知識:Linuxのアクセス権の確認方法
- この記事では
ls -l
を用いてファイルやディレクトリのアクセス権を確認する。ls -l
を実行結果は以下の通り。-rw-rw-r-- 1 user1 user1 210 4月 10 07:53 docker-compose.yml
- この見方がわからないと、この後の記事を理解するのが難しいため、ここで説明しておく
アクセス権の見方
-
表示結果は以下のように分割して見る
オブジェクトのアクセス権 ハードリンク数 所有者 所有グループ ファイルサイズ 更新日 ファイル名 -rw-rw-r-- 1 user1 user1 210 4月 10 07:53 docker-compose.yml -
最初の10文字がアクセス権。上記の例では
-rw-rw-r--
。以下のように分割して見るオブジェクトの種類(1文字目) 所有者の権限(2~4文字目) 所有グループの権限(5~7文字目) その他グループの権限(8~10文字目) - rw- rw- r--
オブジェクトの種類(1文字目)
-
対象オブジェクトの種類を表す
値 意味 - ファイル d ディレクトリ l シンボリックリンク
所有者の権限(2~4文字目)、所有グループの権限(5~7文字目)、その他グループの権限(8~10文字目)
-
各主体(所有者、所有グループ、その他)の権限情報を表す
値 意味 サンプル 2~4文字目 所有者の権限 rw- 5~7文字目 所有グループの権限 rw- 8~10文字目 その他の権限 r--
各主体の権限の見方
-
各主体(所有者、グループ、その他)の権限の見方は以下の通り
モード 説明 - 主体に権限がないということ r 主体に読み取り権があるということ w 主体に書き込み権があるということ x 主体に実行権限があるということ
以上がアクセス権の基本的な見方。以下、記事の本題に移る。
コンテナの実行ユーザーと権限について
- 以下の流れでコンテナの実行ユーザーと権限について説明する
- 実行ユーザーを指定しない場合
- ホストのユーザーを、コンテナの実行ユーザーとして指定する場合
- コンテナの実行ユーザーをホストのユーザーにマッピングする場合
- RootlessモードでDockerを実行する場合
コンテナの実行ユーザーを指定しない場合
- コンテナの実行ユーザーを指定しない場合、実行ユーザーは
root
となる - これはセキュリティ的に危険。コンテナが乗っ取られた場合、ホストに危険な操作が実行される恐れがある
- コンテナから作成されたファイルの所有者も
root
となるため、ホスト側からの取り扱いが難しくなる
動作確認
-
ホストの
/sample
ディレクトリをマウントし、/bin/bash
を実行するDockerfileとdocker-composeを作成するDockerfileFROM ubuntu:latest RUN mkdir /sample CMD ["/bin/bash"]
docker-compose.ymlversion: "3.3" services: sample: build: context: . dockerfile: Dockerfile volumes: - /sample:/sample
-
次に、
docker-compose up --build
→docker-compose run sample
を実行。 -
アクセス後、コンテナ側で
id
を実行し、ログインユーザーを確認するuid=0(root) gid=0(root) groups=0(root)
-
結果は上記の通り。実行ユーザーが
root
であることがわかる -
次に、コンテナからファイル
sample03
を作成するecho "Hello" > /sample/sample03.txt
-
その後、
sample03.txt
のアクセス権をホストから確認する。ホストの/sample
ディレクトリに移動し、ls -l
を実行-rw-r--r-- 1 root root 6 5月 8 17:35 sample03.txt
-
結果は上記の通りで
sample03.txt
の所有者がroot
になっている
コンテナの実行ユーザーを指定する場合
-
docker
コマンドの--user
オプションや、docker-compose
のuser
で実行ユーザーを指定する方法が一般的 -
この時、コンテナのユーザーとホストのユーザーのuid/gidを一致させる方が望ましいが、工夫が必要。具体的には以下のいずれかの作業を行う
① ホストの/etc/passwd
と/etc/group
をマウントし、コンテナ実行時にホストの実行ユーザーを指定する
② ホストの実行ユーザーと同じUID/GUDでコンテナにユーザーを作成し、このユーザーでコンテナを実行する
③ (イメージに実行ユーザーが作成されている場合)、コンテナの実行ユーザーのUID/GUIを、ホストの実行ユーザーのUID/GIDで変更する -
以下、①~③の方法を確認ます。
事前準備:ホスト側に実行ユーザーを作成する
- ホストに実行ユーザーを作成する。今回は
dockeruser
という名前のユーザーを作成する
useradd -m dockeruser
- 作成したユーザーのUID/GUIDを確認する。
id dockeruser
を実行
uid=1001(dockeruser) gid=1001(dockeruser) groups=1001(dockeruser)
- また、ホストのマウント先ディレクトリ
/sample
に対して、dockeruser
がファイルを作成できるように権限を変更しておく
① /etc/passwd
と/etc/group
をマウントし、コンテナ実行時にホストの実行ユーザーを指定する
-
先ほどのdocker-composeを下記のように修正する。
/etc/passwd
と/etc/group
をマウントし、実行ユーザーdockeruser
を指定する -
/etc/passwd
と/etc/group
は読み取り専用でマウントしておくdocker-compose.ymlversion: "3.3" services: sample: build: context: . dockerfile: Dockerfile + user:1001:1001 volumes: - /sample:/sample + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro
-
Dockerfileは変更しない
DockerfileFROM ubuntu:latest RUN mkdir /sample CMD ["/bin/bash"]
-
docker-compose up --build
→docker-compose run sample
を実行。 -
コンテナにアクセスし、
id
コマンドでログインユーザーを確認するuid=1001(dockeruser) gid=1001(dockeruser) groups=1001(dockeruser)
-
結果は上記の通りで、指定した実行ユーザー(uid=1001)となっている
-
次に、コンテナからファイルを作成する
echo "Hello" > /sample/sample03-1.txt
-
作成されたファイル
sample03-1.txt
のアクセス権をホストから確認する。ホストの/sample
ディレクトリに移動し、ls -l
を実行する-rw-r--r-- 1 dockeruser dockeruser 6 5月 8 18:11 sample03-1.txt
-
結果は上記の通りで、作成したファイル
sample03-1.txt
の所有者が指定した実行ユーザーdockeruser
となっている
② ホストの実行ユーザーと同じUID/GUDでコンテナにユーザーを作成し、このユーザーでコンテナを実行する
- コンテナ実行時に、実行ユーザーを作成するスクリプト(createuser.sh)が実行され、かつ、作成された実行ユーザーでコンテナが開始されるようにする
- 先ほどのDockerfileを下記のように修正
FROM ubuntu:latest
RUN mkdir /sample
+ RUN apt-get update && apt-get -y install gosu
+ COPY createuser.sh /usr/bin/createuser.sh
+ RUN chmod +x /usr/bin/createuser.sh
+ ENTRYPOINT ["/usr/bin/createuser.sh"]
CMD ["/bin/bash"]
- 実行ユーザーを作成するcreateuser.shは以下。
#!/bin/bash
USERID=${USER_ID}
GROUPID=${GROUP_ID}
echo "Create User = $USERID. Group = $GROUPID"
groupadd -g $GROUPID dockeruser
useradd -m -s /bin/bash -u $USERID -g $GROUPID dockeruser
exec /usr/sbin/gosu dockeruser "$@"
- docker-composeは以下のように修正。コンテナ実行時の環境変数に実行ユーザー
dockeruser
のUID (1001)とGIUD (1001)を指定し、createuser.sh
に渡るようにする
version: "3.3"
services:
sample:
build:
context: .
dockerfile: Dockerfile
+ environment:
+ - USER_ID=1001
+ - GROUP_ID=1001
volumes:
- /sample:/sample
-
docker-compose up --build
→docker-compose run sample
を実行 - ① と同様に、コンテナ側でマウント先のディレクトリ
/sample
にファイルを作成し、作成されたファイルのアクセス権をホストから確認する - 結果、実行ユーザ
dockeruser
が所有者としてファイルが作成されている
③ イメージに作成された実行ユーザーのUID/GUIを、ホストの実行ユーザーのUID/GIDで変更する
- コンテナ開始時、イメージで作成済の実行ユーザーのUID/GIDを変更するスクリプト(modifyuser.sh)が実行されるようにする
- Dockerfileを下記のように修正する。
FROM ubuntu:latest
RUN mkdir /sample
+ RUN apt-get update && apt-get -y install gosu
+ RUN groupadd -g 2000 dockeruser && \
+ useradd -m -s /bin/bash -u 2000 -g 2000 dockeruser
+ COPY modifyuser.sh /usr/bin/modifyuser.sh
+ RUN chmod +x /usr/bin/modifyuser.sh
+ ENTRYPOINT ["/usr/bin/modifyuser.sh"]
CMD ["/bin/bash"]
- 実行ユーザーのUIDを変更するmodifyuser.sh
#!/bin/bash
USERID=${USER_ID}
GROUPID=${GROUP_ID}
echo "Modify User = $USERID Group = $GROUP_ID"
groupmod -g $GROUP_ID dockeruser
usermod -u $USERID -m -d /home/dockeruser dockeruser
exec /usr/sbin/gosu dockeruser "$@"
- docker-compose。コンテナ実行時の環境変数にホストのユーザー
dockeruser
のUID (1001)とGIUD (1001)を指定
version: "3.3"
services:
sample:
build:
context: .
dockerfile: Dockerfile
+ environment:
+ - USER_ID=1001
+ - GROUP_ID=1001
volumes:
- /sample:/sample
-
docker-compose up --build
→docker-compose run sample
を実行 - コンテナにアクセスし、マウント先のディレクトリ
/sample
にファイルを作成。作成されたファイルのアクセス権をホスト側から確認する - 結果、実行ユーザ
dockeruser
が所有者としてファイルが作成されている
コンテナの実行ユーザーをホストのユーザーにマッピングする
-
コンテナ内の実行ユーザーは
root
のまま、ホストの実行ユーザーをホストの任意のユーザーに置き換える方法 -
まず、
/etc/docker
にdaemon.json
を作成する
{
"userns-remap" : "default"
}
- 作成後、
sudo systemctl restart docker
でdockerを再起動する - 再起動後、
/etc/subuid
を確認すると、以下のようなdockermap
のエントリーが作成されている。
dockremap:231072:65536
-
これにより、コンテナの実行ユーザーのUIDは、ホスト側のUID(231072~)にマッピングされる
-
次に、以下のDockerfileとdocker-composeを作成。実行ユーザーは特に指定していないため、コンテナの実行ユーザーは
root
となる
FROM ubuntu:latest
RUN mkdir /sample
CMD ["/bin/bash"]
version: "3.3"
services:
sample:
build:
context: .
dockerfile: Dockerfile
volumes:
- /sample:/sample
-
docker-compose up --build
→docker-compose run sample
を実行 -
コンテナにアクセスし、
id
を実行して実行ユーザーのUIDを確認する
uid=0(root) gid=0(root) groups=0(root)
-
結果は上記の通りで、コンテナ側の実行ユーザーは
root
であることがわかる -
次に、コンテナ側からマウント先のディレクトリ
/sample
に移動し、ファイルsample04.txt
を作成する
echo sample04 > sample04.txt
- 作成された
sample04.txt
のアクセス権をホスト側からls -l
で確認する
-rw-r--r-- 1 231072 231072 8 5月 14 22:03 sample4.txt
-
sample04.txt
の所有者のUIDは231072
。これは/etc/subuid
に新しく追加されたdockremap
の最初のサブUIDとなっている
RootlessモードでDockerを実行する
- userns-remapを利用する場合、コンテナ側の実行ユーザーは
root
となってしまう - これが許容できない場合、rootlessモードでdockerを実行する
- 参考:Dockerデーモンをル-ト以外のユーザーで実行する (Rootlessモード)