Dockerコンテナでユーザーを分離する方法

Dockerコンテナでユーザーを分離する方法

前回の記事「Docker コンテナの UID と GID を理解する」では、Docker コンテナ内のユーザーとホスト マシン上のユーザーの関係を紹介し、Docker はデフォルトではホスト ユーザーとコンテナ内のユーザーを分離しないと結論付けました。 Linux のユーザー名前空間テクノロジー (「Linux 名前空間: ユーザー」を参照) を既に知っている場合は、当然次のような疑問が湧くでしょう。Docker はなぜユーザーの分離を実現するために Linux ユーザー名前空間を使用しないのでしょうか。実際、Docker にはすでに関連機能が実装されていますが、デフォルトでは有効になっていません。この記事では、コンテナ内でユーザーを分離するように Docker を構成する方法について説明します。
注: この記事のデモ環境は Ubuntu 16.04 です。

Linux ユーザー名前空間の理解

Linux ユーザー名前空間は、実行中のプロセスに対してセキュリティ関連の分離 (uid と gid を含む) を提供し、プロセスがこれらの制限を認識することなくシステム リソースへのアクセスを制限します。 Linux ユーザー名前空間の紹介については、私の記事「Linux 名前空間: ユーザー」を参照してください。

コンテナの場合、権限昇格攻撃を防ぐ最善の方法は、コンテナ アプリケーションを通常のユーザー権限で実行することです。
ただし、一部のアプリケーションはコンテナ内でルート ユーザーとして実行する必要があり、これがユーザー名前空間を使用するのに最適なシナリオです。ユーザー名前空間テクノロジーを使用して、ホスト内の通常のユーザー (通常の権限のみを持つユーザー) をコンテナー内のルート ユーザーにマッピングします。コンテナ内では、ユーザーは自分自身を自分のユーザー名前空間のルートとみなし、ルートのすべての権限を持ちますが、ホスト上のリソースに対しては非常に制限されたアクセス権 (通常のユーザー) しか持ちません。

ユーザー名前空間のユーザーマッピング

ユーザー名前空間を有効にするように Docker デーモンを構成する前に、従属ユーザー/グループと再マッピングに関するいくつかの概念を理解する必要があります。従属ユーザーとグループのマッピングは、2 つの構成ファイル /etc/subuid と /etc/subgid によって制御されます。デフォルトの内容を見てみましょう: ユーザー名前空間を有効にするように docker デーモンを構成する前に、従属ユーザー/グループとマッピング (再マッピング) に関するいくつかの概念を理解する必要があります。

subuid の場合、この行の意味は次のとおりです。

ユーザー nick には、現在のユーザー名前空間内に 100000 から 165535 までのユーザー ID を持つ 65536 人の従属ユーザーがいます。子ユーザー名前空間では、これらの従属ユーザーは 0 から 65535 までの ID を持つユーザーにマップされます。 subgid は subuid と同じ意味を持ちます。

たとえば、ユーザー nick は、ホスト マシン上で通常の権限を持つユーザーです。コンテナが属するユーザー名前空間にその従属 ID の 1 つ (100000 など) を割り当て、そのユーザー名前空間の uid 0 に ID 100000 をマップすることができます。この時点では、コンテナ内のプロセスにルート権限があっても、その権限はコンテナが配置されているユーザー名前空間内に限られます。ホスト マシン内に入ると、せいぜいニック ユーザーの権限しか得られません。

Docker のユーザー名前空間のサポートが有効になっている場合 (Docker の userns-remap 機能)、コンテナーにマップする異なるユーザーを指定できます。たとえば、dockeruser というユーザーを作成し、その subuid と subgid を手動で設定します。

ニックネーム:100000:65536
dockeruser:165536:65536

これを docker デーモンに割り当てます。

{
 "userns-remap": "dockeruser"
}

subuid 設定情報に注意してください。dockeruser と nick ユーザーに設定した従属 ID は重複しません。実際、どのユーザーの従属 ID 設定も重複することはできません。

あるいは、シンプルにして、Docker にすべての面倒な作業を任せることもできます。そのためには、Docker デーモンの userns-rempa パラメータを「default」として指定します。

{
 "userns-remap": "デフォルト"
}

この時点で、Docker は他の構成を自動的に完了します。

