104
Container と Namespace Isolation @maruyama097 ととととと

ContainerとName Space Isolation

Embed Size (px)

Citation preview

Page 1: ContainerとName Space Isolation

Container と Namespace Isolation

@maruyama097

丸山不二夫

Page 2: ContainerとName Space Isolation

Agenda 二つの仮想化技術  VM と Container Linux Kernel での Container サポート Docker の Security を考える あらためて、 Linux Kernel による Namespace

Isolation を考える Capability Cgroup Linux Kernel での Container サポートの「歴史」 参考資料

Page 3: ContainerとName Space Isolation

二つの仮想化技術  VM とContainer

はじめに、 Hyperviser ベースの VMと、 Container という二つの仮想化技術を比較しておこう。

Page 4: ContainerとName Space Isolation

VM と Container VM は、 Host OS 上の Hyperviser(Type 2) 上で、

Host OS とは独立した Guest OS と自前の bin/libを持った Virtual Machine を立ち上げ、その中でアプリを動かす。

Container では、 Guest OS 抜きで、 Host OS 上に直接 Container を立ち上げる。可能であれば、 bin/lib も、 Host OS と共有する。

Page 5: ContainerとName Space Isolation

http://goo.gl/3wlAoe

Diagram source: Docker Inc.

Page 6: ContainerとName Space Isolation

Container ベースの仮想化アーキテクチャー

Hyperviser ベースの仮想化アーキテクチャー

Docker Engine アーキテクチャー

http://arxiv.org/pdf/1501.02967v1.pdf

Page 7: ContainerとName Space Isolation

VM と比べての Container のメリット

http://goo.gl/bT5soe

サイズ

立ち上がり

  統合  

大きい 小さい

遅い 早い

難しい 易しい

Page 8: ContainerとName Space Isolation

VM のメリットと Container の課題  VM 上のプロセスは、 Guest OS のプロセスであっ

て、 Host OS のプロセスではない。同じホストの上で動いていても、異なる VM 上のプロセスは、異なる Guest OS の管理下にあって、相互に干渉しない。

ただ、 Container 上のプロセスは、同時に、 Host OS のプロセス「でも」ある。同じホストの上で動いている Container 上のプロセスは、潜在的には、特権を持つ Host OS 上の他のプロセスから干渉を受ける可能性がある。それはセキュリティ上の危険にもなりうる。

一方で、 Container は、可能な範囲で、 Host OS のリソースを利用しようとする。共有しつつ隔離することは、簡単ではない。 VM 型の仮想化よりContainer 型の仮想化が遅れて登場したのには、そういう理由もある。

Page 9: ContainerとName Space Isolation

Linux Kernel でのContainer サポート

OS 上で Container の機能を実現するためには、クリアしなければならない技術的な課題が、いくつかあった。それらの課題は、基本的には、 linux Kernel の Container サポート機能の発展・強化によって克服されてきた。まず、その概略を見ておこう。

Page 10: ContainerとName Space Isolation

Container を支えるLinux Kernel の機能 基本的には、次の三つの Linux Kernel の機能

が、 Container 技術を支えている。

Capability: スレッド単位で、 Container 内のスーパー・ユーザの特権を制限する。

Namespace: プロセス単位で、ホストのリソースと、 Container のリソースを、「名前空間」で、隔離する。

Cgroup: タスク(プロセスのグループ)単位で、 CPU 、メモリ、ディスク I/O などのリソースの利用を制限・隔離する。

Page 11: ContainerとName Space Isolation

Container 内で制限される Capability

Page 12: ContainerとName Space Isolation

/

bin etc home opt sbin ... tmp usr var

maruyama fujio bin lib sbin local ...

bin etc tools docs ... bin etc git lib ...

emacs eclipse android ... node ocaml python

Chroot による Filesystem Isolation

Page 13: ContainerとName Space Isolation

/

bin etc / opt sbin ... tmp usr var

maruyama fujio bin lib sbin local ...

bin etc tools docs ... bin etc git lib ...

emacs eclipse android ... node ocaml python

chroot /home を実行すると  ...

「 chroot システムコールは、 1982年3月18日( 4.2BSDリリースの 17 ヶ月前)、ビル・ジョイがインストールおよびビルドシステムのテスト用に作成したのが起源である。」

Page 14: ContainerとName Space Isolation

/

bin etc / opt sbin ... tmp usr var

maruyama fujio bin lib sbin local ...

bin etc tools docs ... bin etc git lib ...

emacs eclipse android ... node ocaml python

   Filesystem の namespace Isolation の原型

いったん、 chroot されると、その新しい root 以下の filesystem( 白い領域 ) しか、見えなくなり、その他の領域のファイルへのアクセスもできなくなり、隔離される。

Page 15: ContainerとName Space Isolation

http://goo.gl/qcTuS8

PID namespace の階層構造

Page 16: ContainerとName Space Isolation

CPU : “Top cpuset”      /    \

  CPUSet1 CPUSet2   |    | (Professors)   (Students) さらに Top cpuset には、 (system tasks) が加わる。

Memory : Professors (50%), Students (30%), system (20%)

Disk : Professors (50%), Students (30%), system (20%)

Network : WWW browsing (20%), Network File System (60%),          others (20%)            /    \    Professors (15%) students (5%)

https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt

cgroup によるリソース管理の例

Page 17: ContainerとName Space Isolation

Docker の Security を考える

Docker のセキュリティ技術の中で、先に見たLinux Kernel の Isolation 機能が、どう利用されているのか、次の論文に従って見ておこう。“Analysis of Docker Security”http://arxiv.org/pdf/1501.02967v1.pdf

Page 18: ContainerとName Space Isolation

Process Isolation Process Isolation の主要な目的は、同じホスト下の

コンテナーが、プロセス管理のインターフェースを用いて、他のコンテナーに干渉するのを防ぐこと。

