注意: この記事はLLMによって英語から翻訳されたものです。正確性については保証いたしかねますので、あらかじめご了承ください。 英語の原文はこちら。
かなり長い間、rootless Podmanを使ってきました。最初に驚いたことの一つは、自分のファイルシステムにマウントされた一部のボリュームが、Linuxシステム上には存在しないような妙なUIDに所有されていたことです。
これはLinuxのuser namespace機能によるものだとわかりました。より具体的には、subuidとsubgidです。
では、これは一体何でしょうか。基本的に、rootlessコンテナを実行する際、コンテナ内で動作するものには自分がrootであると思わせたい一方で、コンテナエスケープ時の追加の安全策として、UID 0、つまりシステムのrootのUIDは使いたくありません。
また、コンテナ内で複数のユーザーを表現できるようにもしたいはずです。コンテナには独自のroot、サービスアカウント、アプリケーションユーザー、グループが存在し得ます。従属UID・GID範囲を使うことで、これらの内部的なIDを、コンテナを実行しているユーザーにすべて集約するのではなく、ホスト上の個別の非特権IDにマッピングできます。
これを実現するため、システムは/etc/subuidと/etc/subgidにマッピングを作成します。これらのファイルは次のような内容になります。
$ cat /etc/subuid
ixonae:100000:65536
user2:165536:65536
$ cat /etc/subgid
ixonae:100000:65536
user2:165536:65536最初の数字はUIDマッピングの開始位置、2つ目は作成可能なサブIDの数です。連続した単純な従属範囲の場合、マッピングはhost_uid = subuid_start + container_uidとなります。例えば、rootはホストシステム上で100000になり、Podman内でID
1000のユーザーが作成された場合、ホストシステム上では101000にマッピングされます。
これにより、ホストシステム上ではPodmanから実行されるものは依然として非特権のままですが、コンテナ内ではあたかも特権があるかのように動作できます。
では、65536はどこから来るのでしょうか。多くのシステムでは、このデフォルト値は/etc/login.defs内で定義されています。具体的にはSUB_UID_MIN、SUB_UID_MAX、SUB_UID_COUNTです。このファイルには、useradd使用時に使われるUID_MINとUID_MAXも定義されています。デフォルトの範囲は通常、通常のユーザーIDとの重複を避けるように設定されています。
rootless
Podmanのコマンドやコンテナを実行する際、newuidmapとnewgidmapのユーティリティが呼び出され、user
namespaceの初期化と/proc/<pid>/uid_mapファイルへの書き込みを行います。このファイルはその後、カーネルがパーミッション管理やユーザーIDに関わる処理を行う際に使用されます。
これらのパーミッションは次のように確認できます。
# 以下のコマンドで表示される3つの列は以下の通りです。
# - user namespace内でのID
# - namespace外でのID
# - マッピングの長さ
[user2@myhost ~]$ podman unshare cat /proc/self/uid_map
0 1001 1
1 165536 65536
$ id user2
uid=1001(user2) gid=1001(user2) groups=1001(user2)
$ cat /etc/subuid | grep user2
user2:165536:65536この場合、コンテナ内のrootは、ホストOS上でPodmanを実行しているユーザーにマッピングされていることに注意してください。それ以外のすべてのユーザーはsubuidに紐づけられます。これはPodmanのデフォルトの動作ですが、変更することも可能です。
例えば、Podman Composeを使用する場合は以下のようになります。
services:
app:
userns_mode: auto # デフォルトは "" (未設定)なお、この動作を変更するには、パーミッションの再マッピングが必要になります。Podman
Composeファイル内でマウントするパスに:Uを使用すると、それを自動的に処理できます。
関連する便利なコマンドをいくつか紹介します。
getsubids user2はそのユーザーのsubuidファイルの内容を返しますpodman system migrateは、ユーザーのsubuidファイルが変更された場合に、関連するコンテナのマッピングを更新しますpodman unshare [コマンド]を使うと、Podmanと同じuser namespace内でコマンドを実行でき、ホストユーザーが所有していないファイルへのアクセスが可能になります
追加リソース
- subuid(5) / subgid(5) (man ページ)
- user_namespaces(7) (man ページ)
- Podman: Rootless containers (公式ドキュメント)
- getsubids(1) (man ページ)
- newuidmap(1) / newgidmap(1) (man ページ)
- login.defs(5) (man ページ)
- Understanding rootless Podman’s user namespace modes (Red Hat ブログ)