マイクロVM(Firecracker・gVisor)の隔離設計
マルチテナントで信頼できないコードを安全に走らせたい。コンテナの弱い隔離を、軽量VMのFirecrackerとユーザー空間カーネルのgVisorがどう補い、攻撃面と性能をどう天秤にかけるかを原理で押さえます。
- 1.コンテナはホストカーネルを共有するため、共有カーネルが攻撃面になる。マイクロVMはこの境界を別の隔離壁で置き換える。
- 2.Firecrackerは数十個のデバイスだけを持つ最小VMM(KVM上)で、ハードウェア仮想化の壁を使い、起動を約125ms・メモリ常駐を数MBに抑える。
- 3.gVisorはVMを使わず、ゲストのシステムコールをseccomp-bpf等で横取りしてSentryというユーザー空間カーネルで再実装し、ホストカーネルへの直接到達面を絞る。
なぜコンテナの隔離では足りないのか
コンテナは namespace・cgroup・capability・seccomp を組み合わせた軽量な隔離ですが、決定的な弱点があります。すべてのコンテナがホストのカーネルを共有する点です。コンテナ内のプロセスが発行するシステムコールは、最終的にホストの単一のカーネルが処理します。つまりカーネルに脆弱性があれば、namespace で見える範囲を区切っていても、そのバグを突いて隔離の壁を越えられます。
問題の本質は攻撃面(attack surface)の広さです。Linux のシステムコールは 350 を超え、各々が複雑なカーネルコードに繋がります。seccomp で呼べる呼び出しを絞っても、許可した数十個の窓口の奥はやはり巨大な共有カーネルです。マルチテナント環境(他人のコードを同じホストで走らせるサーバーレスや CI など)では、この共有カーネルが許容しがたいリスクになります。マイクロVM/サンドボックスは、この「共有カーネルへの直接到達」を別の隔離機構で置き換える技術です。
本稿は方向性の異なる2つを比較します。Firecracker はハードウェア仮想化で本物の境界を引き、ゲスト専用のカーネルを走らせる「軽量VM」路線。gVisor はVMを使わず、ゲストのシステムコールを横取りしてユーザー空間で再実装する「ユーザー空間カーネル」路線です。どちらもコンテナ並みの軽さとVM並みの隔離を狙いますが、攻撃面の形が違います。
Firecracker:デバイスを削ぎ落とした最小VMM
Firecracker は AWS Lambda/Fargate を支える VMM(Virtual Machine Monitor)で、KVM の上に乗ります。KVM が CPU/メモリ仮想化(VM entry/exit、EPT/NPT による二段アドレス変換)を担う点は QEMU と同じですが、Firecracker は QEMU を置き換える、極端に小さい VMM です。
設計の核はデバイスモデルの最小化です。汎用 VMM の QEMU が PCI バス・多種のNIC・USB・VGA など膨大なデバイスをエミュレートするのに対し、Firecracker はvirtio準拠の最小限だけを持ちます。
| 観点 | 汎用VMM(QEMU) | Firecracker |
|---|---|---|
| デバイス数 | 数百種を網羅 | virtio-net/block/vsock等の数個に限定 |
| レガシ機構 | PCI・ACPI・BIOS等を完備 | PCIもBIOSも持たずカーネル直ブート |
| コード規模 | 大(攻撃面が広い) | 小(Rust製で約数万行) |
| 起動時間 | 秒オーダ | 約125ms |
| メモリ常駐(VMM) | 数十MB以上 | 1VMあたり約5MB未満 |
この削減が効くのは二重の意味です。第一に起動の速さとメモリ密度。PCI 列挙も BIOS も省き、カーネルを直接ロードして起動するため、1ホストに数千のマイクロVMを詰められます。第二にVMM自体の攻撃面。ゲストがVMから抜け出す(VM escape)には、まず VMM のデバイスエミュレーションコードのバグを突く必要があります。デバイスが数個しかなく実装が Rust で小さければ、その的が小さくなります。さらに Firecracker 自身を seccomp プロファイルと jailer(namespace・cgroup・chroot で包む補助プロセス)で囲い、**「VMを抜けても、次はホストOS側の最小化された牢に落ちる」**という多層防御を組みます。
Firecracker の本質的な強みは、隔離境界がCPUのハードウェア仮想化(VMX non-root とEPT)にある点です。ゲストカーネルとホストカーネルは別物で、ゲストのシステムコールはゲスト専用カーネルが処理します。ホストカーネルへ到達するのは、virtio経由のI/O要求がVMMを介して降りてくる細い経路だけ。共有カーネルという最大の弱点を、構造的に消しています。
gVisor:ユーザー空間に書いたカーネル
gVisor(Google製、runsc ランタイム)は逆の発想です。VMを使わず、それでも共有カーネルへの直接到達を断ちます。中核は Sentry と呼ぶ、Go で書かれたユーザー空間のカーネルです。
仕組みはこうです。サンドボックス内のアプリがシステムコールを発行すると、それはホストカーネルへ素通りせず、Sentry が横取りします。Sentry はそのシステムコール(open・read・mmap・futex など 200 以上)を自前で再実装しており、アプリから見える「カーネル」として振る舞います。ファイルアクセスは Gofer という別プロセスへ委譲し、ネットワークも独自スタックで処理します。アプリのシステムコールがホストカーネルに直接届くことは、原則ありません。
[従来のコンテナ]
アプリ ──syscall──► ホストカーネル(共有・巨大な攻撃面)
[gVisor]
アプリ ──syscall──► Sentry(ユーザー空間カーネル, Go)
│ ごく一部のhostcallだけ
▼
ホストカーネル(seccompで強く制限)
肝は、Sentry 自身がホストカーネルに対して呼べるシステムコールを seccomp で極端に絞っていることです。アプリが何百種を呼ぼうとも、ホストカーネルが実際に晒されるのは Sentry が使う数十種の安全な呼び出しだけ。攻撃者はまず Sentry(Go製でメモリ安全寄り)を破り、さらにその先の絞られた窓口を抜けねばならず、二段の壁になります。
Sentry がシステムコールを捕まえる方式(gVisorでは「プラットフォーム」と呼ぶ)が性能を左右します。ptrace方式はptrace系の仕組みでアプリを止めて横取りしますが、システムコールごとにコンテキストスイッチが入り遅く、現在は非推奨です。これを置き換えたsystrap方式はseccomp-bpfでアプリ自身に横取りコードを実行させ、ptraceの往復を消したもので、2023年以降のデフォルトです。仮想化支援を要しないためVMの中でも動きます。KVM方式は、Sentry自身をゲストとしてVMX non-rootで走らせ、アプリのシステムコール命令をVM exitとして直接Sentryへ届けます。ハードウェア仮想化を借りる分、構成次第で速い場合もありますが、ネスト仮想化下ではsystrapより遅くなりがちで、デフォルトではありません。
攻撃面とオーバーヘッドのトレードオフ
両者は「コンテナの弱い隔離を補う」目的を共有しつつ、削る相手とコストが異なります。
| 観点 | Firecracker(軽量VM) | gVisor(ユーザー空間カーネル) |
|---|---|---|
| 隔離の壁 | ハードウェア仮想化(VMX/EPT) | Sentryによるsyscall再実装+seccomp |
| ゲストカーネル | 本物のLinuxカーネルを別途起動 | Goで書かれたSentryが代替 |
| 主な攻撃面 | VMMのデバイスエミュレーション | Sentryのsyscall実装の正しさ |
| 互換性 | 高い(本物のカーネル) | 未実装syscallがあると動かない場合あり |
| I/O性能 | 比較的良い(virtio) | 重いI/O・syscall多発で低下しやすい |
| 起動・密度 | 約125ms・高密度 | VM不要でさらに軽い起動も可能 |
Firecracker のコストは、本物のゲストカーネルを各VMで動かす点にあります。隔離は強固で互換性も高い反面、ゲストカーネル分のメモリと、I/Oが必ず virtio→VMM を経る間接コストを払います。gVisor のコストは、システムコールがすべて Sentry を経由する点にあります。CPU 計算中心のワークロードでは差は小さい一方、システムコールやI/Oが多発するワークロード(DBや大量のファイル操作)では、横取りと再実装の往復がオーバーヘッドとして効きます。また Sentry が未実装の呼び出しを使うアプリは動かないか縮退するため、互換性は Firecracker に劣ります。
gVisor は攻撃面を Sentry のコードの正しさに移し替えただけで、Sentry にバグがあればそこが破られます(攻撃面をホスト全カーネルからSentryへ縮小はするが消しはしない)。Firecracker も VMMとKVMの正しさに依存し、過去にハイパーバイザのVM escape脆弱性は実在します。両者とも seccomp や jailer で多層にする前提であり、単独の壁に全幅の信頼を置く設計ではありません。
コンテナの弱点はホストカーネルの共有=広い攻撃面。Firecracker=KVM上の最小VMMで、デバイスを数個に削り、ハードウェア仮想化で壁を引く(強い隔離・高い互換・起動約125ms)。gVisor=VMを使わず、syscallをSentry(ユーザー空間カーネル)で横取り再実装し、ホストへの直接到達を断つ(より軽いがsyscall多発で遅く、互換に穴)。Sentryの捕捉はptraceよりKVM方式が速い。どちらも攻撃面を縮小するが消滅させはせず、seccomp等で多層化する。
まとめ
- コンテナは namespace/cgroup で区切ってもホストカーネルを共有するため、共有カーネルが攻撃面になる。マイクロVM/サンドボックスはこの境界を置き換える。
- Firecracker は KVM 上の最小 VMM。デバイスを virtio など数個に削り、PCI/BIOS も省いて起動を約125ms・常駐を数MBに抑える。隔離はハードウェア仮想化が引く。
- gVisor は VM を使わず、システムコールを Sentry(Go製のユーザー空間カーネル)で横取り再実装し、ホストカーネルへの直接到達を seccomp で強く絞る。捕捉は KVM 方式が速い。
- トレードオフは攻撃面とオーバーヘッド。Firecracker は強い隔離と高互換だがゲストカーネル分のコスト、gVisor はより軽いが syscall/I/O 多発で遅く互換に穴が出る。いずれも多層防御が前提。
OS Article
マイクロVM(Firecracker・gVisor)の隔離設計を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
コンテナ
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
Firecrackerは数十個のデバイスだけを持つ最小VMM(KVM上)で、ハードウェア仮想化の壁を使い、起動を約125ms・メモリ常駐を数MBに抑える。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「コンテナ / 仮想化」に近いか確認する。
- 強みである「コンテナはホストカーネルを共有するため、共有カーネルが攻撃面になる。マイクロVMはこの境界を別の隔離壁で置き換える。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。