Docker は、プロセスの Isolation を、コンテナー内のプロセスを namespace でくるんで、ホストや他のコンテナーからのパーミッションや見え方を制限することで実現している。

Page 19: ContainerとName Space Isolation

PID namespace このメカニズムは、 PID namespace のサポート

の上で機能している。これは、プロセス ID (数値)の空間を、ホストのそれから Isolate する。 PID namespace は階層的で、あるプロセスは、自分のnamespace 内の、あるいは、子プロセスのnamespace 内の、他のプロセスのみを見ることができる。

その結果として、新しい namespace が生成されて、いったんあるコンテナーに割り当てられると、ホストは、新しい PID namespace 内のプロセスを見ることも影響を与えることもできるのだが、コンテナー内のプロセスは、ホストあるいは他のコンテナー内で走る別のプロセスを、見ることも何かをすることもできない。

Page 20: ContainerとName Space Isolation

新しい PID namespace での init 攻撃者が、他のプロセスのことを見ることができな

ければ、それを攻撃することは難しくなる。 PID namespaces は、同時に、それぞれのコンテ

ナーが、 init に似たプロセス (PID 1) を持つことを可能にする。このプロセスは、それが終了した時、namespace 内のすべてのプロセスを終了させる。このプロセスは、何か不審なことが検出された時、管理者がコンテナーを完全にシャットダウンするのを助ける。

Page 21: ContainerとName Space Isolation

Filesystem Isolation Filesystem の Isolation を実現するためには、ホス

トとコンテナーのファイルシステムは、不正なアクセスや改ざんから守られていなければならない。

Docker は、 mount namespaces 、 filesystem namespaces  とも呼ばれるが、それを、ことなったコンテナーに関連付けられたファイルシステムの階層の Isolation に利用している。 mount namespaces は、それぞれのコンテナーのプロセスに、ファイルシステム・ツリーの異なったview を提供し、コンテナー内で起きるすべての mount イベントが、コンテナーの内部にだけ影響を与えるように制限する。

Page 22: ContainerとName Space Isolation

namespace を持たないファイルシステム

しかし、 Kernel のファイルシステムのあるものは、namespace を持たない。例えば、以下のディレクトリーがそうである。/sys, /proc/sys, /proc/sysrq, /proc/irq-trigger, /proc/bus

Docker container は、操作のためにこれらをマウントする必要がある。このことは、コンテナーはホストからこれらのファイルシステムの View を継承し、それらに直接アクセスできるという問題を引き起こす。

Page 23: ContainerとName Space Isolation

Capability を用いたファイルシステム保護のメカニズム

Docker は、汚れたコンテナーが、これらのファイルシステムを通じて、ホストに与えうる脅威を、 次の二つのファイルシステム保護のメカニズムで制限しようとする。

1. コンテナーから、これらのファイルシステムに対する書き込みのパーミッションを削除する。

2. コンテナー内のいかなるプロセスも、いかなるファイルシステムの remount を許さない。

この二番目のメマニズムは、コンテナーからCAP_SY S_ADMIN の capability を削除することで達成される。

Page 24: ContainerとName Space Isolation

copy-on-write ファイルシステム

Docker は、また、 copy-on-write ファイルシステムというメカニズムを用いている。

Docker は、コンテナーをファイルシステム・イメージに基づいて生成するのだが、コンテナーは、自身のベースのイメージにコンテンツを書き込むことができる。

同一のイメージ上で複数のコンテナーが生成される時、 copy-on-write ファイルシステムは、それぞれのコンテナーが、その特定のファイルシステムにコンテンツを書き込むことを可能にする。こうして、他のコンテナーがコンテナー内に変更が起きたことを見つけるようなことを防止する。

Page 25: ContainerとName Space Isolation

Device Isolation Unix では、 kernel とアプリケーションは、デバイ

ス・ドライバーへのインターフェースとして機能する、基本的には特殊なファイルであるデバイス・ノードを通じてハードウェアにアクセスする。

もし、コンテナーが、 /dev/mem (物理メモリー ), /dev/sd∗ ( ストレージ ) , /dev/tty ( ターミナル ) といった重要なデバイス・ノードにアクセスできたとすると、ホスト・システムに深刻なダメージを与えることができることになる。こうして、コンテナーがアクセスできるデバイス・ノードに制限を課すことは、本質的に重要だということになる。

Page 26: ContainerとName Space Isolation

cgroup -- Device Whitelist Controller Device Whitelist Controller という cgroup の特徴は、 Docker がコンテナーにアクセスを許すデバイスの集合の制限する手段を提供する。それはまた、コンテナー内のプロセスが、新しいデバイス・ノードを生成することを禁止する。

さらに、 Docker は、コンテナーのイメージを、 nodev で mount する。つまり、そのイメージの中で、デバイス・ノードが、事前に作られていたとしても、そのイメージを利用したコンテナー内のプロセスは、 kernel と通信するのに、それを使うことはできない。

Page 27: ContainerとName Space Isolation

デバイス・アクセスの特権

デフォールトでは、 Docker は、そのコンテナーに拡張した特権を与えない。それゆえ、それはどんなデバイスにもアクセスできない。しかし、オペレーターがコンテナーを「特権を持つ」ものとして実行すれば、 Docker は、コンテナーに対してすべてのデバイスへのアクセスを認める。

Page 28: ContainerとName Space Isolation

IPC Isolation IPC (inter-process communication) は、 セマ

フォー、メッセージ・キュウ、共有メモリーのような、プロセス間でデータを交換するためのものである。

コンテナー内で走るプロセスは、 IPC のリソースのある部分のみを利用してコミュニケーションし、他のコンテナーやホストのプロセスに干渉は許さないように制限されなければならない。

Page 29: ContainerとName Space Isolation

IPC namespace Docker は、 IPC isolation を、 IPC

namespaces を使うことで達成している。それは、分離した IPC namespaces の生成を可能とする。

