講演資料
講義資料スライドの表紙です。スライド画像、または下の要約文中の青いページ番号リンクをクリックすると、別のタブで無駄なノイズのない、純粋なPDFビューア画面が起動し、指定されたページへ直接ジャンプして快適に閲覧できます。
全体概要
このセミナーは、「Containerはいかにして、同一ホスト上のプロセスを安全に隔離するのか」という根本的な問いを中心に据え、LinuxカーネルのNamespace Isolationメカニズムを徹底的に解剖した講義です。
コンテナ技術の隆盛を支えているのは、DockerやLXCといったソフトウェアレイヤーではなく、そのはるか以前からLinuxカーネルに蓄積されてきた低レベルの隔離機能群です。本セミナーはその事実を正面から見据え、「仮想マシン(VM)との本質的な違い」から議論を出発させます。VMはGuest OSを完全に独立させることでプロセスを隔離しますが、コンテナはHost OSのカーネルを共有しながら隔離を実現するという、根本的に困難な課題に挑んでいます。その答えが、Namespace・Capability・Cgroupという三本柱です [p.10]。
歴史的視点も本講義の大きな特徴です。Namespaceの原型とも言えるchrootは1982年にBill Joyが実装し [p.13]、Mount NamespaceがLinux 2.4.19(2002年)に静かに登場してから、IPC・UTS(2006年)、PID・Network・cgroup(2008年)、そしてUser Namespace(2013年)へと、実に30年以上かけて積み重ねられてきた技術的蓄積が、Dockerの誕生(2013年3月)を可能にしたことが年表として示されます [p.97]。
Dockerのセキュリティ実装を「Analysis of Docker Security」論文に基づいて丁寧に解説した後、Linuxマニュアルページに即してNamespaceのAPIと各種名前空間の仕様を精密にトレースし、最後にCapabilityとCgroupの詳細へと議論が展開されます。本セミナーは、コンテナ技術を「使う」レベルから「カーネルの視点で理解する」レベルへと受講者を引き上げることを目指した、高度かつ体系的な技術講義です。
講義のロードマップ
■ Part 1: 二つの仮想化技術 — VMとContainer
- この部の核心:
HypervisorベースのVMとContainerという二つの仮想化パラダイムを対比し、Containerが「Guest OSを持たずにHost OSのリソースを共有しながら隔離する」という本質的な困難を明確化します。軽量・高速・統合容易というContainerの優位性の裏に潜る「共有しつつ隔離する」という技術的課題が、以降の議論全体の動機となります [p.3], [p.4]。
- 論理展開:
- VMはHypervisor(Type 2)上でGuest OSを独立起動し、プロセスをHost OSから完全隔離する [p.4]。
- ContainerはHost OS上に直接起動し、bin/libも可能な範囲で共有する。Dockerのアーキテクチャ図で両者の構造的差異が示される [p.5], [p.6]。
- ContainerプロセスはHost OSのプロセス「でもある」ため、特権を持つHost OS上の他プロセスから干渉を受ける可能性がある [p.8]。
- VM型より Container型の仮想化が遅れて登場したのは、「共有しつつ隔離すること」が技術的に困難だったためである [p.8]。
■ Part 2: Linux KernelでのContainer サポート概観
- この部の核心:
Containerを支える三つのLinuxカーネル機能(Capability・Namespace・Cgroup)の役割と守備範囲を鳥瞰します。それぞれがどのレベルでどのリソースを隔離・制限するのかを最初に整理し、以降の詳細解説への地図を提供します [p.10]。
- 論理展開:
- Capability: スレッド単位でスーパーユーザーの特権を細分化・制限する [p.10]。
- Namespace: プロセス単位でホストのリソースを「名前空間」によって隔離する [p.10]。
- Cgroup: タスク(プロセスグループ)単位でCPU・メモリ・ディスクI/Oの利用を制限・隔離する [p.10]。
- chrootをFilesystem Isolationの原型として位置づけ、`chroot /home`実行によってプロセスが新ルート以下しか見えなくなる仕組みを図示する [p.12], [p.13], [p.14]。
- Container内で無効化されるCapabilityの一覧(CAP_SYS_MODULE、CAP_SYS_RAWIO、CAP_SYS_ADMINなど15項目)が示される [p.11]。
- cgroupによるCPU・メモリ・ディスク・ネットワークリソースの階層的管理の具体例(Professors/Students/System tasks)が示される [p.16]。
■ Part 3: DockerのSecurityを考える
- この部の核心:
「Analysis of Docker Security」論文に基づき、DockerがLinuxカーネルのNamespace・Capability・Cgroupをどのように組み合わせてセキュリティを実現しているかを、Process・Filesystem・Device・IPC・Network Isolationの各観点から体系的に解説します [p.17]。
- 論理展開:
- Process Isolation: PID namespaceによりContainer内プロセスはHost・他Containerのプロセスを見えなくし、攻撃困難にする。Container内ではPID 1(init相当)が終了すると全プロセスがSIGKILLで終了する [p.18], [p.19], [p.20]。
- Filesystem Isolation: mount namespacesによりFilesystemの階層ビューをContainer単位に分離する。ただし`/sys`・`/proc/sys`など一部はnamespaceを持たず、CAP_SYS_ADMINのcapabilityを削除することでremountを禁止する [p.21], [p.22], [p.23]。
- copy-on-writeファイルシステム: 同一イメージから複数Container起動時に、各Containerが独立した書き込み領域を持つことで他Containerに変更が見えないようにする [p.24]。
- Device Isolation: cgroupのDevice Whitelist Controllerで許可デバイスを制限し、Containerイメージをnodevでmountすることでデバイスノードの悪用を防ぐ [p.25], [p.26], [p.27]。
- IPC Isolation: IPC namespacesにより各ContainerのSystem V IPC・POSIXメッセージキューを完全分離する [p.28], [p.29]。
- Network Isolation: network namespacesにより各ContainerがIPアドレス・ルーティングテーブル・ネットワークデバイスを独立して保有する。ただしデフォルトのVirtual Ethernet bridgeはARP spoofing・MAC floodingに弱い点が指摘される [p.30], [p.31], [p.32]。
- Cgroup for DoS防止: cgroupによりCPU・メモリ・ディスクIOの上限設定が可能となり、一Container全リソース占有を防止する [p.33]。
- Linux Capabilities&LSM: AppArmor・SELinux・Seccompを含むLinux Security Moduleフレームワークとの連携が示される [p.34], [p.35], [p.36], [p.37], [p.38]。
■ Part 4: あらためてLinux KernelによるNamespace Isolationを考える
- この部の核心:
Linuxマニュアルページ(namespaces(7)・pid_namespaces(7)・user_namespaces(7))に忠実に従い、6種類のNamespaceの仕様・APIの正確な動作・階層構造・親子関係を精密に解説します。「名前空間は、グローバルシステムリソースを抽象化層で覆い、その名前空間内のプロセスに専用の分離されたリソースがあるように見せる仕組みである」という定義が核心です [p.40]。
- 論理展開:
- 6種のNamespace一覧: IPC(CLONE_NEWIPC)・Network(CLONE_NEWNET)・Mount(CLONE_NEWNS)・PID(CLONE_NEWPID)・User(CLONE_NEWUSER)・UTS(CLONE_NEWUTS) [p.41]。
- Namespace API: `clone(2)`で新Namespace生成・`setns(2)`で既存Namespace参加・`unshare(2)`で呼び出しプロセスを新Namespaceへ移動する三つのシステムコールが示される [p.43], [p.44], [p.45]。
- `/proc/[pid]/ns/`ディレクトリ: 各プロセスごとに6つのNamespaceがシンボリックリンクとして存在し、bind mountやファイルディスクリプタ保持でNamespaceを存続させる仕組みが解説される [p.46], [p.47]。
- 各Namespaceの詳細: IPC(System V IPC・POSIXメッセージキューの分離)[p.48]、Network(ネットワークデバイス・スタック・ポートの分離、vethペアによる橋渡し)[p.49]、Mount(マウントポイント集合の分離)[p.51]、UTS(ホスト名・NISドメイン名の分離)[p.53] が順次解説される。
- PID Namespace詳細: 新Namespaceの最初のプロセスがPID 1(init相当)となり、終了時にSIGKILLで全プロセスを終了させる。PID Namespaceは入れ子可能で木構造を成し、親Namespaceからは子を見えるが逆は不可という一方向性が重要 [p.55], [p.56], [p.57], [p.58], [p.60], [p.61], [p.62], [p.63]。
- `/proc`とPID Namespace: `/proc`はmountしたプロセスのPID Namespace内のプロセスのみを表示する [p.64]。
- User Namespace詳細: Linux 3.8で完成。UID/GID・Capability・rootディレクトリを分離し、Namespace外では非特権ユーザーでも内部ではUID 0として全Capabilityを持てる。ネストは最大32階層 [p.65], [p.66], [p.67], [p.68], [p.69], [p.70], [p.71], [p.72]。
■ Part 5: Capability
- この部の核心:
従来UNIXの「特権プロセス vs 非特権プロセス」という二項対立を、Linux 2.2以降が「Capability」という細粒度の権限分割に進化させた意義を解説します。Capabilityはスレッド単位の属性であり、これによってContainerのroot権限を安全に制限する基盤が形成されます [p.73], [p.74], [p.75]。
- 論理展開:
- Linux 2.2以降、スーパーユーザーの権限をCAP_CHOWN・CAP_NET_ADMIN・CAP_SYS_ADMINなど独立したCapabilityグループに分割した [p.75]。
- 特権プロセスはカーネルの全権限チェックをバイパスするが、Capabilityを使えば必要な特権のみを付与可能となる [p.74]。
- DockerはContainerからCAP_SYS_MODULE・CAP_SYS_RAWIO・CAP_NET_ADMINなど多数のCapabilityを無効化し、侵入者がroot権限を取得してもHost破壊を防ぐ設計としている [p.37], [p.38]。
■ Part 6: Cgroup
- この部の核心:
cgroups(control groups)は、プロセスグループのリソース利用を制限・隔離するLinuxカーネル機能であり、2006年にRohit SethがGoogleで開発を開始し、2008年にLinux 2.6.24にマージされました。DoS攻撃への防御線としてContainerごとのリソース上限設定を可能にする重要な機構です [p.76], [p.77]。
- 論理展開:
- cgroupは「タスクの集合を一つ以上のサブシステムのパラメーター集合に関連づける」仕組みである [p.77]。
- `/sys/fs/cgroup/`以下にファイルシステムとしてマウントし、tasksファイルへのPID書き込みでプロセスをグループに割り当てる [p.79], [p.80]。
- DockerはLXCドライバーでは`
lxc-conf="lxc.cgroup.cpu.shares=50"`、libcontainerドライバーでは`
cpu-shares=50`によりcgroupを設定する [p.81], [p.82]。 - Red Hat Enterprise LinuxにおけるサブシステムはblkIO・cpu・cpuacct・cpuset・devices・freezer・memory・net_cls・net_prio・nsが存在する [p.83], [p.84]。
■ Part 7: Linux KernelでのContainer サポートの「歴史」
- この部の核心:
Namespace Isolationの技術史を年表として俯瞰し、1982年のchrootから2013年のDocker誕生まで、約30年にわたる技術蓄積がいかにしてコンテナ技術を可能にしたかを示します。技術は一夜にして生まれるのではなく、Linuxカーネルへの地道なコミットの積み重ねであることが明示されます [p.97]。
- 論理展開:
- Linux 2.4.19(2002年8月): Mount Namespaceがひっそりと登場。`namespace.c`はVFSのmount/umount操作を中心とした約800行のファイルで、現在の`namespace.c`の構造的原型となる [p.86], [p.87], [p.88], [p.89]。
- Linux 2.6.19(2006年11月): IPC・UTS Namespaceが追加。2006年10月にnsproxyでNamespaceハンドルを束ねるアイデアが出されて以降、コミットが活発化する [p.91], [p.92], [p.93]。
- Linux 2.6.24(2008年1月): PID・Network Namespaceとcgroupが一挙に追加。Kernel Newbiesが「重要事項」として明示的に記載するほどの節目となる [p.94], [p.95]。
- Linux 3.8(2013年2月): User Namespace supportが完成。非特権プロセスがNamespaceを作成できるようになる [p.96]。
- Docker(2013年3月): Linux 3.8完成の1ヶ月後にDockerが登場。すべての技術蓄積の上に成立している [p.97]。
