【Docker】 WSL 2 を利用したコンテナー内開発で権限をどう設定するべきか

WSL 2 の Linux ファイルシステムを bind mount してコンテナー内開発を行う場合、
権限を適切に設定しないと、
コンテナー内で作成したファイルが、ホストの WSL 2 や Windows 側で
操作できなくなってしまうなどの問題が発生します。

この記事では、
WSL 2 を利用したコンテナー内開発において
権限をどう設定するべきかについて解説します。

WSL 2 を利用したコンテナー内開発での権限の問題

初期状態では、
WSL 2 のファイルシステムを開発用コンテナーに bind mount すると、
多くの場合、コンテナー内で作成したファイルが
ホストの WSL 2 や Windows 側で操作できなくなってしまいます。

これは、権限が次のようになりやすいためです:

対象ユーザー権限
コンテナー内で作成したファイルの所有者root
WSL 2 や Windows 側からの操作UID 1000

コンテナー側のユーザー権限について知っておくべきこと

  • コンテナー内は root 権限を前提に設計されていることが多いです
    • そのため、Visual Studio Code のコンテナー内開発で作ったファイルは所有者が root になります
  • 公開されているイメージには、
    コンテナー内にユーザーや権限に関する意図的な設計がある場合もあります
      • Nginx 公式イメージにおける www-data ユーザー
      • MySQL 公式イメージにおける mysql ユーザー
  • コンテナーを実行するときに実行ユーザーを指定する方法もあります
    • しかし、あまり実用的ではありません
      • 今度はコンテナーが設計通りに動作しない問題を解決しなくてはならなくなります
        • コンテナー内が既定のユーザー権限を前提にした設計になっていることが多いため

ホスト側のユーザー権限について知っておくべきこと

  • ホスト側の WSL 2 Linux ディストリビューションは
    初期設定では、UID 1000 のユーザーとして操作することになります
    • UID 1000 は Linux ディストリビューションの初期設定時に作成されたユーザーです
  • Windows のエクスプローラーからの操作も、この UID 1000 のユーザーの扱いとなります
    • Windows 側からコピーや移動して持ってきたファイルも
      UID 1000 のユーザーが所有者となります

Docker 公式のベストプラクティス

Docker の公式ドキュメントでは、
権限を気にする必要があったり、ファイル・フォルダーを追加更新削除する場合、
bind mount ではなく volume を使うことを推奨しています。

ただし、同時に各所で
「bind mount は開発環境に適しています」
とも記載されています。

One case where it is appropriate to use bind mounts is during development

Where and how to persist application data | Docker development best practices | Docker Documentation

参考:

volume を使う場合、インポートやエクスポートの処理を自作することになり、
開発の開始と終了時にこれらの処理を実行する必要があります。

参考: Use volumes | Docker Documentation

Visual Studio Code のベストプラクティス

Visual Studio Code の公式ドキュメントでは、
ユーザーと権限に関するいくつかの対策が記載されています。

中でも、新たに root 以外の実行ユーザーを作ることは
開発環境だけでなく本番環境にとっても
セキュリティー的に望ましいと解説されています。

参考: Adding a non-root user to your dev container | dvanced Container Configuration

Running your application as a non-root user is recommended
even in production (since it is more secure),
so this is a good idea even if you’re reusing an existing Dockerfile.

Creating a non-root user | Advanced Container Configuration

ただし、次のような課題もあります:

  • 開発者同士でホスト側の UID を合わせる必要があります
  • コンテナー内にユーザー ID を作成してから利用開始する必要があるため
    公開されている Docker イメージを、そのまますぐ利用することができなくなります
  • 公開されている Docker イメージのユーザー権限の設計を変えることになります

WSL 2 を隔離してデフォルトユーザーを root にする

WSL 2 のデフォルトユーザーを root にすると、権限の煩雑さから解放されます。
セキュリティー的にはあまり望ましくありませんが、
次のことを考慮すると、Docker を利用する上においては、リスクは変わってないと言えます。

  • WSL 2 にする前の Docker Desktop も権限的にほぼ同様の状態であること
  • いずれにしてもコンテナーが root で動作していること