ある IPC namespaces 内のプロセスは、他の IPC namespaces の IPC リソースを読み書きできない。Docker は、それぞれのコンテナーに、 IPC namespaces を割り当て、そうすることで、コンテナー内のプロセスを、他のコンテナー内のプロセスの干渉から守っている。

Page 30: ContainerとName Space Isolation

Network Isolation Network isolation は、 Man-in-the-Middle (MitM)

や ARP spoofing といったネットワーク・ベースの攻撃を予防するのに重要である。コンテナーは、盗聴されないように、また、他のコンテナーやホストのネットワーク・トラフィックを操作できないように設定される必要がある。

それぞれのコンテナーに対して、 Docker は、 network namespaces を使って、独立したネットワーク・スタックを生成する。だから、それぞれのコンテナーは、自分の IP アドレス、 IP ルーティングテーブル、ネットワーク・デバイスを持っている。このことで、コンテナーは相互に対応するネットワーク・インターフェースで相互作用することを可能とする。それは、それが外部のホストと相互作用する仕方とまったく同じである。

Page 31: ContainerとName Space Isolation

Virtual Ethernet bridge デフォールトでは、コンテナー間の接続性は、ホス

トマシンに対するのと同じように、 Virtual Ethernet bridge によって与えられる。このアプローチによって、 Docker はホストマシンに、 docker0 という virtual ethernet bridge を生成する。それは、自動的にネットワーク・インターフェースにパケットを送り出す。

Docker が新しいコンテナーを生成するとき、それはユニークな名前で virtual ethernet インターフェースを確立し、このインターフェースをこのブリッジに接続する。このインターフェースはまた、コンテナーの eth0 インターフェースに接続され、コンテナーがブリッジにパケットを送ることを可能にする。

Page 32: ContainerとName Space Isolation

Limiting of Resources ここでは、 Docker のデフォールトの接続性モデル

は、 ARP spoofing や Mac flooding といった攻撃には弱いことを注意しておこう。なぜなら、ブリッジは、送られてきたパケットすべてをフィルタリングなしでフォワードするからである。

Denial-of-Service (DoS) は、マルチ・テナント・システムに対する最も一般的な攻撃の一つである。そこでは、あるプロセス、または、あるグループのプロセスが、システムのすべてのリソースを消費しようとし、それによって、他のプロセスの正常なオペレーションをダメにする。こうした攻撃を防ぐためには、それぞれのコンテナーに割り当てられるリソースに制限をかけることが可能でなければならない。

Page 33: ContainerとName Space Isolation

cgroup Cgroups は、 Docker がこの問題を扱うために利用

する最も重要なコンポーネントである。それは、どんな Docker コンテナーも利用できる CPU 、メモリー、ディスク IO といったリソースの量を、それぞれのコンテナーがリソースの公平な共有を得ることができ、かつ、いかなるコンテナーもすべてのリソースを消費することがないことを保証するようにコントロールする。

それは、また、それぞれのコンテナーに割り当てられたリソースに関連した上限と制約条件を設定することを可能にする。例えば、こうした制約条件の一つは、特定のコンテナーに利用可能な CPU の利用に上限を設けることである。

Page 34: ContainerとName Space Isolation

Docker and Kernel Security Systems Linux のホスト・システムのセキュリティを強固な

ものにするために、 kernel のセキュルティ・システムが存在する。それには、 Linux capabilities とLinux Security Module (LSM) が含まれる。 Linux capabilities は、それぞれのプロセスに与えられた特権を制限し、 LSM は、 Linux kernel が、異なったセキュリティ・モデルをサポートすることを可能にするフレームワークを提供する。公式の Linux kernek に統合された LSM には、 AppArmor 、 SELinux 、 Seccomp が含まれる。

Page 35: ContainerとName Space Isolation

Linux Capabilities Linux capabilities のマニュアル・ページで述べら

れているように、伝統的には、 Unix システムは、プロセスを二つのカテゴリーに分類する。(スーパー・ユーザーすなわち root に所有される)特権プロセスと、(通常のユーザーに所有される)非特権プロセスである。

kernel は、特権プロセスについては、すべてのパーミッション・チェックをスキップし、非特権プロセスについては完全なパーミッション・チェックを行う。しかしながら、 Linux kernel は、バージョン 2.2 以降は、スーパーユーザーの特権を Capabilityに分割し、 kernel は、それを、それぞれ独立に、有効にしたり無効にできる。

Page 36: ContainerとName Space Isolation

コンテナーからの root の capability の削除

Docker コンテナーは、ホスト・システムと共有した kernel 上で走る。それゆえ、そのタスクの大部分は、 kernel によってハンドルされうる。 その結果、多くの場合、コンテナーに完全な root の特権を与える必要はない。

こうして、コンテナーから root の capability の幾つかを削除しても、コンテナーの利用可能性や機能性に影響を与えることはなく、むしろ、システムのセキュリティーを効果的に改善する。例えば、システムのネットワークを修正する能力を与えるCAP_NET_ADMIN capability は、コンテナーから削除可能である。というのも、すべてのネットワークの構成は、コンテナーを起動する以前に、 Docker デーモンによって処理できるからである。

Page 37: ContainerとName Space Isolation

Docker の configuration Docker は、コンテナーが利用可能な configuration

の設定を可能にする。デフォールトでは、 Dockerは、たとえ侵入者がコンテナー内で root のアクセス権限を取得したとしても、侵入者がホスト・システムにダメージを与えるのを防ぐために、コンテナーから非常に多くの数の Linux capability を無効にしている。 次の表は、こうした container 内で無効にされている capability の一部である。

Page 38: ContainerとName Space Isolation

Container 内で制限される Capability

Page 39: ContainerとName Space Isolation

あらためて、 Linux Kernel によるNamespace Isolation を考える

Namespace による Isolation pid_namespaces user_namespacesLinux man ページ、 namespace(7) よりhttp://linuxjm.osdn.jp/html/LDP_man-pages/man7/namespaces.7.html

Page 40: ContainerとName Space Isolation

