Docker コンテナの uid と gid の詳細な理解

Docker コンテナの uid と gid の詳細な理解

デフォルトでは、コンテナ内のプロセスは root ユーザー権限で実行され、この root ユーザーはホスト マシンの root ユーザーと同じユーザーです。恐ろしいことに聞こえますが、これはコンテナ内のプロセスに適切な機会が与えられると、ホスト マシン上のすべてを制御できることを意味するからです。この記事では、ユーザー名、グループ名、ユーザー ID (uid)、グループ ID (gid) がコンテナー内のプロセスとホスト システム間でどのようにマッピングされるかを理解します。これはシステムのセキュリティにとって非常に重要です。注: この記事のデモ環境は Ubuntu 16.04 です (下の画像はインターネットから引用したものです)。

まずuidとgidを理解しましょう

Linux カーネルは uid と gid を管理し、カーネルレベルのシステム コールを使用して、要求に権限を付与するかどうかを決定します。たとえば、プロセスがファイルに書き込もうとすると、カーネルは作成プロセスの uid と gid をチェックして、ファイルを変更するのに十分な権限があるかどうかを判断します。カーネルはユーザー名とグループ名ではなく、uid と gid を使用することに注意してください。

簡潔にするために、この記事の残りの部分では uid のみを例として使用します。システムは、基本的に gid を uid と同じように扱います。

多くの学生は、Docker コンテナを単に軽量の仮想マシンとして理解しています。これにより、コンテナ技術の理解の難しさが軽減されますが、多くの誤解を招く可能性もあります。実際、仮想マシン技術とは異なり、同じホスト上で実行されるすべてのコンテナは同じカーネル (ホストのカーネル) を共有します。コンテナ化によってもたらされる大きな価値は、これらすべての独立したコンテナ (実際にはプロセス) がカーネルを共有できることです。つまり、Docker ホスト上で数百または数千のコンテナが実行されている場合でも、カーネルによって制御される uid と gid のセットは 1 つだけになります。したがって、同じ uid は、ホストとコンテナ内の同じユーザーを表します (異なる場所に異なるユーザー名が表示される場合でも)。

ユーザー名を表示するための通常の Linux ツール (id などのコマンドなど) はカーネルの一部ではないため、同じ uid が異なるコンテナーで異なるユーザー名として表示される場合があることに注意してください。ただし、異なるコンテナーであっても、同じ uid に対して異なる権限を持つことはできません。

Linux ユーザー名前空間テクノロジーをすでに知っている場合は、「Linux 名前空間: ユーザー」を参照してください。これまでのところ、Docker はデフォルトでユーザー名前空間を有効にしていないことに注意してください。これは、この記事で説明されているケースでもあります。次の記事では、ユーザー名前空間を有効にするために Docker を設定する方法を紹介します。

コンテナ内のデフォルト ユーザーは root です。

関連する設定が行われていない場合、コンテナ内のプロセスはデフォルトで root ユーザー権限で開始されます。次のデモでは、ubuntu イメージを使用して sleep プログラムを実行します。

$ docker run -d --name sleepme ubuntu スリープ無限

上記のコマンドでは sudo が使用されていないことに注意してください。ホスト マシン上の著者のログイン ユーザーは nick で、uid は 1000 です。

ホスト内のスリープ プロセスの情報を表示します。

$ ps aux | grep スリープ

スリープ プロセスの有効なユーザー名は root です。つまり、スリープ プロセスには root 権限があります。

次にコンテナに入り、状況が以前と同じであることを確認します。スリープ プロセスにもルート権限があります。

では、コンテナ内の root ユーザーはホスト上の root ユーザーと同じですか?

答えは「はい、同じ UID に対応します」です。理由は前に説明しました。システム全体が同じカーネルを共有し、カーネルは uid と gid のセットを 1 つだけ管理します。

実際、上記の結論はデータ量を通じて簡単に検証できます。ホスト マシン上に、root ユーザーだけが読み書きできるファイルを作成します。