ユーザー分離を有効にするためにDockerデーモンを構成する

ここでは単純なアプローチを採用し、Docker にユーザー名前空間のデフォルト ユーザーを作成させます。まず /etc/docker/daemon.json ファイルを作成する必要があります。

$ sudo touch /etc/docker/daemon.json

次に、その内容を次のように編集し (ファイルがすでに存在する場合は、次の構成項目を追加するだけです)、Docker サービスを再起動します。

{
 "userns-remap": "デフォルト"
}
$ sudo systemctl docker.serviceを再起動します

ユーザーの分離についていくつかの点を確認しましょう。

まず、docker が dockremap という名前のユーザーを作成したことを確認します。

次に、新しいユーザーの dockremap 関連項目が /etc/subuid ファイルと /etc/subgid ファイルに追加されているかどうかを確認します。

次に、/var/lib/docker ディレクトリの下に新しいディレクトリ 165536.165536 が作成されていることがわかりました。ディレクトリの権限を確認します。

165536 は、ユーザー dockremap によってマップされた uid です。 165536.165536 ディレクトリの内容を表示します。

これは基本的に /var/lib/docker ディレクトリの内容と一致しており、ユーザー分離が有効になると、ファイル関連のコンテンツが新しく作成された 165536.165536 ディレクトリに配置されることを示しています。

上記のチェックにより、docker デーモンがユーザー分離機能を有効にしていることを確認できます。

ホストのUIDとコンテナのUID

Docker デーモンでユーザー分離を有効にした後、ホストの uid とコンテナの uid の変更を確認してみましょう。

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

uid 165536 はユーザー dockremap の従属 ID であり、ホスト マシン上で特別な権限はありません。ただし、コンテナ内のユーザーは root なので、結果は完璧に見えます。

新しく作成されたコンテナはユーザー名前空間を作成します

Docker デーモンがユーザー分離を有効にする前は、新しく作成されたコンテナ プロセスとホスト上のプロセスは同じユーザー名前空間にあります。つまり、Docker はコンテナに新しいユーザー名前空間を作成しません。

上図では、コンテナプロセスのスリープとホスト上のプロセスは同じユーザー名前空間にあります(ユーザー分離機能は有効になっていません)。

docker デーモンでユーザー分離を有効にした後、コンテナ内のプロセスのユーザー名前空間を表示してみましょう。

上の図の 4404 は、先ほど起動したコンテナ内のスリープ プロセスの PID です。ご覧のとおり、Docker はコンテナの新しいユーザー名前空間を作成します。このユーザー名前空間では、コンテナ内のユーザー ルートは神であり、最高権力を持ちます。

データボリューム内のファイルにアクセスする

データ ボリューム内のファイルにアクセスして、コンテナ内のルート ユーザーがどのような権限を持っているかを証明できます。それぞれユーザー root、165536、nick に属する 4 つのファイルを作成します。 root ユーザーのみが rootfile の読み取りと書き込みができます。ユーザー nick は nickfile の読み取りと書き込み権限を持っています。UID 165536 はファイル 165536file の読み取りと書き込み権限を持っています。すべてのユーザーが testfile の読み取りと書き込みができます。

次に、これらのファイルをデータ ボリュームとしてコンテナーにマウントし、コンテナーからアクセスするための権限を確認します。

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

コンテナ内の root ユーザーは 165536file と testfile にのみアクセスできます。つまり、このユーザーはホスト マシン内で非常に制限された権限を持っています。

コンテナ内のユーザー名前空間を無効にする

docker デーモンに「userns-remap」パラメータが設定されると、すべてのコンテナでユーザー分離がデフォルトで有効になります (新しいユーザー名前空間がデフォルトで作成されます)。場合によっては、ユーザー分離が有効になっていないシナリオに戻る必要があるかもしれません。この場合、--userns=host パラメータを使用して、単一のコンテナのユーザー分離を無効にすることができます。 --userns=host パラメータは主に次の 3 つのコマンドで使用されます。

docker コンテナ作成
dockerコンテナの実行
docker コンテナ実行

たとえば、次のコマンドを実行します。

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

プロセス情報を表示します:

プロセスの実効ユーザーは再び root になり、プロセスに対して新しいユーザー名前空間は作成されません。

既知の問題