namespace とは何か? 名前空間は、 グローバルシステムリソースを抽象化

層で覆うことで、 名前空間内のプロセスに対して、 自分たちが専用の分離されたグローバルリソースを持っているかのように見せる仕組みである。 グローバルリソースへの変更は、 名前空間のメンバーである他のプロセスには見えるが、 それ以外のプロセスには見えない。 名前空間の一つの利用方法はコンテナーの実装である。

Page 41: ContainerとName Space Isolation

6 つの namespace名前空間 定数 分離対象

IPC CLONE_NEWIPC System V IPC, POSIX メッセージキュー

Network CLONE_NEWNET ネットワークデバイス、スタック、ポートなど

Mount CLONE_NEWNS マウントポイント

PID CLONE_NEWPID プロセス ID

User CLONE_NEWUSER ユーザー ID とグループ ID

UTS CLONE_NEWUTS ホスト名と NIS ドメイン名

Page 42: ContainerとName Space Isolation

linux/nsproxy.h

Page 43: ContainerとName Space Isolation

namespace API clone clone(2) システムコールは新しいプロセスを作成

する。 呼び出し時に flags 引き数で以下のリストにある CLONE_NEW*  のフラグを一つ以上指定すると、 各フラグに対応する新しい名前空間が作成され、 子プロセスはこれらの名前空間のメンバーになる。 ( このシステムコールは名前空間とは関係のない機能も多数実装している。 )

Page 44: ContainerとName Space Isolation

namespace API setns setns(2) システムコールを使うと、呼び出したプ

ロセスを既存の名前空間に参加させることができる。 参加する名前空間は、 以下で説明する /proc/[pid]/ns  ファイルのいずれか一つを参照するファイルディスクリプターを使って指定する。

Page 45: ContainerとName Space Isolation

namespace API unshare unshare(2) システムコールは、 呼び出したプロ

セスを新しい名前空間に移動する。 呼び出し時の flags 引き数に以下のリストにあるCLONE_NEW*  フラグを一つ以上指定すると、 各フラグに対応する新しい名前空間が作成され、 呼び出したプロセスがこれらの名前空間のメンバーになる。 ( このシステムコールは名前空間とは関係のない機能も多数実装している。 )

Page 46: ContainerとName Space Isolation

/proc/[pid]/ns/ ディレクトリ 各プロセスには /proc/[pid]/ns/  サブディレクトリ

があり、 このサブディレクトリには setns(2) での操作がサポートされている名前空間単位にエントリーが存在する。

一つ一つのプロセスごとに、 6 つの namespace が、対応していることに、注意。

$ ls -l /proc/$$/ns total 0 lrwxrwxrwx. 1 mtk mtk 0 Jan 14 01:20 ipc -> ipc:[4026531839] lrwxrwxrwx. 1 mtk mtk 0 Jan 14 01:20 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 mtk mtk 0 Jan 14 01:20 net -> net:[4026531956] lrwxrwxrwx. 1 mtk mtk 0 Jan 14 01:20 pid -> pid:[4026531836] lrwxrwxrwx. 1 mtk mtk 0 Jan 14 01:20 user -> user:[4026531837] lrwxrwxrwx. 1 mtk mtk 0 Jan 14 01:20 uts -> uts:[4026531838]

Page 47: ContainerとName Space Isolation

/proc/[pid]/ns/ ディレクトリ このディレクトリ内のファイルのいずれかをファイ

ルシステムの他のどこかにバインドマウント (mount(2) 参照 ) することで、 その名前空間のすべてのプロセスが終了した場合でも、 pid  で指定したプロセスの対応する名前空間を保持することができる。

このディレクトリ内のファイルのいずれか ( またはこれらのファイルのいずれかにバインドマウントされたファイル ) をオープンすると、 pid  で指定されたプロセスの対応する名前空間に対するファイルハンドルが返される。 このファイルディスクリプターがオープンされている限り、 その名前空間のすべてのプロセスが終了した場合であっても、 その名前空間は存在し続ける。 このファイルディスクリプターは setns(2) に渡すことができる。

Page 48: ContainerとName Space Isolation

IPC namespace(CLONE_NEWIPC) IPC 名前空間は、 特定の IPC リソース、すなわち、

System V IPC オブジェクト (svipc(7) 参照 ) 、(Linux 2.6.30 以降では ) POSIX メッセージキュー (mq_overview(7) 参照 ) を分離する。 これらの IPC 機構に共通の特徴は、 IPC オブジェクトがファイルシステムのパス名以外の方法で識別されるという点である。

各 IPC 名前空間はそれぞれ、 独自の System V IPC 識別子の集合と独自の POSIX メッセージキューファイルシステムを持つ。 IPC 名前空間に作成されたオブジェクトは、 その名前空間のメンバーの他のすべてのプロセスにも見えるが、 他の IPC 名前空間のプロセスには見えない。

Page 49: ContainerとName Space Isolation

Network namespace(CLONE_NEWNET) ネットワーク名前空間は、 ネットワークに関連する

システムリソースの分離を提供する。 分離されるリソースは、 ネットワークデバイス、 IPv4 と IPv6 のプロトコルスタック、 IP ルーティングテーブル、 ファイアウォール、 /proc/net  ディレクトリ、 /sys/class/net  ディレクトリ、 ( ソケットの ) ポート番号などである。

物理ネットワークデバイスは 1 つのネットワーク名前空間にのみ属すことができる。 仮想ネットワークデバイス (“veth”) ペアは、 ネットワーク名前空間間のトンネルを作成するのに使うことができるパイプ風の抽象概念で、 別の名前空間に属す物理ネットワークデバイスへのブリッジを作成するのに使用できる。

Page 50: ContainerとName Space Isolation

Network namespace による Isolation

http://goo.gl/qcTuS8

Page 51: ContainerとName Space Isolation

Mount namespace(CLONE_NEWNS) マウント名前空間はファイルシステムのマウントポ

