Linux 名前空間ユーザーの詳細な説明

Linux 名前空間ユーザーの詳細な説明

ユーザー名前空間は Linux 3.8 で追加された新しい名前空間で、ユーザー ID やグループ ID、キー、機能などのセキュリティ関連のリソースを分離するために使用されます。同じユーザーのユーザー ID とグループ ID は、異なるユーザー名前空間では異なる場合があります (PID 名前空間と同様)。つまり、ユーザーは、あるユーザー名前空間では通常のユーザーである一方、別のユーザー名前空間ではスーパーユーザーである可能性があります。

ユーザー名前空間はネストできます (現在、カーネルは最大 32 層を制御します)。システムのデフォルトのユーザー名前空間を除き、すべてのユーザー名前空間には親ユーザー名前空間があり、各ユーザー名前空間には 0 個以上の子ユーザー名前空間を含めることができます。 プロセス内で unshare または clone が呼び出されて新しいユーザー名前空間が作成されると、現在のプロセスの元のユーザー名前空間が親ユーザー名前空間になり、新しいユーザー名前空間が子ユーザー名前空間になります。

注: この記事のデモ環境は Ubuntu 16.04 です。

ユーザー名前空間を作成する

unshare コマンドの --user オプションを使用して、新しいユーザー名前空間を作成できます。

$ unshare -user -r /bin/bash 

-r パラメータを使用して、新しいユーザー名前空間のルート ユーザーを外部ニックネーム ユーザーにマッピングします (マッピングに関連する概念については次に説明します)。新しいユーザー名前空間では、ルート ユーザーに、uts 名前空間などの他の名前空間を作成する権限が与えられます。これは、現在の bash プロセスにすべての機能があるためです。

新しい uts 名前空間を作成して試してみましょう。

$ unshare --uts /bin/bash 

新しい uts 名前空間が正常に作成されたことがわかります。これは、ユーザー名前空間を除き、他のタイプの名前空間を作成するには CAP_SYS_ADMIN 機能が必要になるためです。新しいユーザー名前空間が作成され、uid と gid がマップされると、このユーザー名前空間の最初のプロセスは完全な機能をすべて持つようになり、他のタイプの新しい名前空間を作成できるようになります。

実際、上記の操作 (2 つの名前空間の作成) を 2 つのステップに分割する必要はありません。unshare を使用すると、一度に複数の名前空間を作成できます。

unshare の実装では、実際には CLONE_NEWUSER | CLONE_NEWUTS が渡されます。これはおおよそ次のようになります。

共有を解除します(CLONE_NEWUSER | CLONE_NEWUTS);

上記の場合、カーネルは CLONE_NEWUSER が最初に実行されることを確認し、次に残りの CLONE_NEW* を実行します。これにより、ルート ユーザーを使用せずに新しいコンテナを作成できます。このルールはクローン機能にも適用されます。

UIDとGIDのマッピングを理解する

前回のデモでは、ユーザー名前空間間のユーザーのマッピングについて説明しました。今度は同じデモを使用して、マッピングが何であるかを理解しましょう。まず、現在のユーザーの ID とユーザー名前空間を確認しましょう。

次に、unshare --user /bin/bash コマンドを実行して、新しいユーザー名前空間を作成します。今回は -r パラメータがないことに注意してください。

$ unshare --user /bin/bash 

新しいユーザー名前空間では、現在のユーザーは nobody になり、ID は 65534 になります。

これは、親ユーザー名前空間のユーザー ID とグループ ID を子ユーザー名前空間にまだマッピングしていないためです。この手順は、システムが 1 つのユーザー名前空間のユーザーの権限を他のユーザー名前空間で制御できるようにするために必要です (他のユーザー名前空間のプロセスにシグナルを送信したり、他のユーザー名前空間にマウントされたファイルにアクセスしたりするなど)。

マッピングがない場合、getuid() および getgid() を使用して新しいユーザー名前空間のユーザー ID とグループ ID を取得すると、システムはファイル /proc/sys/kernel/overflowuid で定義されたユーザー ID と proc/sys/kernel/overflowgid で定義されたグループ ID を返します。どちらのデフォルト値も 65534 です。つまり、マッピングが指定されていない場合、ID はデフォルトで 65534 にマッピングされます。

次に、新しいユーザー名前空間でのニックネーム ユーザーのマッピングを完了します。

