サーバーレス関数やエッジ実行基盤(利用者に近い場所でコードを動かす仕組み)をマルチテナント構成で運用しているなら、一度立ち止まって確認してほしい点があります。それは「関数同士の分離境界が、OSカーネルの共有を前提にしていないか」という点です。
DockerやKubernetesのコンテナは、同じホストOSのカーネルをテナント間で共有します。この前提自体は長年実績がありますが、エッジ環境や不特定多数のコードを預かる実行基盤では、話が変わってきます。
何が起きるか
コンテナは軽量で起動が速い反面、分離境界がソフトウェア定義にとどまります。カーネルの脆弱性、たとえばdirty pipeのようなバグやeBPF(カーネル内で安全にプログラムを実行させる仕組み)経由の権限昇格が見つかると、1つのテナントの関数から他テナントやホスト自体への侵害につながり得ます。
Cloudflare WorkersやDeno Deployが採用するV8 Isolates(JavaScriptエンジン内でコードごとに実行環境を区切る仕組み)も、起動がミリ秒以下と非常に高速な一方で、同じプロセス・同じカーネルを共有します。境界はV8エンジンのサンドボックス機能に依存しており、ハードウェアレベルの壁ではありません。V8エンジンやNode.js/Denoランタイムにゼロデイ脆弱性が出れば、分離を突破される可能性が残ります。
影響範囲は単一リクエストにとどまりません。ホストを共有する設計では、1つの脆弱性がマルチテナント全体、場合によっては物理ホストそのものの侵害にまで広がります。エッジノードは通信基地局やオフィス内の小型サーバーなど、物理的にアクセスされやすい場所に置かれることも多く、クラウドのデータセンターより前提とすべき脅威レベルが高くなります。
なぜ起きるか
根本原因は「速さ」と「隔離の強さ」がトレードオフの両端に位置している構造にあります。
コンテナやV8 Isolatesがカーネル共有という設計を選ぶのは、起動時間を極限まで削るためです。カーネルを毎回新規に立ち上げる従来型の仮想マシンは、起動に1〜2秒かかり、サーバーレスの「リクエストが来てから数十ミリ秒で応答する」という要求に合いません。
一方、AWS Lambdaの基盤技術であるFirecracker(Amazonが開発したKVMベースの軽量VMM)のようなMicroVM方式は、KVM(Linuxカーネルが提供する仮想化機構)を使い関数ごとに独立したカーネルとメモリ空間を割り当てます。ゲスト側のカーネルが侵害されてもホストには波及しません。ただし一般的な仮想マシンの起動コストがネックになり、長らく「安全だが遅い」という評価がついて回っていました。
Firecrackerがこの構図を変えたのは、汎用ハイパーバイザー(QEMUなど)とは違い、Rustで書かれた軽量VMMとして、不要なデバイスエミュレーションを削ぎ落とした設計にしたためです。これにより起動時間を50ミリ秒未満まで圧縮し、MicroVMの「遅い」という弱点を大きく縮小しました。つまり原因は、分離の強さを選ぶか起動の速さを選ぶかという二択を、長年どちらかしか取れなかったアーキテクチャ上の制約にあります。
自分のプロジェクトが該当するか確認する
まず、自分たちの実行基盤がどの分離モデルに属しているかを確認します。
- コンテナランタイム(Docker/containerd)だけで関数やテナントを分離していないか
- 使っているサーバーレス基盤やエッジ実行環境が、V8 Isolates型(Cloudflare Workers、Deno Deploy系)か、MicroVM型(AWS Lambda、Firecracker採用基盤)かを把握しているか
- 不特定の外部コード(顧客が書いたプラグインや関数)を同一ホストで実行していないか
実行環境の調査は以下のコマンドで足がかりになります。
# ホスト側でカーネル共有型コンテナかどうかを確認(名前空間の分離状況)
lsns -t pid,net,mnt
# KVMベースの仮想化が有効かどうか(Firecracker等MicroVM方式に必要)
ls /dev/kvm
# 稼働中コンテナのランタイムを確認(runcかKata/Firecracker系か)
docker info | grep -i "runtime"docker infoの出力でruncのみが表示される場合、標準のカーネル共有型コンテナです。Kata Containersやfirecracker-containerdといったランタイムが併記されていれば、すでにMicroVM相当の分離を導入している可能性があります。
社内の基盤チームに対しては、以下を確認するとよいです。
- 関数実行基盤の設計ドキュメントに「分離モデル」の章があるか
- マルチテナントで顧客コードを実行する場合、脅威モデル(想定する攻撃者像)にカーネル脆弱性が含まれているか
- インシデント対応計画に「カーネル脆弱性公開時のパッチ適用手順」があるか
対策の手順
該当する、あるいはリスクが気になる場合、以下の順で対応を検討します。
ステップ1: 脅威モデルの棚卸し
不特定多数のコードを実行するのか、社内の信頼できるコードのみかを整理します。前者であれば、ソフトウェア境界だけの分離は不十分と判断する材料になります。
ステップ2: 分離方式の選択肢を比較する
| 方式 | 起動速度 | 分離の強さ | 代表例 |
|---|---|---|---|
| 標準コンテナ(runc) | 非常に速い | カーネル共有(弱) | Docker/Kubernetes |
| V8 Isolates | 最速(サブミリ秒) | プロセス内分離(中) | Cloudflare Workers |
| Firecracker MicroVM | 速い(50ms未満) | ハードウェア境界(強) | AWS Lambda |
| 汎用VM(QEMU等) | 遅い(1-2秒) | ハードウェア境界(強) | 従来型仮想化 |
ステップ3: 移行コストを見積もる
既存基盤がruncベースの場合、全面移行ではなくKata Containersやfirecracker-containerdのような「既存のKubernetes/Dockerワークフローの上にMicroVM分離を載せる」アプローチが現実的です。コンテナイメージの互換性や起動時間への影響を、ステージング環境で計測してから本番に適用します。
ステップ4: 冷起動対策とセットで検討する
MicroVM導入時は起動時間の増加が懸念点になります。スナップショット(起動済み状態の保存と復元)やプリウォーム(事前に実行環境を温めておく仕組み)など、冷起動を緩和する仕組みが基盤側に用意されているかを合わせて確認します。
ステップ5: ハイブリッド構成も選択肢に入れる
すべての関数をMicroVMにする必要はありません。信頼度の高い内部処理はV8 Isolatesやコンテナで高速に、外部由来・未信頼のコードはMicroVMで厳格に分離するという使い分けも、現実的な落とし所です。
まとめ
コンテナやV8 Isolatesの分離境界は、起動速度と引き換えにカーネル共有という前提を抱えています。
まずdocker infoや/dev/kvmの有無で、自分たちの実行基盤がどちらの性質を持つかを確認してください。
マルチテナントで未信頼のコードを扱う場合は、FirecrackerやKata Containersのような MicroVM方式への部分移行、あるいはハイブリッド構成を検討する価値があります。
起動速度と分離強度はトレードオフであり、どちらか一方を無条件に選ぶのではなく、扱うコードの信頼度に応じて使い分ける判断が求められます。