イントの集合を分離する。 つまり、別のマウント名前空間のプロセスには別のファイルシステム階層が見えるということである。 マウント名前空間内のマウントの集合は mount(2) と umount(2) で変更される。

/proc/[pid]/mounts  ファイル (Linux 2.4.19 以降に存在 ) は、 そのプロセスのマウント名前空間で現在マウントされている全ファイルシステムの一覧を表示する。 このファイルのフォーマットは fstab(5) に記載されている。

Page 52: ContainerとName Space Isolation

Mount namespace による Isolation

http://goo.gl/qcTuS8

Page 53: ContainerとName Space Isolation

UTS namespace(CLONE_NEWUTS) UTS 名前空間は、 ホスト名と NIS ドメイン名の 2

つのシステム識別子を分離する。 これらの識別子は sethostname(2) と setdomainname(2) を使って設定でき、 uname(2), gethostname(2), getdomainname(2) を使って取得できる。

Page 55: ContainerとName Space Isolation

PID namespaces(CLONE_NEWPID) PID 名前空間はプロセス ID 番号空間を分離する。

これは、異なる PID 名前空間のプロセスは同じ PID を持つことができることを意味する。 PID 名前空間を使うことで、コンテナー内のプロセス群を中断、再開したり、 コンテナー内のプロセスの PID を保持したままコンテナーを新しいホストに移行したりするといった機能をコンテナーが提供することが可能になる。

新しい PID 名前空間の PID は、 独立したシステムであるかのように、 1 から始まる。 fork(2), vfork(2), clone(2) を呼び出すと、 その名前空間内で一意な PID でプロセスが生成される。

Page 56: ContainerとName Space Isolation

名前空間の init プロセス

新しい名前空間で作成される最初のプロセス ( すなわち、 CLONE_NEWPID  フラグで clone(2) を使って作成されたプロセスや、 CLONE_NEWPID  フラグで unshare(2) を呼び出した後のプロセスによって作成された最初のプロセス ) は PID 1 を持ち、 そのプロセスはその名前空間の “ init” プロセスとなる。

名前空間内でみなしごになった (親プロセスがいなくなった ) 子プロセスは、 init(1) ではなくこのプロセスが親プロセスになる ( ただし、 同じ PID 名前空間内のその子プロセスの先祖が、 prctl(2) の PR_SET_CHILD_SUBREAPER  コマンドを使って、 自分自身をみなしごとなった子孫のプロセスの引き取り手になっている場合はこの限りではなく ) 。

Page 57: ContainerとName Space Isolation

“init” プロセスの終了

PID 名前空間の "init" プロセスが終了すると、 カーネルはその名前空間の全プロセスを SIGKILL  シグナルで終了する。 この動作は、 PID 名前空間の正しい操作のためには "init" プロセスは不可欠であるという事実を反映したものである。 この場合、 その PID 名前空間へのそれ以降の fork(2) はエラー ENOMEM  で失敗する。 "init" プロセスが終了している PID 名前空間に新しいプロセスを作成することはできない。

Page 58: ContainerとName Space Isolation

Nested PID namespace PID 名前空間は入れ子にすることができる。 最初の

("root") PID 名前空間以外の各 PID 名前空間は親を持つ。 PID 名前空間の親は clone(2) やunshare(2) を使ってその名前空間を作成したプロセスの PID 名前空間である。 したがって、 PID 名前空間は木構造を構成し、 すべての名前空間は親を辿って行くと、最終的には root 名前空間に辿り着く。

Page 59: ContainerとName Space Isolation

http://goo.gl/qcTuS8

PID namespace の階層構造

Page 60: ContainerとName Space Isolation

“Visible” process プロセスは、所属する PID 名前空間の他のプロセス

から見える。また、 root PID 名前空間に向かう直系の先祖の各 PID 名前空間のプロセスからも見える。 この場合、「見える」とは、 あるプロセスが、 他のプロセスがプロセス ID を指定するシステムコールを使う際に操作の対象にできることを意味する。

逆に、子供 PID 名前空間のプロセスから親や先祖の名前空間のプロセスは見えない。 あるプロセスは自分自身の PID 名前空間とその子孫の名前空間のプロセスだけが見える ( 例えば、 kill(2) でシグナルを送信したり、 setpriority(2) で nice 値を設定したり、など ) 。

Page 61: ContainerとName Space Isolation

root PID namespace プロセスは、そのプロセスが見える PID 名前空間

の階層の各層においてプロセス ID を一つ持ち、 直接の先祖の名前空間を辿ることで root PID 名前空間に至ることができる。

プロセス ID に対して操作を行うシステムコールは、常に、呼び出し元プロセスの PID 名前空間で見えるプロセス ID を使って操作を行う。 getpid(2) の呼び出しでは、 常に、 プロセスが作成された名前空間に関連付けられた PID を返す。

Page 62: ContainerとName Space Isolation

namespace の親子関係

PID 名前空間内のプロセスは名前空間の外部に親プロセスを持つことができる。 例えば、その名前空間の初期プロセス ( すなわち PID 1 を持つ init(1) プロセス ) の親プロセスは必然的に別の名前空間に属すことになる。

同様に、 あるプロセスが setns(2) を使って子プロセスを PID 名前空間に参加させた場合、 子プロセスは setns(2) の呼び出し元とは異なる PID 名前空間に属す。 子プロセスで getppid(2) を呼び出すと 0 が返される。

プロセスは (setns(2) を CLONE_NEWPID  で使うなどで ) 子供の PID 名前空間に自由に入ることができるが、 逆の方向には移動できない。 つまり、 プロセスは先祖の名前空間 (親、親の親など ) に入ることはできない。 PID 名前空間の変更は一方向の操作である。

Page 63: ContainerとName Space Isolation

namespace の親子関係