ユーザー名前空間は比較的高度な機能です。現在、Docker によるサポートは完全ではありません。既存の機能との非互換性がいくつか知られています。

  • ホストの PID または NET 名前空間を共有する (--pid=host または --network=host)
  • 外部ストレージとデータ ボリューム ドライバーに互換性がなく、ユーザー名前空間をサポートしていない可能性があります。
  • --userns=host を指定せずに --privileged を使用する

要約する

Dockerはユーザー名前空間をサポートしており、設定方法も非常にシンプルです。ユーザー名前空間を有効にすると、セキュリティが向上しますが、同時に、さまざまな制限により他の個々の機能に問題が発生する可能性があります。現時点では、選択を行い、画一的な決定に別れを告げ、適切な機能が適切なシナリオに表示されるようにする必要があります。

参照:

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

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

以下もご興味があるかもしれません:
  • Dockerとiptablesとブリッジモードのネットワーク分離と通信操作の実装
  • Dockerコンテナのネットワーク管理とネットワーク分離の実装
  • Dockerを使用してコンテナリソースを制限する方法
  • Docker Docker の保存場所を変更する コンテナイメージのサイズ制限を変更する操作
  • Docker CPU 制限の実装
  • Docker がコンテナに利用可能な CPU を制限する方法
  • Docker でコンテナに使用できるメモリを制限する方法
  • Docker の分離と制限の原則の紹介

<<:  Ubuntu でディスク容量不足により MySQL が起動しない場合の解決策

>>:  ドラミング効果を実現するJavascript

推薦する

Facebook 出会い系サイトデザインのユーザー エクスペリエンス分析

<br />関連記事: Facebookの情報アーキテクチャの分析 元記事: http:...

スプレッド演算子のサンプルコードと JavaScript での応用

スプレッド演算子を使用すると、式をある時点で展開できます。スプレッド演算子は、複数のパラメーター (...

MySQL 8.0.11 のインストールと設定方法のグラフィックチュートリアル MySQL 8.0 の新しいパスワード認証方法

この記事では、参考までにMySQL8.0.11のインストールと設定方法、およびMySQL8.0の新し...

ボタンをEnterキーに関連付けるjsコード

コードをコピーコードは次のとおりです。 <html> <ヘッド> <ス...

Linuxドライバのプラットフォームバスの詳細説明

目次1. プラットフォームバスの紹介1.1. Linuxドライバの分離と階層化1.1.1. Linu...

IDEA で mysql8.0.3 と mybatis-generator を使用する際に発生するバグ

1. プラグインを追加し、pomファイルの下に次の設定を追加します。 <!-- mybatis...

Vueで親子コンポーネント通信を実装する方法

目次1. 親コンポーネントと子コンポーネントの関係2. 小道具3. $エミット4. $親V. 結論 ...

mysql 8.0.12 winx64 のダウンロードとインストールのチュートリアル

MySQL 8.0.12のダウンロードとインストールのチュートリアルは参考までに、具体的な内容は次の...

HTML での select optgroup タグの使用の概要

時々、選択した内容をグループ化する必要があります。以前はプログラム制御を使用していました。今日、se...

ffmpeg コマンドラインを使用してビデオを変換するためのサンプルコード

この記事の本文を始める前に、まず ffmpeg プログラムをインストールする必要があります (Lin...

Vue の新しいおもちゃ VueUse の具体的な使い方

目次序文VueUseとは使いやすいおなじみの手ぶれ補正やスロットル機能もありますグローバル状態を共有...

Ubuntu 18.04 は pyenv、pyenv-virtualenv、virtualenv、Numpy、SciPy、Pillow、Matplotlib をインストールします

1. 現在、Pythonのバージョン管理ツールは数多く存在します。その中でも比較的使いやすいのがPy...

MySQLクエリのパフォーマンスを分析する方法

目次スロークエリの基礎: データ取得の最適化データベースから不要なデータが要求されていないか確認する...

アバター変更機能を実装するJavaScript

この記事では、アバター変更機能を実装するためのJavaScriptの具体的なコードを参考までに共有し...

JS でカルーセル画像を実装するいくつかの方法

カルーセル主なアイデアは次のとおりです。大きなコンテナには、コンテナの幅の整数倍の非常に長いテーブル...