More Related Content Similar to ContainerとName Space Isolation (20) More from maruyama097 (20) ContainerとName Space Isolation2. Agenda
二つの仮想化技術 VMとContainer
Linux Kernelでの Container サポート
DockerのSecurityを考える
あらためて、Linux Kernel によるNamespace
Isolationを考える
Capability
Cgroup
Linux Kernelでの Container サポートの「歴史」
参考資料
8. VMのメリットとContainerの課題
VM上のプロセスは、Guest OSのプロセスであって、
Host OSのプロセスではない。同じホストの上で動いてい
ても、異なるVM上のプロセスは、異なるGuest OSの管
理下にあって、相互に干渉しない。
ただ、Container上のプロセスは、同時に、Host OSの
プロセス「でも」ある。同じホストの上で動いている
Container上のプロセスは、潜在的には、特権を持つ
Host OS上の他のプロセスから干渉を受ける可能性があ
る。それはセキュリティ上の危険にもなりうる。
一方で、Containerは、可能な範囲で、Host OSのリ
ソースを利用しようとする。共有しつつ隔離することは、簡
単ではない。VM型の仮想化よりContainer型の仮想化
が遅れて登場したのには、そういう理由もある。
10. Containerを支える
Linux Kernelの機能
基本的には、次の三つのLinux Kernelの機能が、
Container技術を支えている。
Capability: スレッド単位で、Container内のスー
パー・ユーザの特権を制限する。
Namespace: プロセス単位で、ホストのリソースと、
Containerのリソースを、「名前空間」で、隔離する。
Cgroup: タスク(プロセスのグループ)単位で、 CPU、
メモリ、ディスクI/Oなどのリソースの利用を制限・隔離す
る。
12. /
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
13. /
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ヶ月前)、ビル・ジョイ
がインストールおよびビルドシステムのテスト用に作成したのが起源である。」
14. /
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(白い領域)しか、見えな
くなり、その他の領域のファイルへのアクセスもできなくなり、隔離される。
16. 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によるリソース管理の例
18. Process Isolation
Process Isolationの主要な目的は、同じホスト下のコン
テナーが、プロセス管理のインターフェースを用いて、他
のコンテナーに干渉するのを防ぐこと。
Docker は、プロセスのIsolationを、コンテナー内のプ
ロセスをnamespaceでくるんで、ホストや他のコンテナー
からのパーミッションや見え方を制限することで実現して
いる。
19. PID namespace
このメカニズムは、PID namespace のサポートの上
で機能している。これは、プロセスID(数値)の空間を、ホ
ストのそれからIsolateする。 PID namespace は階層
的で、あるプロセスは、自分のnamespace内の、あるい
は、子プロセスのnamespace内の、他のプロセスのみを
見ることができる。
その結果として、新しいnamespaceが生成されて、いっ
たんあるコンテナーに割り当てられると、ホストは、新しい
PID namespace内のプロセスを見ることも影響を与える
こともできるのだが、コンテナー内のプロセスは、ホストあ
るいは他のコンテナー内で走る別のプロセスを、見ること
も何かをすることもできない。
24. copy-on-write ファイルシステム
Docker は、また、 copy-on-write ファイルシステムと
いうメカニズムを用いている。
Dockerは、コンテナーをファイルシステム・イメージに基
づいて生成するのだが、コンテナーは、自身のベースのイ
メージにコンテンツを書き込むことができる。
同一のイメージ上で複数のコンテナーが生成される時、
copy-on-write ファイルシステムは、それぞれのコンテ
ナーが、その特定のファイルシステムにコンテンツを書き
込むことを可能にする。こうして、他のコンテナーがコンテ
ナー内に変更が起きたことを見つけるようなことを防止す
る。
26. cgroup -- Device Whitelist Controller
Device Whitelist Controllerという cgroupの特徴は、
Dockerがコンテナーにアクセスを許すデバイスの集合の
制限する手段を提供する。それはまた、コンテナー内のプ
ロセスが、新しいデバイス・ノードを生成することを禁止す
る。
さらに、Dockerは、コンテナーのイメージを、nodevで
mountする。つまり、そのイメージの中で、デバイス・ノー
ドが、事前に作られていたとしても、そのイメージを利用し
たコンテナー内のプロセスは、kernelと通信するのに、そ
れを使うことはできない。
28. IPC Isolation
IPC (inter-process communication) は、 セマ
フォー、メッセージ・キュウ、共有メモリーのような、プロセ
ス間でデータを交換するためのものである。
コンテナー内で走るプロセスは、IPCのリソースのある部
分のみを利用してコミュニケーションし、他のコンテナーや
ホストのプロセスに干渉は許さないように制限されなけれ
ばならない。
29. IPC namespace
Docker は、IPC isolation を、IPC namespacesを
使うことで達成している。それは、分離したIPC
namespacesの生成を可能とする。
あるIPC namespaces内のプロセスは、他のIPC
namespacesのIPCリソースを読み書きできない。
Dockerは、それぞれのコンテナーに、IPC
namespacesを割り当て、そうすることで、コンテナー内
のプロセスを、他のコンテナー内のプロセスの干渉から
守っている。
30. Network Isolation
Network isolationは、 Man-in-the-Middle (MitM)
やARP spoofingといったネットワーク・ベースの攻撃を
予防するのに重要である。コンテナーは、盗聴されないよ
うに、また、他のコンテナーやホストのネットワーク・トラ
フィックを操作できないように設定される必要がある。
それぞれのコンテナーに対して、Dockerは、 network
namespacesを使って、独立したネットワーク・スタック
を生成する。だから、それぞれのコンテナーは、自分のIP
アドレス、IPルーティングテーブル、ネットワーク・デバイス
を持っている。このことで、コンテナーは相互に対応する
ネットワーク・インターフェースで相互作用することを可能
とする。それは、それが外部のホストと相互作用する仕方
とまったく同じである。
31. Virtual Ethernet bridge
デフォールトでは、コンテナー間の接続性は、ホストマシン
に対するのと同じように、 Virtual Ethernet bridgeに
よって与えられる。このアプローチによって、Dockerはホ
ストマシンに、docker0というvirtual ethernet bridge
を生成する。それは、自動的にネットワーク・インター
フェースにパケットを送り出す。
Dockerが新しいコンテナーを生成するとき、それはユ
ニークな名前でvirtual ethernet インターフェースを確
立し、このインターフェースをこのブリッジに接続する。こ
のインターフェースはまた、コンテナーのeth0インター
フェースに接続され、コンテナーがブリッジにパケットを送
ることを可能にする。
32. Limiting of Resources
ここでは、Dockerのデフォールトの接続性モデルは、
ARP spoofing や Mac floodingといった攻撃には弱い
ことを注意しておこう。なぜなら、ブリッジは、送られてきた
パケットすべてをフィルタリングなしでフォワードするから
である。
Denial-of-Service (DoS) は、マルチ・テナント・システ
ムに対する最も一般的な攻撃の一つである。そこでは、あ
るプロセス、または、あるグループのプロセスが、システム
のすべてのリソースを消費しようとし、それによって、他の
プロセスの正常なオペレーションをダメにする。こうした攻
撃を防ぐためには、それぞれのコンテナーに割り当てられ
るリソースに制限をかけることが可能でなければならない。
34. Docker and Kernel Security
Systems
Linuxのホスト・システムのセキュリティを強固なものにす
るために、kernelのセキュルティ・システムが存在する。
それには、 Linux capabilitiesとLinux Security
Module (LSM)が含まれる。 Linux capabilitiesは、そ
れぞれのプロセスに与えられた特権を制限し、LSMは、
Linux kernelが、異なったセキュリティ・モデルをサポー
トすることを可能にするフレームワークを提供する。公式
のLinux kernekに統合されたLSMには、
AppArmor 、SELinux、Seccompが含まれる。
35. Linux Capabilities
Linux capabilitiesのマニュアル・ページで述べられてい
るように、伝統的には、Unixシステムは、プロセスを二つ
のカテゴリーに分類する。(スーパー・ユーザーすなわち
rootに所有される)特権プロセスと、(通常のユーザーに
所有される)非特権プロセスである。
kernelは、特権プロセスについては、すべてのパーミッ
ション・チェックをスキップし、非特権プロセスについては
完全なパーミッション・チェックを行う。しかしながら、
Linux kernelは、バージョン 2.2以降は、スーパーユー
ザーの特権をCapabilityに分割し、kernelは、それを、
それぞれ独立に、有効にしたり無効にできる。
39. あらためて、Linux Kernel による
Namespace Isolationを考える
NamespaceによるIsolation
pid_namespaces
user_namespaces
Linux man ページ、namespace(7)より
http://linuxjm.osdn.jp/html/LDP_man-
pages/man7/namespaces.7.html
41. 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 ドメイン名
43. namespace API clone
clone(2) システムコールは新しいプロセスを作成する。
呼び出し時に flags 引き数で以下のリストにあ
る CLONE_NEW* のフラグを一つ以上指定すると、
各フラグに対応する新しい名前空間が作成され、 子プロ
セスはこれらの名前空間のメンバーになる。 (このシステ
ムコールは名前空間とは関係のない機能も多数実装して
いる。)
44. namespace API setns
setns(2) システムコールを使うと、呼び出したプロセス
を既存の名前空間に参加させることができる。 参加する
名前空間は、 以下で説明する/proc/[pid]/ns ファイル
のいずれか一つを参照するファイルディスクリプターを
使って指定する。
45. namespace API unshare
unshare(2) システムコールは、 呼び出したプロセスを
新しい名前空間に移動する。 呼び出し時の flags 引き
数に以下のリストにあるCLONE_NEW* フラグを一つ
以上指定すると、 各フラグに対応する新しい名前空間が
作成され、 呼び出したプロセスがこれらの名前空間のメ
ンバーになる。 (このシステムコールは名前空間とは関係
のない機能も多数実装している。)
46. /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]
47. /proc/[pid]/ns/ ディレクトリ
このディレクトリ内のファイルのいずれかをファイルシステ
ムの他のどこかにバインドマウント (mount(2) 参照)
することで、 その名前空間のすべてのプロセスが終了し
た場合でも、 pid で指定したプロセスの対応する名前空
間を保持することができる。
このディレクトリ内のファイルのいずれか (またはこれらの
ファイルのいずれかにバインドマウントされたファイル) を
オープンすると、 pid で指定されたプロセスの対応する
名前空間に対するファイルハンドルが返される。 このファ
イルディスクリプターがオープンされている限り、 その名
前空間のすべてのプロセスが終了した場合であっても、
その名前空間は存在し続ける。 このファイルディスクリプ
ターは setns(2) に渡すことができる。
48. 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 名前空間のプロセスには見え
ない。
49. Network namespace
(CLONE_NEWNET)
ネットワーク名前空間は、 ネットワークに関連するシステ
ムリソースの分離を提供する。 分離されるリソースは、
ネットワークデバイス、 IPv4 と IPv6 のプロトコルスタッ
ク、 IP ルーティングテーブル、 ファイアウォー
ル、 /proc/net ディレクトリ、 /sys/class/net ディレク
トリ、 (ソケットの) ポート番号などである。
物理ネットワークデバイスは 1 つのネットワーク名前空間
にのみ属すことができる。 仮想ネットワークデバイス
(“veth”) ペアは、 ネットワーク名前空間間のトンネルを
作成するのに使うことができるパイプ風の抽象概念で、
別の名前空間に属す物理ネットワークデバイスへのブリッ
ジを作成するのに使用できる。
53. UTS namespace
(CLONE_NEWUTS)
UTS 名前空間は、 ホスト名と NIS ドメイン名の 2 つの
システム識別子を分離する。 これらの識別子
は sethostname(2) と setdomainname(2) を
使って設定で
き、 uname(2), gethostname(2), getdomain
name(2) を使って取得できる。
55. PID namespaces
(CLONE_NEWPID)
PID 名前空間はプロセス ID 番号空間を分離する。 こ
れは、異なる PID 名前空間のプロセスは同じ PID を持
つことができることを意味する。 PID 名前空間を使うこと
で、コンテナー内のプロセス群を中断、再開したり、 コン
テナー内のプロセスの PID を保持したままコンテナーを
新しいホストに移行したりするといった機能をコンテナー
が提供することが可能になる。
新しい PID 名前空間の PID は、 独立したシステムであ
るかのように、 1 から始ま
る。 fork(2), vfork(2), clone(2) を呼び出すと、 そ
の名前空間内で一意な PID でプロセスが生成される。
56. 名前空間の init プロセス
新しい名前空間で作成される最初のプロセス (すなわち、
CLONE_NEWPID フラグで clone(2) を使って作成
されたプロセスや、 CLONE_NEWPID フラグ
で unshare(2) を呼び出した後のプロセスによって作
成された最初のプロセス) は PID 1 を持ち、 そのプロセ
スはその名前空間の “init” プロセスとなる。
名前空間内でみなしごになった (親プロセスがいなくなっ
た) 子プロセスは、 init(1) ではなくこのプロセスが親プ
ロセスになる (ただし、 同じ PID 名前空間内のその子プ
ロセスの先祖が、 prctl(2)
の PR_SET_CHILD_SUBREAPER コマンドを使っ
て、 自分自身をみなしごとなった子孫のプロセスの引き
取り手になっている場合はこの限りではなく)。
57. “init”プロセスの終了
PID 名前空間の "init" プロセスが終了すると、 カーネ
ルはその名前空間の全プロセスを SIGKILL シグナル
で終了する。 この動作は、 PID 名前空間の正しい操作
のためには "init" プロセスは不可欠であるという事実を
反映したものである。 この場合、 その PID 名前空間へ
のそれ以降の fork(2) はエラーENOMEM で失敗す
る。 "init" プロセスが終了している PID 名前空間に新し
いプロセスを作成することはできない。
58. Nested PID namespace
PID 名前空間は入れ子にすることができる。 最初の
("root") PID 名前空間以外の各 PID 名前空間は親を
持つ。 PID 名前空間の親は clone(2) や
unshare(2) を使ってその名前空間を作成したプロセス
の PID 名前空間である。 したがって、 PID 名前空間は
木構造を構成し、 すべての名前空間は親を辿って行くと、
最終的には root 名前空間に辿り着く。
60. “Visible” process
プロセスは、所属する PID 名前空間の他のプロセスから
見える。また、 root PID 名前空間に向かう直系の先祖
の各 PID 名前空間のプロセスからも見える。 この場合、
「見える」とは、 あるプロセスが、 他のプロセスがプロセス
ID を指定するシステムコールを使う際に操作の対象にで
きることを意味する。
逆に、子供 PID 名前空間のプロセスから親や先祖の名
前空間のプロセスは見えない。 あるプロセスは自分自身
の PID 名前空間とその子孫の名前空間のプロセスだけ
が見える (例えば、kill(2) でシグナルを送信した
り、 setpriority(2) で nice 値を設定したり、など)。
61. root PID namespace
プロセスは、そのプロセスが見える PID 名前空間の階層
の各層においてプロセス ID を一つ持ち、 直接の先祖の
名前空間を辿ることで root PID 名前空間に至ることが
できる。
プロセス ID に対して操作を行うシステムコールは、常に、
呼び出し元プロセスの PID 名前空間で見えるプロセス
ID を使って操作を行う。 getpid(2) の呼び出しでは、
常に、 プロセスが作成された名前空間に関連付けられた
PID を返す。
62. namespaceの親子関係
PID 名前空間内のプロセスは名前空間の外部に親プロセス
を持つことができる。 例えば、その名前空間の初期プロセス
(すなわち PID 1 を持つ init(1) プロセス) の親プロセスは
必然的に別の名前空間に属すことになる。
同様に、 あるプロセスが setns(2) を使って子プロセスを
PID 名前空間に参加させた場合、 子プロセスは setns(2)
の呼び出し元とは異なる PID 名前空間に属す。 子プロセス
で getppid(2) を呼び出すと 0 が返される。
プロセスは (setns(2) を CLONE_NEWPID で使うなど
で) 子供の PID 名前空間に自由に入ることができるが、 逆
の方向には移動できない。 つまり、 プロセスは先祖の名前
空間 (親、親の親など) に入ることはできない。 PID 名前空
間の変更は一方向の操作である。
63. namespaceの親子関係
別の言い方をすると、 あるプロセスがどの PID 名前空
間に所属するかは、 そのプロセスが作成されたときに決
定され、 それ以降は変更されることはない。 いろいろあ
るが、プロセス間の親子関係には、PID 名前空間の親子
関係がそのまま反映されるということだ。 プロセスの親プ
ロセスは、同じ名前空間にいるか、もしくは直接の親 PID
名前空間にいるかのいずれかである。
64. /proc と PID 名前空間
/proc ファイルシステムは、/proc のマウントを行ったプ
ロセスの PID 名前空間で見えるプロセスだけを表示する。
たとえ、 その /proc ファイルシステムが他の名前空間の
プロセスから参照されたとしても、そうである。
新しい PID 名前空間を作成した後、 子プロセスが、自身
の root ディレクトリを変更し、新しい procfs インスタン
スを /proc にマウントするのは ps(1) などのツールが
正しく動作するためにも有用である。 clone(2)
の flags 引き数に CLONE_NEWNS も指定されて新
しいマウント名前空間が同時に作成された場合は、 root
ディレクトリを変更する必要はない。 新しい procfs イン
スタンスを /proc にそのままマウントすることができる。
66. User namespaces
(CLONE_NEWUSER)
ユーザー名前空間は、 セキュリティに関連する識別子や
属性、 特にユーザー ID やグループ ID
(credentials(7) 参照)、 root ディレクトリ、 キー
(keyctl(2) 参照)、 ケーパビリティを分離する。 プロセ
スのユーザー ID とグループ ID はユーザー名前空間の
内部と外部で異なる場合がある。 特に、 あるプロセスが
ユーザー名前空間の外部では通常の非特権ユーザー
ID を持つが、 同時にユーザー名前空間の内部ではユー
ザー ID 0 を持つという場合がある。 言い換えると、 そ
のプロセスはそのユーザー名前空間の内部での操作に
対してすべての特権を持つが、 名前空間の外部での操
作では特権を持たない。
67. Nested User namespace
ユーザー名前空間は入れ子にすることができる。 つまり、
最初の ("root") 名前空間以外の各名前空間は親の
ユーザー名前空間を持ち、 0 個以上のユーザー名前空
間を持つということである。 親のユーザー名前空間
は、 CLONE_NEWUSER フラグを指定し
て unshare(2) や clone(2) を呼び出してユーザー
名前空間を作成したプロセスのユーザー名前空間である。
カーネルにより (バージョン 3.11 以降では) ユーザー名
前空間のネスト数に 32 という上限が課され
る。 unshare(2) や clone(2) の呼び出しでこの上限
を超えてしまう場合はエラー EUSERS で失敗する。
68. User namespaceのメンバー
各プロセスは必ず 1 個のユーザー名前空間のメンバーとな
る。 CLONE_NEWUSER フラグを指定せずに fork(2)
や clone(2) でプロセスを作成した場合、 そのプロセスは
親プロセスと同じユーザー名前空間のメンバーとなる。 シン
グルスレッドのプログラムは、 変更先のユーザー名前空間で
CAP_SYS_ADMIN を持っていれば、 setns(2) を使っ
て別のユーザー名前空間に参加することができる。 変更時
に、 変更後の名前空間ですべてのケーパビリティを獲得する。
CLONE_NEWUSER を指定して clone(2)
や unshare(2) を呼び出すと、 新しいプロセス
(clone(2) の場合) や呼び出したプロセス (unshare(2)
の場合) がその呼び出しで作成された新しいユーザー名前空
間のメンバーとなる。
69. User namespaceとCapability
CLONE_NEWUSER フラグが指定された clone(2)
で作成された子プロセスは、 新しい名前空間ですべての
ケーパビリティを持った状態で開始される。 同様
に、 unshare(2) を使って新しいユーザー名前空間を
作成したり、 setns(2) を使って既存のユーザー名前空
間に参加したりしたプロセスは、 その名前空間ですべて
のケーパビリティを獲得する。 一方、 そのプロセスは、親
のユーザー名前空間 (clone(2) の場合) や直前の
ユーザー名前空間 (unshare(2) や setns(2) の場
合) では、 root ユーザー (root 名前空間のユーザー
ID 0 のプロセス) により新しい名前空間の作成や参加
が行われた場合であっても、 ケーパビリティを全く持たな
い。
70. 他のnamespaceとの関係
Linux 3.8 以降では、 非特権プロセスがユーザー名前
空間を作成することができる。 また、 呼び出し元のユー
ザー名前空間で CAP_SYS_ADMIN ケーパビリティ
を持っているだけで、 マウント名前空間、 PID 名前空間、
IPC 名前空間、 ネットワーク名前空間、 UTS 名前空間
を作成できる。
ユーザー名前空間以外の名前空間が作成された場合、
その名前空間は呼び出したプロセスが名前空間の作成
時にメンバーであったユーザー名前空間により所有され
る。 ユーザー名前空間以外の名前空間における操作に
は、 対応するユーザー名前空間でのケーパビリティが必
要である。
71. 他のnamespaceとの関係
一つの clone(2) や unshare(2) の呼び出し
で CLONE_NEWUSER が他の CLONE_NEW* フ
ラグと一緒に指定された場合、 そのユーザー名前空間が
最初に作成されることが保証され、 子プロセス
(clone(2) の場合) や呼び出し元 (unshare(2) の
場合) はその呼び出しで作成される残りの名前空間で特
権を持つ。 したがって、 特権を持たない呼び出し元がフ
ラグを組み合わせて指定することができる。
72. 他のnamespaceとの関係
新しい IPC 名前空間、 マウント名前空間、 ネットワーク
名前空間、 PID 名前空間、 UTS 名前空間
が clone(2) や unshare(2) で作成される際、 カー
ネルは新しい名前空間に対して作成したプロセスのユー
ザー名前空間を記録する (この関連付けは変更できな
い)。 その新しい名前空間のプロセスがその後名前空間
で分離されたグローバルリソースに対して特権操作を行う
場合、 カーネルが新しい名前空間に対して関連付けた
ユーザー名前空間でのプロセスのケーパビリティに基づ
いてアクセス許可のチェックが行われる。
74. Capability
権限のチェックを行う観点から見ると、伝統的な UNIX の
実装では プロセスは二つのカテゴリーに分類できる:
特権 プロセス (実効ユーザーID が 0 のプロセス。ユー
ザーID 0 は スーパーユーザーや root と呼ばれる)
と 非特権 プロセス (実効ユーザーID が 0 以外のプロ
セス) である。
非特権プロセスでは、プロセスの資格情報 (通常は、実
効UID 、実効GID と追加のグループリスト) に基づく権
限チェックが行われるのに対し、 特権プロセスでは全て
のカーネルの権限チェックがバイパスされる。
75. Capability
バージョン 2.2 以降の Linux では、 これまでスーパー
ユーザーに結び付けられてきた権限を、 いくつかのグ
ループに分割している。これらのグループはケーパビリ
ティ(capability) と呼ばれ、グループ毎に独立に有効、
無効を設定できる。 ケーパビリティはスレッド単位の属性
である。
76. 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
77. cgroupとは何か?
Control Groups は、タスクの集合を、集約あるいは分
割するためのメカニズムを提供する。そして、それらのタ
スクの将来の子供達を、特別な振る舞いを持った階層的
なグループへと集約あるいは分割する。
cgroupは、タスクの集合を、一つあるいはそれ以上のサ
ブシステムのパラメーターの集合に関連づける。
https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt
78. 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によるリソース管理の例
79. /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
80. サンプル
/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/cpuset
cd /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
81. 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
82. Dockerとcgroup
Feature LXC Libcontainer
Relative CPU share -c, –cpu-shares
–lxc-
conf=”lxc.cgroup.cp
u.shares”
Lock to a CPU core –cpuset-cpus
–lxc-
conf=”lxc.cgroup.cp
uset.cpus”
Limit memory -m, –memory
–lxc-
conf=”lxc.cgroup.cp
uset.mems”
https://goo.gl/am2B4Y
83. 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
84. 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
86. 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に対
応しているのだが。
87. Linux 2.4.19 namespace.c
struct 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)
88. Linux 2.4.19 namespace.c
int 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)
89. Linux 2.4.19 namespace.c
long 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)
91. 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
94. 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/
今から、振り返ると、よくわかる記事だ。
97. 時系列で見た、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
99. 参考文献
Analysis of Docker Security
http://arxiv.org/pdf/1501.02967v1.pdf
Separation Anxiety: A Tutorial for Isolating
Your System with Linux Namespaces
http://www.toptal.com/linux/separation-anxiety-
isolating-your-system-with-linux-namespaces
PID namespaces in the 2.6.24 kernel
http://lwn.net/Articles/259217/
Bringing new security features to Docker
https://opensource.com/business/14/9/security-for-
docker
100. Linux Manual Page
Namespaces
http://linuxjm.osdn.jp/html/LDP_man-
pages/man7/namespaces.7.html
PID namespaces
http://linuxjm.osdn.jp/html/LDP_man-
pages/man7/pid_namespaces.7.html
User namespaces
http://linuxjm.osdn.jp/html/LDP_man-
pages/man7/user_namespaces.7.html
Capability
http://linuxjm.osdn.jp/html/LDP_man-
pages/man7/capabilities.7.html
101. Linux Manual Page
LXC
http://linux.die.net/man/7/lxc
CGROUPS
https://www.kernel.org/doc/Documentation/cgroups/cgr
oups.txt