別の言い方をすると、 あるプロセスがどの PID 名前空間に所属するかは、 そのプロセスが作成されたときに決定され、 それ以降は変更されることはない。 いろいろあるが、プロセス間の親子関係には、 PID 名前空間の親子関係がそのまま反映されるということだ。 プロセスの親プロセスは、同じ名前空間にいるか、もしくは直接の親 PID 名前空間にいるかのいずれかである。

Page 64: ContainerとName Space Isolation

/proc と PID 名前空間

/proc  ファイルシステムは、 /proc  のマウントを行ったプロセスの PID 名前空間で見えるプロセスだけを表示する。 たとえ、 その /proc  ファイルシステムが他の名前空間のプロセスから参照されたとしても、そうである。

新しい PID 名前空間を作成した後、 子プロセスが、自身の root ディレクトリを変更し、新しい procfs インスタンスを /proc  にマウントするのは ps(1) などのツールが正しく動作するためにも有用である。 clone(2) の flags 引き数に CLONE_NEWNS  も指定されて新しいマウント名前空間が同時に作成された場合は、 root ディレクトリを変更する必要はない。 新しい procfs インスタンスを /proc  にそのままマウントすることができる。

Page 65: ContainerとName Space Isolation

User namespaces

http://linuxjm.osdn.jp/html/LDP_man-pages/man7/user_namespaces.7.html CLONE_NEWUSER( このフラグが clone() で意味を持つようになったのは Linux 2.6.23 である。 現在の clone() の動作が取り込まれたのは Linux 3.5 であり、 ユーザー名前空間が完全に機能するようにする最後の機能が取り込まれたのは Linux 3.8 である。 )

Page 66: ContainerとName Space Isolation

User namespaces(CLONE_NEWUSER) ユーザー名前空間は、 セキュリティに関連する識別

子や属性、 特にユーザー ID やグループ ID (credentials(7) 参照 ) 、 root ディレクトリ、 キー (keyctl(2) 参照 ) 、 ケーパビリティを分離する。 プロセスのユーザー ID とグループ ID はユーザー名前空間の内部と外部で異なる場合がある。 特に、 あるプロセスがユーザー名前空間の外部では通常の非特権ユーザー ID を持つが、 同時にユーザー名前空間の内部ではユーザー ID 0 を持つという場合がある。 言い換えると、 そのプロセスはそのユーザー名前空間の内部での操作に対してすべての特権を持つが、 名前空間の外部での操作では特権を持たない。

Page 67: ContainerとName Space Isolation

Nested User namespace ユーザー名前空間は入れ子にすることができる。 つ

まり、 最初の ("root") 名前空間以外の各名前空間は親のユーザー名前空間を持ち、 0 個以上のユーザー名前空間を持つということである。 親のユーザー名前空間は、 CLONE_NEWUSER  フラグを指定して unshare(2) や clone(2) を呼び出してユーザー名前空間を作成したプロセスのユーザー名前空間である。

カーネルにより (バージョン 3.11 以降では ) ユーザー名前空間のネスト数に 32 という上限が課される。 unshare(2) や clone(2) の呼び出しでこの上限を超えてしまう場合はエラー EUSERS  で失敗する。

Page 68: ContainerとName Space Isolation

User namespace のメンバー

各プロセスは必ず 1 個のユーザー名前空間のメンバーとなる。 CLONE_NEWUSER  フラグを指定せずに fork(2) や clone(2) でプロセスを作成した場合、 そのプロセスは親プロセスと同じユーザー名前空間のメンバーとなる。 シングルスレッドのプログラムは、 変更先のユーザー名前空間で CAP_SYS_ADMIN  を持っていれば、 setns(2) を使って別のユーザー名前空間に参加することができる。 変更時に、 変更後の名前空間ですべてのケーパビリティを獲得する。

CLONE_NEWUSER  を指定して clone(2) や unshare(2) を呼び出すと、 新しいプロセス (clone(2) の場合 ) や呼び出したプロセス (unshare(2) の場合 ) がその呼び出しで作成された新しいユーザー名前空間のメンバーとなる。

Page 69: ContainerとName Space Isolation

User namespace と Capability CLONE_NEWUSER  フラグが指定された clone

(2) で作成された子プロセスは、 新しい名前空間ですべてのケーパビリティを持った状態で開始される。 同様に、 unshare(2) を使って新しいユーザー名前空間を作成したり、 setns(2) を使って既存のユーザー名前空間に参加したりしたプロセスは、 その名前空間ですべてのケーパビリティを獲得する。 一方、 そのプロセスは、親のユーザー名前空間 (clone(2) の場合 ) や直前のユーザー名前空間 (unshare(2) や setns(2) の場合 ) では、 root ユーザー (root 名前空間のユーザー ID 0 のプロセス ) により新しい名前空間の作成や参加が行われた場合であっても、 ケーパビリティを全く持たない。

Page 70: ContainerとName Space Isolation

他の namespace との関係

Linux 3.8 以降では、 非特権プロセスがユーザー名前空間を作成することができる。 また、 呼び出し元のユーザー名前空間で CAP_SYS_ADMIN ケーパビリティを持っているだけで、 マウント名前空間、 PID 名前空間、 IPC 名前空間、 ネットワーク名前空間、 UTS 名前空間を作成できる。

ユーザー名前空間以外の名前空間が作成された場合、 その名前空間は呼び出したプロセスが名前空間の作成時にメンバーであったユーザー名前空間により所有される。 ユーザー名前空間以外の名前空間における操作には、 対応するユーザー名前空間でのケーパビリティが必要である。

Page 71: ContainerとName Space Isolation

他の namespace との関係

一つの clone(2) や unshare(2) の呼び出しで CLONE_NEWUSER  が他の CLONE_NEW*  フラグと一緒に指定された場合、 そのユーザー名前空間が最初に作成されることが保証され、 子プロセス (clone(2) の場合 ) や呼び出し元 (unshare(2) の場合 ) はその呼び出しで作成される残りの名前空間で特権を持つ。 したがって、 特権を持たない呼び出し元がフラグを組み合わせて指定することができる。