次に、それをコンテナにマウントします。

$ docker run --rm -it -w=/testv -v $(pwd)/testv:/testv ubuntu

コンテナ内でファイルを読み書きできます。

コンテナ内のプロセスのユーザー ID は、Dockerfile の USER コマンドまたは docker run コマンドの --user パラメータを使用して指定できます。これら 2 つの状況を別々に検討してみましょう。

Dockerfile でユーザー ID を指定する

Dockerfile にユーザー appuser を追加し、USER コマンドを使用して、プログラムをこのユーザーとして実行するように指定できます。Dockerfile の内容は次のとおりです。

Ubuntuから
useradd -r -u 1000 -g appuserを実行します
ユーザー appuser
ENTRYPOINT ["sleep", "infinity"]

test という名前のイメージにコンパイルします。

docker build -t テストを実行します。 

テストイメージを使用してコンテナを起動します。

$ docker run -d --name sleepme テスト

ホスト内のスリープ プロセスの情報を表示します。

今回表示される有効なユーザーは nick です。これは、ホスト マシンで、uid 1000 を持つユーザーの名前が nick であるためです。次にコンテナに入り、確認してみましょう。

$ docker exec -it sleepme bash 

コンテナ内の現在のユーザーは、設定した appuser です。コンテナ内の /etc/passwd ファイルを確認すると、appuser の uid が 1000 であることがわかります。これは、ホスト マシンのユーザー nick の uid と同じです。

ユーザー nick だけが読み書きできる別のファイルを作成しましょう。

また、それをデータ ボリュームとしてコンテナーにマウントします。

$ docker run -d --name sleepme -w=/testv -v $(pwd)/testv:/testv テスト

コンテナでは、testfile の所有者は appuser になり、もちろん appuser にはファイルの読み取りと書き込みの権限があります。

ここで一体何が起こったのでしょうか?これは何を示しているのでしょうか?

まず、ホスト システムには、uid 1000 のユーザー ニックネームが存在します。次に、コンテナ内のプログラムは appuser として実行されます。これは、Dockerfile プログラムで USER appuser コマンドを使用して指定されます。

実際、システム カーネルによって管理される uid 1000 は 1 つだけです。ホスト マシンではユーザー nick と見なされ、コンテナーではユーザー appuser と見なされます。
したがって、明確にしておく必要があることが 1 つあります。コンテナー内では、ユーザー appuser はコンテナー外のユーザー nick の権利と権限を取得できるということです。ホスト上のユーザー nick または uid 1000 に付与された権限は、コンテナー内の appuser にも付与されます。

コマンドライン引数からユーザーIDをカスタマイズする

docker run コマンドの --user パラメータを使用して、コンテナ内のプロセスのユーザー ID を指定することもできます。たとえば、次のコマンドを実行します。

$ docker run -d --user 1000 --name sleepme ubuntu スリープ無限

コマンドラインでパラメータ --user 1000 を指定したので、スリープ プロセスの実効ユーザーは nick として表示されます。コンテナに入って見てみましょう:

$ docker exec -it sleepme bash 

何が起こっているのか?ユーザー名が「名前がありません!」と表示される! /etc/passwd ファイルを確認すると、確かに uid 1000 のユーザーは存在しません。ユーザー名がなくても、ユーザー ID の権限にはまったく影響しません。ニックネームを持つユーザーだけが読み書きできるファイルの読み書きは引き続き可能で、ユーザー情報はユーザー名ではなく uid に置き換えられます。

コンテナの作成時に docker run --user で指定されたユーザー ID は、Dockerfile で指定された値を上書きすることに注意してください。
テスト イメージを使用して 2 つのコンテナを再度実行します。

$ docker run -d テスト

スリープ プロセス情報を表示します。

$ docker run --user 0 -d テスト

スリープ プロセス情報を再度確認します。

--urser 0 パラメータを指定するプロセスは、有効なユーザーが root であることを示しており、コマンドラインパラメータ --user 0 が Dockerfile 内の USER コマンドの設定をオーバーライドすることを示しています。