ID をマッピングする方法は、/proc/PID/uid_map ファイルと /proc/PID/gid_map ファイルにマッピング情報を追加することです (ここで、PID は新しいユーザー名前空間のプロセス ID であり、両方のファイルは最初は空です)。これら 2 つのファイル内の構成情報の形式は次のとおりです (各ファイルには複数の構成情報を含めることができます)。

ID-inside-ns ID-outside-ns 長さ

たとえば、構成 0 1000 500 は、親ユーザー名前空間の 1000 ~ 1500 が新しいユーザー名前空間の 0 ~ 500 にマップされることを意味します。

uid_map ファイルと gid_map ファイルの書き込み操作には、厳密な権限制御があります。簡単に言うと、これら 2 つのファイルの所有者は、新しいユーザー名前空間を作成したユーザーであるため、このユーザーと同じユーザー名前空間内の root アカウントは、これらのファイルに書き込むことができます。このユーザーがマップ ファイルに書き込む権限を持っているかどうかは、CAP_SETUID および CAP_SETGID 機能を持っているかどうかによって決まります。注: マップ ファイルにデータを書き込むことができるのは 1 回だけですが、一度に複数のエントリを書き込むことができ、エントリの最大数は 5 です。

開いたばかりのシェル ウィンドウを最初のシェル ウィンドウとして呼び出し、ユーザー マッピング操作 (新しいユーザー名前空間でユーザー ニックネームをルートにマップする) の実行を開始します。

最初のステップは、最初のシェル ウィンドウで現在のプロセスの ID を確認することです。

2 番目のステップは、新しいシェル ウィンドウ (2 番目のシェル ウィンドウと呼ぶ) を開くことです。プロセス 3049 のマッピング ファイルのプロパティを表示します。

ユーザー nick はこれら 2 つのファイルの所有者です。これら 2 つのファイルにマッピング情報を書き込んでみましょう。

自分がファイルの所有者なのに、ファイルに書き込む権限がないのは奇妙に思えます。実際、根本的な理由は、現在の bash プロセスに CAP_SETUID および CAP_SETGID 権限がないことです。

次に、/bin/bash プログラムの関連する機能を設定します。

次のようにコードをコピーします
$ sudo setcap cap_setgid、cap_setuid+ep /bin/bash

$ sudo setcap cap_setgid、cap_setuid+ep /bin/bash

次に bash をリロードすると、対応する機能が表示されます。

次に、マッピング情報をマップ ファイルに書き換えます。

$ エコー '0 1000 500' > /proc/3049/uid_map
$ エコー '0 1000 500' > /proc/3049/gid_map

今回は書き込みが成功しました。後でマッピング情報を手動で書き込む必要はないので、次のコマンドを使用して /bin/bash の機能を元の設定に戻します。

$ sudo setcap cap_setgid,cap_setuid-ep /bin/bash 

ステップ3: 最初のシェルウィンドウに戻る

bash をリロードし、id コマンドを実行します。

現在のユーザーは root (新しいユーザー名前空間の root ユーザー) になりました。現在の bash プロセスの機能を見てみましょう。

0000003fffffffff は、現在実行中の bash がすべての機能を持っていることを意味します。

ステップ4. 最初のシェルウィンドウで

/root ディレクトリのアクセス権限を確認します。

許可なし!ホスト名を変更してみてください:

まだ許可が出ません!この新しいユーザー名前空間のルート ユーザーは、親ユーザー名前空間では機能しないようです。これはまさに、ユーザー名前空間が期待する効果です。他のユーザー名前空間のリソースにアクセスする場合、アクセスを実行するために権限が使用されます。たとえば、root の親ユーザー名前空間に対応するユーザーは nick であるため、システムのホスト名を変更することはできません。

通常ユーザー nick にはホスト名を変更する権限がありません。では、デフォルトユーザー名前空間の root ユーザーをサブユーザー名前空間の root ユーザーにマッピングした後、ホスト名を変更することはできますか?答えはノーです!これは、マッピングがどのように実行されたとしても、子ユーザー名前空間のユーザーが親ユーザー名前空間のリソースにアクセスする場合、そのユーザーが開始するプロセスの機能は空であるため、子ユーザー名前空間のルート ユーザーは親ユーザー名前空間の通常のユーザーと同等になるためです。

ユーザー名前空間と他の名前空間の関係

