- 最近、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モード)