ただ、WSL 2 上で操作を誤ると、
権限が強いために重要なファイルを削除してしまう、といったことも考えられます。

参考: Windows 10の「WSL」の自動マウントやfstabによるマウント処理をwsl.confファイルで制御する:Tech TIPS – @IT

これを防ぐため、WSL 2 側からの Windows へのアクセスは
読み取り専用にしておくことをお奨めします。

どうやって WSL 2 のデフォルトユーザーを root にするの?

既存の Linux ディストリビューションの設定を変更する場合

1. root のパスワードを設定します

対象の Linux ディストリビューションのターミナルを起動し、
次のように入力します:

# ユーザーを root に切り替え
y-shinoda $ sudo su -
# パスワードを設定
root $ passwd

参考: Set up WSL (Ubuntu) on Windows 10 Pro | 東京大学 佐々木淳 研究室 沿岸環境学 海岸工学 環境水工学 水環境学

2. デフォルトユーザーを root に変更します

Windows PowerShell を管理者権限で起動し、
次のコマンドを実行します:

<Linux ディストリビューション名> config --default-user root

例: Ubuntu の場合:

ubuntu config --default-user root

参考: ubuntu 14.04 – How to sign into “root” account by default on Windows Subsystem for Linux Bash terminal – Super User

新規 Linux ディストリビューションを設定する場合

少なくとも、Ubuntu は Windows へのインストール直後に
次の手順でデフォルトユーザーを root にできます。

1.
Microsoft Store から Windows に Ubuntu をインストールし終わったら、
Ubuntu を起動し、ターミナル上でインストール処理の完了を待ちます。

ターミナル上でインストール処理の完了を待ちます
ターミナル上でインストール処理の完了を待ちます

2.
インストール処理が完了し、”Enter new UNIX username:” と表示されたら
一旦、ターミナルを閉じます。

"Enter new UNIX username:" と表示されたら 一旦、ターミナルを閉じます
“Enter new UNIX username:” と表示されたら 一旦、ターミナルを閉じます

3.
再度 Ubuntu を起動すると、デフォルトユーザーが root になっています。

再度 Ubuntu を起動すると、デフォルトユーザーが root になっています
再度 Ubuntu を起動すると、デフォルトユーザーが root になっています

どうやって WSL 2 側から Windows へのアクセスを読み取り専用にするの?

WSL 2 の Linux ファイルシステム上の /etc/wsl.conf に
次の内容のファイルを作成します:

[automount]
options="metadata,umask=22,fmask=11,ro"

そして Windows を再起動します。

すると、Linux ファイルシステムで開いたシェルからは、
権限の表示は書き込み可能の表示でも、
実際に書き込みを行うと読み込み専用のファイルシステムであるエラーが発生します:

$ ls -la /mnt/c/Users/public/workspace
total 0
drwxr-xr-x 1 root root 4096 Oct 14 11:44 .
drwxr-xr-x 1 root root 4096 Oct 14 11:44 ..
-rwxr--r-- 1 root root    0 Oct 14 11:44 test1.txt
$ touch /mnt/c/Users/public/workspace/test2.txt
touch: cannot touch '/mnt/c/Users/public/workspace/test2.txt': Read-only file system
$ rm -rf /mnt/c/Users/public/workspace
rm: cannot remove '/mnt/c/Users/public/workspace/test1.txt': Read-only file system

参考:

ちなみに、読み取り専用にするのではなく、マウント自体をやめてみたところ、
Visual Studio Code の WSL リモート開発とコンテナー内開発が動かなくなりました。

Visual Studio Code の WSL リモート開発とコンテナー内開発のエラー
Visual Studio Code の WSL リモート開発とコンテナー内開発のエラー

Visual Studio Code
Docker returned an error. Make sure the Docker daemon is running.
[OK]

タイトルとURLをコピーしました