名前空間は、 Linux カーネルの機能の一つで、カーネルリソースを分割し、あるプロセス群にはあるリソース群を、別のプロセス群には別のリソース群を認識させるものです。この機能は、リソースとプロセス群に同じ名前空間タイプを割り当てつつ、それらの名前空間が明確に分離された環境を参照できるようにすることで機能します。これにより、プロセスまたはプロセス グループがシステムのハードウェアおよびソフトウェア リソースの唯一のユーザーであるかのような錯覚を生み出します。このようなリソースの例としては、プロセス ID、ホスト名、ユーザー ID、ファイル名、ネットワーク インターフェイス、プロセス間通信(IPC) メカニズムなどがあります。[ 1 ] [ 2 ]
Linuxの名前空間は、 cgroup (コントロールグループ)とともに、 Docker、Kubernetes、LXC、Podmanなどの最新のOSレベルの仮想化およびLinuxコンテナ化プラットフォームを支える基盤技術です。cgroupは、プロセスが使用できるシステムリソースの量(CPU、メモリ、ディスクI/O制限など)を決定しますが、名前空間は、プロセスが参照および操作できるものを決定します。
「名前空間」という用語は、特定の種類の名前空間(例えば、プロセスID名前空間)だけでなく、特定の名前空間を指す場合にもよく使われます。Linuxシステムは、各種類につき1つの初期名前空間から始まり、これはすべてのプロセスで共有されます。プロセスはその後、追加の名前空間を作成したり、既存の名前空間に参加したりすることができ、複雑で入れ子になった分離境界を実現できます。
Linux の名前空間は、ベル研究所のオペレーティングシステム Plan 9全体で利用されていたより広範な名前空間機能に大きく影響を受けており、すべてをファイルとして扱い、プロセスごとの名前空間分離を提供していました。[ 3 ]
Linux の名前空間の実装は、2002 年に 2.4.19 カーネルがリリースされたときに始まりました。最初に導入された名前空間は、カーネル開発者 Al Viro によって開拓された mount 名前空間で、ファイルシステムのマウント ポイントを分離するものでした。[ 4 ]この種のものとしては初めてだったため、導入されたシステム コールフラグは単にCLONE_NEWNS(New Namespace) という名前で、「mount」を指定していないため、歴史的な遺物と見なされることがよくあります。
その後、数年かけて段階的に名前空間が導入されました。
Linuxカーネルバージョン5.6以降、名前空間には正確に8種類存在します。名前空間の機能はすべての種類で統一されており、各プロセスは名前空間に関連付けられ、その名前空間に関連付けられたリソース(該当する場合はその子孫名前空間を含む)のみを参照または使用できます。これにより、各プロセス(またはプロセスのグループ)は、システムに対する独自の、区分けされたビューを持つことができます。
マウントネームスペースは、Linuxに最初に追加されたネームスペースであり、マウントポイントを制御します。マウントネームスペースは、ファイルシステム階層を独立したビューでプロセスに提供します。作成時に、現在のマウントネームスペースのマウントポイントが最初に新しいネームスペースにコピーされます。ただし、その後作成またはアンマウントされたマウントポイントは、デフォルトではネームスペース間で伝播されません。
Linuxの共有サブツリー機能を使用すると、ホストとコンテナ間、またはその逆方向にイベント(USBドライブのマウントなど)を伝播するように特定のマウントポイントを設定できます。[ 10 ]このタイプの新しい名前空間を作成するために使用されるクローンフラグはですCLONE_NEWNS。
PID名前空間は、プロセスに独立したプロセスID(PID)のセットを提供します。PID名前空間は厳密にネストされています。新しいPID名前空間内で新しいプロセスが作成されると、現在の名前空間から最初の(ルート)PID名前空間までの各名前空間ごとに異なるPIDが割り当てられます。したがって、最初のPID名前空間(ホストオペレーティングシステムなど)のプロセスは、コンテナ内のプロセスとは異なるPIDではありますが、すべてのコンテナにわたるすべてのプロセスを参照できます。
PID名前空間で最初に作成されたプロセスには、プロセスID番号1が割り当てられます。これは、ホストシステムの通常のinitプロセスとほぼ同じ特別な扱いを受けます。特に注目すべきは、名前空間内の孤立したプロセスはすべて、自動的にこのPID 1プロセスに再親付けされることです。このPID 1プロセスが終了すると、カーネルはシグナルを送信して、そのPID名前空間内の他のすべてのプロセスとその子孫を直ちに終了しますSIGKILL。[ 11 ]
ネットワーク名前空間は、ネットワークスタックを仮想化します。新しいネットワーク名前空間が作成されると、ループバックインターフェイス(lo)のみが含まれ、初期状態ではダウンしています。各ネットワークインターフェイス(物理インターフェイスか仮想インターフェイスかを問わず)は、一度に1つのネットワーク名前空間にのみ存在できますが、管理者はインターフェイスを名前空間間でアクティブに移動できます。
各ネットワーク名前空間は、独自のIPアドレスセット、ルーティングテーブル、ソケットリスト、接続追跡テーブル、ファイアウォールルール( iptablesやnftablesなど)、およびその他のネットワーク関連リソースを保持します。[ 5 ]コンテナにネットワーク接続を付与するために、管理者は通常、仮想イーサネット(veth)ペアを作成し、一方の端をホスト名前空間に、もう一方の端をコンテナのネットワーク名前空間に配置し、ホスト側を物理ネットワークにブリッジします。ネットワーク名前空間を破棄すると、その中の仮想インターフェイスは自動的に破棄され、物理インターフェイスは元のネットワーク名前空間に戻されます。
IPC名前空間は、SysVスタイルのプロセス間通信メカニズムやPOSIXメッセージキューからプロセスを分離します。これにより、異なるIPC名前空間のプロセスが共通のIPC識別子を使用して相互に通信することを防ぎます。例えば、異なる名前空間の2つのプロセスが同じ共有メモリセグメント識別子を使用してSHM関数群を介してメモリを割り当てる場合、カーネルはそれらに完全に分離された2つの共有メモリ領域が提供されることを保証します。
UTS名前空間は、ホスト名とNISドメイン名という2つのシステム識別子を分離します。UTSという名前は、システムコールに渡されるデータ構造に由来し、歴史的にはUNIXタイムシェアリングunameシステムの略です。プロセスが新しいUTS名前空間を作成すると、ホスト名とドメイン名は呼び出し元の名前空間からコピーされます。新しい名前空間内のプロセスは、ホストマシンや他のコンテナに影響を与えることなくホスト名を変更できます。[ 12 ]
ユーザーネームスペースは、複数のプロセス群にわたって特権の分離とユーザー識別情報の分離の両方を提供するように設計された、重要なセキュリティ機能です。カーネル3.8で完全に導入されたユーザーネームスペースは、非特権コンテナの基盤となっています。PIDネームスペースと同様に、ユーザーネームスペースもネスト構造になっており、新しく作成されたネームスペースは、それを作成したネームスペースの子として扱われます。
ユーザー名前空間は、コンテナの内部視点からホストシステムのグローバル視点にユーザー ID (UID) とグループ ID (GID) を変換するマッピング テーブルを保持します。これにより、プロセスはコンテナ内でルート権限 (UID 0) を持つことができますが、基盤となるホスト マシン上では、権限のない制限付きユーザー ID (UID 100000 など) に数学的にマッピングされます。[ 13 ]脆弱性によりコンテナの「ルート」プロセスが名前空間から抜け出せた場合でも、ホスト システムはそれを制限付きユーザー ID として扱い、潜在的な被害を大幅に制限します。
cgroup名前空間は、プロセスが属する制御グループ階層の識別情報を隠蔽します。この名前空間が存在する前は、コンテナ内のプロセスは、ホストシステムに対するcgroupのパス全体(例:)を検査して見ることができました。/proc/self/cgroup/sys/fs/cgroup/memory/docker/container_id
cgroupファイルシステムビューを仮想化することで、cgroup名前空間内のプロセスは自身のcgroupディレクトリをルートとして認識します(/)。これにより、ホストの基盤となるインフラストラクチャに関する情報漏洩を防ぎ、コンテナオーケストレーションツールが競合するcgroupパスなしでコンテナをノード間でシームレスに移行できるようになります。この名前空間タイプは、2016年3月からLinux 4.6に存在しています。[ 14 ]
タイムネームスペースを使用すると、プロセスは異なるシステム時刻を監視できます。これは、2020 年 3 月に Linux 5.6 で導入されました。具体的には、2 つの特定のカーネルクロックを分離しCLOCK_MONOTONICますCLOCK_BOOTTIME。
コンテナをある物理ホストから別の物理ホストに移行したり、スナップショットから復元したりすると、新しいホストのシステム稼働時間とクロック値は、当然ながら古いホストとは異なります。タイムネームスペースを使用すると、コンテナランタイムがクロックオフセットを設定できるため、コンテナ内のアプリケーションが突然の時間的な変動による混乱を経験することがなくなります。
syslog名前空間は、カーネルのログリングを分離するために、HuaweiのエンジニアであるRui Xiangによって提案されました。しかし、この提案はLinuxカーネルのメインラインには統合されませんでした。 [ 15 ]その代わりに、ユーザー空間のソリューションがこの要件をほぼ満たしました。たとえば、systemdは、分離されたログ環境を提供するために、2020年2月に「ジャーナル名前空間」の概念を導入しました。[ 16 ]
インテグリティ測定アーキテクチャ(IMA)は、ファイルが改ざんされていないことを確認するために、アクセス前にファイルを測定するカーネルセキュリティサブシステムです。標準のIMAはグローバルに動作するため、コンテナ環境で競合が発生します。IBMとHuaweiからの多大な貢献により、カーネルコミュニティによる継続的な開発は、IMA名前空間の導入を目指しています。これにより、各コンテナが分離されたプラットフォーム構成レジスタ(PCR)、固有の測定ログ(ML)、および独立した評価キーを維持できるようになり、ハードウェアレベルの暗号化による証明を個々のコンテナに直接提供できるようになります。[ 17 ]
管理操作における権限分離を容易にするため、すべての名前空間タイプはユーザー名前空間に紐付けられています。非ユーザー名前空間が作成された場合、その名前空間は作成時にアクティブであったユーザー名前空間によって「所有」されているとみなされます。
CAP_SYS_ADMIN所有するユーザー名前空間で管理権限(具体的には、機能)を持つユーザーは、その名前空間に対して管理アクションを実行できます。たとえば、プロセスがネットワークインターフェイスの IP アドレスを変更する管理権限を持っている場合、そのプロセスはそれを実行できますが、そのアクティブなユーザー名前空間がその特定のネットワーク名前空間を所有している場合に限ります。最初の(ホスト)ユーザー名前空間は他のすべての名前空間の祖先であるため、ホストのルートユーザーは、システム全体にわたるすべての名前空間タイプに対する管理制御を本質的に保持します。[ 18 ]
名前空間はカーネル内で仮想ファイルオブジェクトとして表現され、procfs擬似ファイルシステムを介してアクセス可能です。
カーネルは、パス にある各実行プロセスの名前空間関連付けを公開します。 内の多くの非ファイル リソースと同様に、これらのエントリは特別なシンボリック リンクとして現れます。リンクを読み取ると、 の形式の文字列が得られます。/proc/pid/ns/kind/prockind:[inode_number]
これらのinode番号は、カーネルメモリ内の固有の名前空間オブジェクトと1対1に対応します。2つのプロセスが特定の名前空間タイプ(例net:[4026531969]:)に対して同じinode番号を示す場合、それらはその名前空間を共有します。
Linux 6.1.0 以降では、文字列は、、、、、、のkindいずれかになります。さらに、子プロセスが親プロセスとは異なる特性を継承する可能性がある名前空間 (PID やユーザー名前空間など) については、カーネルがリンクを提供します。cgroupipcmntnetpidtimeuseruts/proc/pid/ns/kind_for_children
4つの主要なシステムコールが名前空間を直接操作します。
clone: 新しいプロセスを生成するために使用されます。特定のフラグ(やなどCLONE_NEWPID)を渡すことでCLONE_NEWNET、カーネルは指定された新しい名前空間を作成し、その中に子プロセスを配置します。unshare: プロセスが実行コンテキストの一部を親プロセスから切り離すことを可能にし、呼び出し元のプロセスを事実上まったく新しい名前空間に移動させます。setns: 実行中のプロセスが既に存在する名前空間に入ることを許可します。これには、名前空間のシンボリックリンクのいずれかを指すファイルディスクリプタ/procが必要です。ioctl: 特定の名前空間リクエスト ( やNS_GET_PARENTなどNS_GET_USERNS) で使用して、異なる名前空間間の階層関係を検出します。システムのどの部分からも名前空間が参照されなくなった場合、カーネルは自動的にそれを破棄します。含まれるリソースのクリーンアッププロセスは、名前空間の種類によって異なります。名前空間は、以下のいずれかの条件が満たされている限り、アクティブに参照され、維持されているとみなされます。
/proc/pid/ns/kindiproute2これは、ファイルシステム内に作成されるバインドマウントの基盤となります(これは、プロセスを実行せずにネットワーク名前空間を維持するために、ネットワークツールなどで一般的に使用される手法です)。Linux ネームスペースは、現代のソフトウェア環境全体で広く採用されています。これらは、コンテナ技術を構築するためにcgroupsと普遍的に組み合わされています。例としては、 Docker、[ 19 ] LXC (Linux Containers)、Podman 、 Kubernetesのようなコンテナオーケストレーションシステムなどがあります。
純粋なコンテナ以外にも、名前空間はプロセスのサンドボックス化やセキュリティのために広く利用されています。Google ChromeやChromium は、Web レンダリング プロセスをサンドボックス化するためにユーザー、PID、ネットワークの名前空間に大きく依存しており、レンダラーが侵害された場合に攻撃者が与えることができる損害を大幅に制限しています。[ 20 ] FlatpakやSnapなどのパッケージ フォーマットは、名前空間を使用してデスクトップ アプリケーションをホスト ファイルシステムやユーザー データから分離しています。
さらに、init システムsystemd は名前空間を使用してシステム サービスを保護します。systemd サービス ファイル内のPrivateNetwork=yesや などのディレクティブはPrivateTmp=yes、それぞれ隔離されたネットワーク内でデーモンを起動し、名前空間をマウントするようにカーネルに指示します。
コマンドラインユーティリティもこれらの機能を活用しています。このutil-linuxパッケージにはunshare、新しく作成した名前空間内でシェルやスクリプトを起動できるコマンドが含まれています。名前空間を利用して、隔離された非特権のrootライクな環境を作成する例を以下に示します。
unshare --map-root-user --fork --pid --mount-proc --root = " ${ chrootdir } " " $@ "このコマンドは、新しいユーザー、PID、およびマウント名前空間でプロセスを起動し、従来のコマンドの現代的でより安全な同等物として機能しますchroot。