要約する

この記事の例から、コンテナ内で実行されているプロセスにもホスト リソースへのアクセス権があることがわかります (Docker はデフォルトでユーザーを分離しません)。もちろん、一般的にコンテナ テクノロジでは、コンテナ内のプロセスの可視リソースがコンテナ内でブロックされます。ただし、データ ボリューム内のファイルに対する操作で示したように、コンテナー内のプロセスがホスト マシンのリソースにアクセスする機会を得ると、その権限はホスト マシン上のユーザーの権限と同じになることがわかります。したがって、より安全な方法は、デフォルトのルート ユーザーを使用するのではなく、コンテナー内のプロセスに適切な権限を持つユーザーを指定することです。もちろん、Linux のユーザー名前空間テクノロジーを使用してユーザーを分離するという、より良い解決策があります。次の記事では、ユーザー名前空間のサポートを有効にするために Docker を構成する方法を紹介します。

参照:

Docker コンテナでの uid と gid の動作を理解する
Docker エンジンのユーザー名前空間の紹介
ユーザー名前空間でコンテナを分離する

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

<<:  MySQLの日付文字列タイムスタンプ変換の詳細な説明

>>:  redhat7 に yum 経由で mysql5.7.17 をインストールするチュートリアル

推薦する

ポータルサイトのフォーカス画像のデザインに関するいくつかの結論

フォーカス画像は、画像、テキスト、動的なインタラクティブ効果を統合したコンテンツを表示する方法です。...

vue + Electron でデスクトップ アプリケーションを作成するためのサンプル コード

1.vueパッケージングここでは、vueネイティブパッケージングコマンドを使用してvueプロジェクト...

CentOS に Redis と MySQL をインストールする

1|0MySQL(MariaDB) 1|11. 説明MariaDB データベース管理システムは My...

Vue プロジェクトにインターフェース リスニング マスクを追加する方法

1. 事業背景マスク レイヤーを使用してユーザーの異常な操作を遮断する方法は、フロントエンドでよく使...

MySQL クエリのパケットが大きすぎる問題と解決策

問題の説明:エラーメッセージ:原因: com.mysql.jdbc.PacketTooBigExce...

MySQL 5.7.13 のインストールと設定方法の Mac でのグラフィック チュートリアル

MySQL 5.7.13 Mac用インストールチュートリアル、非常に詳細で、以下のように記録されてい...

React useEffect の理解と使用

目次繰り返しレンダリングループを避ける副作用の除去についてReact16.8 の新しい useEff...

MySQL の垂直テーブルを水平テーブルに変換する方法と最適化のチュートリアル

1. 縦型テーブルと横型テーブル垂直テーブル: テーブル内のフィールドとフィールド値はキーと値の形式...

js でパズルゲームを実装する

この記事では、パズルゲームを実装するためのjsの具体的なコードを参考までに共有します。具体的な内容は...

JS配列インデックス検出におけるデータ型の問題の詳細な説明

WeChat アプレット プロジェクトを書いていたとき、その中に「都市選択」機能がありました。作者は...

nginx は画像表示の遅さとダウンロードの不完全さの問題を解決します

前面に書かれた最近、ある読者から、ブラウザからサーバーにアクセスすると、画像の表示が遅く、ブラウザに...

Ubuntuがネットワークに接続できない場合の解決策

仮想マシン内の Ubuntu がネットワークに接続できない場合の効果的な解決策: 1. Ubuntu...

DPlayer.js ビデオ再生プラグインの使い方

DPlayer.jsビデオプレーヤープラグインは使いやすい主な用途: ビデオの再生、監視の開始、終了...

RocketMQ の Docker インストールとインストール中に発生した問題の解決策

目次rocketmqイメージを取得する名前rvを作成する単一のブローカーノードを作成するrocket...

DockerコンテナでのMySQLデータのインポート/エクスポートの詳細な説明

序文MySQL データのインポートとエクスポートは mysqldump コマンドで解決できることは誰...