Page 72: ContainerとName Space Isolation

他の namespace との関係

新しい IPC 名前空間、 マウント名前空間、 ネットワーク名前空間、 PID 名前空間、 UTS 名前空間が clone(2) や unshare(2) で作成される際、 カーネルは新しい名前空間に対して作成したプロセスのユーザー名前空間を記録する ( この関連付けは変更できない ) 。 その新しい名前空間のプロセスがその後名前空間で分離されたグローバルリソースに対して特権操作を行う場合、 カーネルが新しい名前空間に対して関連付けたユーザー名前空間でのプロセスのケーパビリティに基づいてアクセス許可のチェックが行われる。

Page 74: ContainerとName Space Isolation

Capability 権限のチェックを行う観点から見ると、伝統的な

UNIX の実装では プロセスは二つのカテゴリーに分類できる : 

特権 プロセス ( 実効ユーザー ID が 0 のプロセス。ユーザー ID 0 は スーパーユーザーや root と呼ばれる ) と 非特権 プロセス ( 実効ユーザー ID が 0 以外のプロセス ) である。

非特権プロセスでは、プロセスの資格情報 (通常は、実効 UID 、実効 GID と追加のグループリスト ) に基づく権限チェックが行われるのに対し、 特権プロセスでは全てのカーネルの権限チェックがバイパスされる。

Page 75: ContainerとName Space Isolation

Capability バージョン 2.2 以降の Linux では、 これまでスー

パーユーザーに結び付けられてきた権限を、 いくつかのグループに分割している。これらのグループはケーパビリティ (capability) と呼ばれ、グループ毎に独立に有効、無効を設定できる。 ケーパビリティはスレッド単位の属性である。

Page 76: ContainerとName Space Isolation

cgroups

cgroups (control groups) とは、プロセスグループのリソース (CPU 、メモリ、ディスク I/Oなど ) の利用を制限・隔離する Linuxカーネルの機能。“ process containers” という名称で Rohit Seth が 2006 年 9 月から開発を開始し [1]

、 2007年に cgroups と名称変更され、 2008年 1 月に Linux カーネル 2.6.24 にマージされた [2]。それ以来、多くの機能とコントローラが追加された。https://ja.wikipedia.org/wiki/Cgroups

Page 77: ContainerとName Space Isolation

cgroup とは何か? Control Groups は、タスクの集合を、集約あるい

は分割するためのメカニズムを提供する。そして、それらのタスクの将来の子供達を、特別な振る舞いを持った階層的なグループへと集約あるいは分割する。

cgroup は、タスクの集合を、一つあるいはそれ以上のサブシステムのパラメーターの集合に関連づける。

https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt

Page 78: ContainerとName Space Isolation

CPU : “Top cpuset”      /    \

  CPUSet1 CPUSet2   |    | (Professors)   (Students) さらに Top cpuset には、 (system tasks) が加わる。

Memory : Professors (50%), Students (30%), system (20%)

Disk : Professors (50%), Students (30%), system (20%)

Network : WWW browsing (20%), Network File System (60%),          others (20%)            /    \    Professors (15%) students (5%)

https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt

cgroup によるリソース管理の例

Page 79: ContainerとName Space Isolation

/sys/fs/cgroup/ # echo browser_pid >

/sys/fs/cgroup/<restype>/<userclass>/tasks

# echo pid > /sys/fs/cgroup/network/<new_class>/tasks (after some time)

# echo pid > /sys/fs/cgroup/network/<orig_class>/tasks

https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt

Page 80: ContainerとName Space Isolation

サンプル/sys/fs/cgroup/cpuset/Charlie

mount -t tmpfs cgroup_root /sys/fs/cgroup mkdir /sys/fs/cgroup/cpuset mount -t cgroup cpuset -ocpuset /sys/fs/cgroup/cpusetcd /sys/fs/cgroup/cpuset mkdir Charlie cd Charlie /bin/echo 2-3 > cpuset.cpus /bin/echo 1 > cpuset.mems /bin/echo $$ > tasks sh

https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt

Page 81: ContainerとName Space Isolation

Docker と cgroup # With the LXC driver $ docker run -d --name='lxc_test' \     --lxc-conf="lxc.cgroup.cpu.shares=50" \     busybox

# With the libcontainer driver $ docker run -d --name='libcontainer_test' \     --cpu-shares=50 \     busybox

https://goo.gl/am2B4Y

Page 82: ContainerとName Space Isolation

Docker と cgroup

Feature LXC Libcontainer

Relative CPU share -c, –cpu-shares–lxc-conf=”lxc.cgroup.cpu.shares”

Lock to a CPU core –cpuset-cpus–lxc-conf=”lxc.cgroup.cpuset.cpus”

Limit memory -m, –memory–lxc-conf=”lxc.cgroup.cpuset.mems”

https://goo.gl/am2B4Y

Page 83: ContainerとName Space Isolation

Available Subsystems in Red Hat Enterprise Linux blkio — this subsystem sets limits on input/output

access to and from block devices such as physical drives (disk, solid state, USB, etc.).

cpu — this subsystem uses the scheduler to provide cgroup tasks access to the CPU.

cpuacct — this subsystem generates automatic reports on CPU resources used by tasks in a cgroup.

cpuset — this subsystem assigns individual CPUs (on a multicore system) and memory nodes to tasks in a cgroup.

devices — this subsystem allows or denies access to devices by tasks in a cgroup.

freezer — this subsystem suspends or resumes tasks in a cgroup.

https://goo.gl/EHpRNb

Page 84: ContainerとName Space Isolation

Available Subsystems in Red Hat Enterprise Linux memory — this subsystem sets limits on memory use by

tasks in a cgroup, and generates automatic reports on memory resources used by those tasks.

net_cls — this subsystem tags network packets with a class identifier (classid) that allows the Linux traffic controller (tc) to identify packets originating from a particular cgroup task.

net_prio — this subsystem provides a way to dynamically set the priority of network traffic per network interface.

