57
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Dockerコンテナの実行ユーザーと権限の関係

Posted at
  • 最近、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を作成する

    Dockerfile
    FROM ubuntu:latest
    RUN mkdir /sample
    CMD ["/bin/bash"]
    
    docker-compose.yml
    version: "3.3"
    services:
      sample:
        build:
        context: .
        dockerfile: Dockerfile
      volumes:
        - /sample:/sample
    
  • 次に、docker-compose up --builddocker-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-composeuserで実行ユーザーを指定する方法が一般的

  • この時、コンテナのユーザーとホストのユーザーの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.yml
    version: "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は変更しない

    Dockerfile
    FROM ubuntu:latest
    RUN mkdir /sample
    CMD ["/bin/bash"]
    
  • docker-compose up --builddocker-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を下記のように修正
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は以下。
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に渡るようにする
docker-compose.yml
version: "3.3"
services:
  sample:
    build:
    context: .
    dockerfile: Dockerfile
+ environment:
+   - USER_ID=1001
+   - GROUP_ID=1001
  volumes:
    - /sample:/sample
  • docker-compose up --builddocker-compose run sampleを実行
  • ① と同様に、コンテナ側でマウント先のディレクトリ/sampleにファイルを作成し、作成されたファイルのアクセス権をホストから確認する
  • 結果、実行ユーザdockeruserが所有者としてファイルが作成されている

③ イメージに作成された実行ユーザーのUID/GUIを、ホストの実行ユーザーのUID/GIDで変更する

  • コンテナ開始時、イメージで作成済の実行ユーザーのUID/GIDを変更するスクリプト(modifyuser.sh)が実行されるようにする
  • Dockerfileを下記のように修正する。
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
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)を指定
docker-compose.yml
version: "3.3"
services:
  sample:
    build:
    context: .
    dockerfile: Dockerfile
+ environment:
+   - USER_ID=1001
+   - GROUP_ID=1001
  volumes:
    - /sample:/sample
  • docker-compose up --builddocker-compose run sampleを実行
  • コンテナにアクセスし、マウント先のディレクトリ/sampleにファイルを作成。作成されたファイルのアクセス権をホスト側から確認する
  • 結果、実行ユーザdockeruserが所有者としてファイルが作成されている

コンテナの実行ユーザーをホストのユーザーにマッピングする

  • コンテナ内の実行ユーザーはrootのまま、ホストの実行ユーザーをホストの任意のユーザーに置き換える方法

  • まず、/etc/dockerdaemon.jsonを作成する

daemon.json
  {
    "userns-remap" : "default"
  }
  • 作成後、sudo systemctl restart dockerでdockerを再起動する
  • 再起動後、/etc/subuidを確認すると、以下のようなdockermapのエントリーが作成されている。
subuid
  dockremap:231072:65536
  • これにより、コンテナの実行ユーザーのUIDは、ホスト側のUID(231072~)にマッピングされる

  • 次に、以下のDockerfileとdocker-composeを作成。実行ユーザーは特に指定していないため、コンテナの実行ユーザーはrootとなる

Dockerfile
 FROM ubuntu:latest
 RUN mkdir /sample
 CMD ["/bin/bash"]
docker-compose.yml
version: "3.3"
services:
  sample:
    build:
    context: .
    dockerfile: Dockerfile
  volumes:
    - /sample:/sample
  • docker-compose up --builddocker-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を実行する

57
49
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?