Linux の各名前空間は、ユーザー名前空間に関連付けられています。このユーザー名前空間は、対応する名前空間が作成されたときにプロセスが属するユーザー名前空間です。これは、各名前空間に所有者 (ユーザー名前空間) があることと同じです。これにより、任意の名前空間での操作がユーザー名前空間の権限によって制御されることが保証されます。これは、変更する uts 名前空間が親ユーザー名前空間に属しており、新しいユーザー名前空間のプロセスには古いユーザー名前空間の機能がないため、子ユーザー名前空間でホスト名を設定すると失敗する理由でもあります。

uts 名前空間を例にとると、uts_namespace 構造体にはユーザー名前空間へのポインターがあり、それが属するユーザー名前空間を指します (私が確認した v4.13 カーネルでは、uts_namespace 構造体の定義は /include/linux/utsname.h ファイルにあります)。

他の名前空間の定義も同様です。

要約する

他の名前空間と比較すると、ユーザー名前空間は少し複雑です。これは機能性によるもので、権限管理に関しては直感的ではない傾向があります。この記事では、ユーザー名前空間の基本的な概念についてのみ紹介しました。他にも興味深い内容が数多くありますので、ぜひご覧ください。

参照:

ユーザー名前空間のマニュアルページ
名前空間の運用、パート 5: ユーザー名前空間
名前空間の運用、パート 6: ユーザー名前空間についてさらに詳しく
Linuxの機能

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

以下もご興味があるかもしれません:
  • Docker の基礎: Linux 名前空間のグラフィック説明

<<:  Vueはボタン切り替え画像を実装します

>>:  MySQL がテーブルを読み取れないエラー (MySQL 1018 エラー) の解決方法

推薦する

Linux アカウントのパスワードを変更する詳細な例

個人アカウントのパスワードを変更する一般ユーザーが個人アカウントのパスワードを変更する場合は、他のコ...

Linux DMAインターフェースの知識ポイントの詳細な説明

1. 2種類のDMAマッピング1.1. 一貫性のあるDMAマッピング主に長期間使用されるエリアをマッ...

Reactの親コンポーネントと子コンポーネント間のデータ転送の詳細な説明

目次1. 親コンポーネントが子コンポーネントにデータを渡す1.1. 親コンポーネントコード1.2. ...

MySQL 5.7.16 のインストールと設定方法のグラフィック チュートリアル (Ubuntu 16.04)

Ubuntu 16.04 に MySQL 5.7 をインストールするにはどうすればいいですか?メイ...

vue3のテレポート瞬間移動機能の使い方を詳しく解説

vue3テレポート瞬間移動機能の使用は参考用です。具体的な内容は次のとおりです。テレポートは通常、瞬...

シンプルなショッピングカート機能を実現するjs

この記事の例では、簡単なショッピングカート機能を実現するためのjsの具体的なコードを参考までに共有し...

TypeScript の Enum が問題となる理由

目次どうしたの?いつ使うか列挙の数を制御するビット値コントロールインデックス非数値列挙結論はType...

Linux で Multitail コマンドを使用するチュートリアル

MultiTail は、tail コマンド機能と同様に、複数のドキュメントを同時に監視するために使用...

MySQL で左結合を使用して where 条件を追加する問題の詳細な分析

現在の需要:グループとファクターの 2 つのテーブルがあります。1 つのグループは複数のファクターに...

WindowsにOpenSSLをインストールし、OpenSSLを使用して公開鍵と秘密鍵を生成します。

1. OpenSSL公式サイト公式ダウンロードアドレス: https://www.openssl....

主軸上のFlex子要素の比率を制御する方法

背景フレックス レイアウトにより、配置とスペースの割り当てがより効果的に実現されます。最近、flex...

Docker で MySQL を起動したときに SQL 文を自動的に実行する方法

Docker で MySQL コンテナを作成する場合、コンテナの起動後にデータベースとテーブルが自動...

docker compose を使用して fastDFS ファイル サーバーを構築する方法

前回の記事では、docker compose を使用して FastDfs ファイル サーバーをインス...

Docker プライベート ウェアハウスを構築する (自己署名方式)

作成したイメージを一元管理し、サービスの展開を容易にするために、プライベート Docker リポジト...

HTML の META タグの使用に関するヒントの例

HTML メタタグHTML メタタグは、Web ページのコンテンツに関する情報をブラウザや検索エンジ...