ns — the namespace subsystem

https://goo.gl/EHpRNb

Page 85: ContainerとName Space Isolation

Linux Kernel でのContainer サポートの「歴史」

Page 86: ContainerとName Space Isolation

Linux 2.4.19 (2002 年 8 月 3 日 ) Mount Namespace まず、 Linux 2.4.19 (2002 年 8 月 3 日リリース )

で、 mount の namespace が初めて登場する。 13年以上昔の話だ。ソースをダウンロードしたのだが、当時の Linux は、 tar.gz で 32M しかなかった。 CHANGES も読んでみたが、 namespace の話は、全然、登場しない。ひっそりと世に出た。

この時の namespace.h, namaspace.c は、もっぱら、 (Virtual) File System の mount, umount に関わったものだった。面白いのは、こうした役割と構成が、現バージョンの Linux の namespace,[hc]でも受け継がれているように見えること。もっとも、ここでの mount, umount は、きちんと Container用の Namespace に対応しているのだが。

Page 87: ContainerとName Space Isolation

Linux 2.4.19 namespace.cstruct vfsmount *alloc_vfsmnt(char *name)void free_vfsmnt(struct vfsmount *mnt)struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)static int check_mnt(struct vfsmount *mnt)static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd)static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root)void __mntput(struct vfsmount *mnt)static void *m_start(struct seq_file *m, loff_t *pos)static void *m_next(struct seq_file *m, void *v, loff_t *pos)static void m_stop(struct seq_file *m, void *v)static inline void mangle(struct seq_file *m, const char *s)static int show_vfsmnt(struct seq_file *m, void *v)

Page 88: ContainerとName Space Isolation

Linux 2.4.19 namespace.cint may_umount(struct vfsmount *mnt) void umount_tree( struct vfsmount *mnt)static int do_umount(struct vfsmount *mnt, int flags)asmlinkage long sys_umount(char * name, int flags)asmlinkage long sys_oldumount(char * name)static int mount_is_safe(struct nameidata *nd)static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)static int do_loopback(struct nameidata *nd, char *old_name, int recurse)static int do_remount(struct nameidata *nd,int flags, int mnt_flags,void *data)static int do_move_mount(struct nameidata *nd, char *old_name)static int do_add_mount(struct nameidata *nd, char *type, int flags,

int mnt_flags, char *name, void *data)static int copy_mount_options (const void *data, unsigned long *where)

Page 89: ContainerとName Space Isolation

Linux 2.4.19 namespace.clong do_mount(char * dev_name, char * dir_name, char *type_page,

unsigned long flags, void *data_page)int copy_namespace(int flags, struct task_struct *tsk)asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, unsigned long flags, void * data)static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd)asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)static void __init init_mount_tree(void)void __init mnt_init(unsigned long mempages)

Page 90: ContainerとName Space Isolation

2002 年当時、 Linux が対応していたハードウェア達

Page 91: ContainerとName Space Isolation

Linux 2.6.19 (2006 年 11 月 29 日 )IPC, UTS Namespace 次は、それから 4 年後の Linux 2.6.19 (2006 年 11

月 29 日リリース ) 。 IPC と UTS の namespace が追加される。これも、 9 年も前の話だ。 Android のベースになった Linux は、 2.6.23 あたりだから、それより古い。この時の、 Kernel Newbies のまとめがこれ。http://kernelnewbies.org/Linux_2_6_19 是非、読んでみてほしい。 namespace の話、見つけるの大変だから。僕は音をあげて「ページ内検索」を使った。一行だけ。ただ、 2006 年 10 月に、namespace のハンドルを、 nsproxy で束ねるというアイデアが出されて以降、活発にコミットが行われていることがわかる。 http://goo.gl/xjrSoQ

Page 92: ContainerとName Space Isolation
Page 93: ContainerとName Space Isolation
Page 94: ContainerとName Space Isolation

Linux 2.6.24 (2008 年 1 月 24 日 )PID, Network Namespace 現在の形ができたのは、 Linux 2.6.24 (2008 年 1

月 24 日リリース ) 。 PID と Network のnamespace が追加されて、 Control Group も登場する。( cgroup の起源は、ちゃんと追いかけていない) Kernel Newbies のまとめはこちら。http://kernelnewbies.org/Linux_2_6_24 目の悪い僕でもはっきりわかる。この時のおすすめ記事がこちら。“Notes from a container”  http://lwn.net/Articles/256389/ 今から、振り返ると、よくわかる記事だ。

Page 95: ContainerとName Space Isolation
Page 96: ContainerとName Space Isolation
Page 97: ContainerとName Space Isolation

時系列で見た、 Namespace Isolation 1982 年 3 月 18 日 4.2BSD chroot 2002 年 8 月 3 日 Linux 2.4.19

Mount Namespace 2006 年 11 月 29 日 Linux 2.6.19

IPC, UTS Namespace 2008 年 1 月 24 日 Linux 2.6.24

PID, Network Namespace, cgroup 2008 年 10 月 9 日 Linux 2.6.27 LXC 始まる 2009 年 3 月23日  Linux 2.6.29 LXC 2013 年 2 月 18 日  Linux 3.8 User Namespace 2013 年 3 月 13 日 Docker

Page 98: ContainerとName Space Isolation

参考資料

Page 99: ContainerとName Space Isolation

参考文献 Analysis of Docker Security

http://arxiv.org/pdf/1501.02967v1.pdf Separation Anxiety: A Tutorial for Isolating Your

System with Linux Namespaceshttp://www.toptal.com/linux/separation-anxiety-isolating-your-system-with-linux-namespaces 

PID namespaces in the 2.6.24 kernelhttp://lwn.net/Articles/259217/

Bringing new security features to Dockerhttps://opensource.com/business/14/9/security-for-docker

Page 101: ContainerとName Space Isolation

Linux Manual Page LXC

http://linux.die.net/man/7/lxc  CGROUPS

https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt