Container Runtimes, Engines, Builders, And Sandboxes
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
コンテナセキュリティで最大の混乱の元のひとつは、まったく異なる複数のコンポーネントが同じ単語に収束してしまうことです。 “Docker” はイメージフォーマット、CLI、デーモン、ビルドシステム、ランタイムスタック、あるいは単にコンテナ一般の概念を指すことがあります。セキュリティの観点では、この曖昧さは問題です。なぜなら、異なるレイヤーが異なる防御を担っているからです。悪いbind mountによるブレイクアウトは低レベルのランタイムバグによるブレイクアウトと同じではなく、どちらもKubernetesのクラスタポリシーのミスとは異なります。
このページではエコシステムを役割ごとに分け、残りのセクションで保護や弱点が実際にどこに存在するのかを正確に論じられるようにします。
OCI As The Common Language
現代のLinuxコンテナスタックは、多くがOCI仕様群を話すため相互運用が可能です。OCI Image Specificationはイメージとレイヤーがどのように表現されるかを説明します。OCI Runtime Specificationはランタイムがプロセスをどのように起動すべきか(namespaces、mounts、cgroups、セキュリティ設定を含む)を説明します。OCI Distribution Specificationはレジストリがコンテンツをどのように公開するかを標準化します。
これは、あるツールで作られたコンテナイメージが別のツールで動く理由や、複数のエンジンが同じ低レベルのランタイムを共有できる理由を説明します。また多くの製品でセキュリティ挙動が似て見える理由も説明します:多くの場合、同じOCIランタイム設定を構築して同じ少数のランタイムに渡しているからです。
Low-Level OCI Runtimes
低レベルランタイムはカーネル境界に最も近いコンポーネントです。これは実際にnamespacesを作成し、cgroup設定を書き込み、capabilitiesやseccompフィルタを適用し、最後に execve() でコンテナプロセスを実行する部分です。人々が機械的なレベルで「コンテナ隔離」について議論する場合、明示されていなくても通常このレイヤーを指しています。
runc
runc は参照実装のOCIランタイムで、最も知られた実装のままです。Docker、containerd、多くのKubernetesデプロイで広く使われています。公開された研究やエクスプロイト資料が runc スタイルの環境を標的にすることが多いのは、それらが一般的であり、runc が多くの人がLinuxコンテナを思い描く際の基準を定義しているからです。したがって、runc を理解することは古典的なコンテナ隔離の強いメンタルモデルを読者に与えます。
crun
crun は別のOCIランタイムで、Cで書かれ、現代のPodman環境で広く使われています。cgroup v2のサポート、rootlessの使い勝手、より低いオーバーヘッドが評価されることが多いです。セキュリティの観点で重要なのは、異なる言語で書かれているという点ではなく、依然として同じ役割を果たしているという点です:OCI設定をカーネル下で動作するプロセスツリーに変換するコンポーネントです。rootlessなPodmanワークフローが安全に感じられることが多いのは、crun が魔法のようにすべてを解決するからではなく、その周辺スタックがユーザーネームスペースや最小権限の方向により強く寄る傾向があるからです。
runsc From gVisor
runsc は gVisor が用いるランタイムです。ここでは境界が有意に変わります。大半のsyscallを通常の方法でホストカーネルに直接渡す代わりに、gVisor はユーザースペースのカーネル層を挿入し、Linuxインターフェースの大部分をエミュレートまたは仲介します。その結果は単にいくつかの追加フラグを持つ通常の runc コンテナではなく、ホストカーネルの攻撃面を減らすことを目的とした異なるサンドボックス設計です。互換性やパフォーマンスのトレードオフがこの設計には含まれるため、runsc を使う環境は通常のOCIランタイム環境とは別に文書化されるべきです。
kata-runtime
Kata Containers はワークロードを軽量な仮想マシン内で起動することで境界をさらに押し広げます。管理上はこれがコンテナデプロイのように見えることがあり、オーケストレーション層もそのように扱うかもしれませんが、基礎となる隔離境界は伝統的なホストカーネル共有コンテナというよりも仮想化に近くなります。これにより、コンテナ中心のワークフローを放棄せずにより強固なテナント隔離が必要な場合にKataは有用です。
Engines And Container Managers
低レベルランタイムがカーネルと直接話すコンポーネントであるのに対し、engineやmanagerはユーザや運用者が通常対話するコンポーネントです。イメージのpull、メタデータ、ログ、ネットワーク、ボリューム、ライフサイクル操作、API公開などを扱います。このレイヤーは実に重要で、多くの現実世界の侵害はここで発生します:runtime socketやdaemon APIへのアクセスは、低レベルランタイム自体が完全に健全であってもホスト侵害に等しいことがあります。
Docker Engine
Docker Engine は開発者にとって最も認識されているコンテナプラットフォームであり、コンテナ語彙がDocker型になった理由の一つです。典型的な経路は docker CLI から dockerd へで、dockerd は containerd や OCIランタイムのような低レベルコンポーネントを調整します。歴史的に、Dockerのデプロイはしばしばrootfulであり、Dockerソケットへのアクセスは非常に強力なプリミティブでした。だからこそ多くの実践的な権限昇格資料が docker.sock に焦点を当てるのです:プロセスが dockerd に特権コンテナの作成、ホストパスのマウント、あるいはホストnamespaceへの参加を要求できれば、カーネルエクスプロイトは不要かもしれません。
Podman
Podman はよりデーモンレスなモデルを念頭に設計されました。運用上、これによりコンテナは長時間稼働する特権デーモンではなく標準的なLinuxメカニズムで管理される単なるプロセスであるという考えが強化されます。Podman はまた、多くの人が最初に学んだ古典的なDockerデプロイよりもはるかに強力なrootlessストーリーを持ちます。それがPodmanを自動的に安全にするわけではありませんが、特にユーザーネームスペース、SELinux、および crun と組み合わせるとデフォルトのリスクプロファイルを大きく変えます。
containerd
containerd は多くのモダンスタックでコアなランタイム管理コンポーネントです。Dockerの下で使われ、Kubernetesの主要なランタイムバックエンドの一つでもあります。強力なAPIを公開し、イメージとスナップショットを管理し、最終的なプロセス作成を低レベルランタイムに委譲します。containerdに関するセキュリティ議論では、containerdのソケットや ctr/nerdctl の機能へのアクセスが、インターフェースやワークフローが「開発者向け」ではなく感じられてもDockerのAPIと同じくらい危険であり得ることを強調すべきです。
CRI-O
CRI-O は Docker Engine よりも焦点が絞られています。汎用の開発者プラットフォームである代わりに、Kubernetes Container Runtime Interface をクリーンに実装することを中心に構築されています。これにより、CRI-O は Kubernetes ディストリビューションや OpenShift のような SELinux に依存したエコシステムで特に一般的です。セキュリティの観点からは、その狭いスコープは概念的なノイズを減らすのに有用です:CRI-O は「Kubernetesのためにコンテナを実行する」レイヤーの一部であり、何でもやるプラットフォームではありません。
Incus, LXD, And LXC
Incus/LXD/LXC システムは Dockerスタイルのアプリケーションコンテナとは分けて考える価値があります。これらはしばしばsystem containersとして使われるからです。system container は通常、より完全なユーザースペース、長時間稼働するサービス、より広いデバイス公開、より深いホスト統合を持つ軽量マシンのように振る舞うことが期待されます。隔離機構自体は依然としてカーネルプリミティブに基づきますが、運用上の期待は異なります。その結果、ここでのミスコンフィギュレーションは「悪いアプリコンテナのデフォルト」のように見えることは少なく、軽量仮想化やホスト委譲のミスに近い形になります。
systemd-nspawn
systemd-nspawn は systemd ネイティブで、テスト、デバッグ、OSに近い環境の実行に非常に有用という点で興味深い位置を占めます。クラウドネイティブの本番ランタイムとして支配的ではありませんが、ラボやディストリビューション指向の環境で頻繁に現れるため言及に値します。セキュリティ分析において、これは「コンテナ」という概念が複数のエコシステムと運用スタイルに跨ることを思い出させます。
Apptainer / Singularity
Apptainer(旧 Singularity)は研究やHPC環境で一般的です。その信頼前提、ユーザーワークフロー、実行モデルは Docker/Kubernetes 中心のスタックとは重要な点で異なります。特にこれらの環境では、ユーザにパッケージ化されたワークロードを実行させたいが、広範な特権的なコンテナ管理権限を渡したくないという要求が強いことが多いです。すべてのコンテナ環境を基本的に「サーバ上のDocker」と仮定すると、これらのデプロイを大きく誤解することになります。
Build-Time Tooling
多くのセキュリティ議論はランタイムだけを語りますが、ビルド時ツールも重要です。なぜならイメージの内容、ビルド秘密の露出、どれだけ信頼されたコンテキストが最終成果物に組み込まれるかを決めるからです。
BuildKit と docker buildx はキャッシュ、secret mounting、SSH転送、マルチプラットフォームビルドなどの機能をサポートするモダンなビルドバックエンドです。これらは便利な機能ですが、セキュリティの観点では、秘密がイメージレイヤに leak する場所を作ったり、過剰に広いビルドコンテキストが本来含めるべきでないファイルを露出させたりする可能性も生みます。Buildah は特にPodman周りのOCIネイティブエコシステムで似た役割を果たし、Kaniko はビルドパイプラインに特権的なDockerデーモンを付与したくないCI環境でよく使われます。
重要な教訓は、イメージ作成とイメージ実行は別のフェーズであるということです。しかし、弱いビルドパイプラインはコンテナが起動されるずっと前に弱いランタイムの姿勢を生む可能性がある、という点です。
Orchestration Is Another Layer, Not The Runtime
Kubernetes をランタイムそのものと同一視してはなりません。Kubernetes はオーケストレータです。Pod をスケジュールし、desired state を保存し、ワークロード設定を通じてセキュリティポリシーを表現します。kubelet は containerd や CRI-O のような CRI 実装と話し、それがさらに runc、crun、runsc、または kata-runtime のような低レベルランタイムを呼び出します。
この分離は重要です。なぜなら、多くの人がある保護を「Kubernetes」のものだと誤認しているが実際にはノードランタイムによって強制されている場合や、Pod spec から来た挙動を「containerdのデフォルト」のせいにしている場合があるからです。実際には最終的なセキュリティ姿勢は合成です:オーケストレータが何かを要求し、ランタイムスタックがそれを翻訳し、最終的にカーネルがそれを強制します。
Why Runtime Identification Matters During Assessment
エンジンとランタイムを早期に特定すれば、その後の多くの観察が解釈しやすくなります。rootless の Podman コンテナはユーザーネームスペースが関与している可能性を示唆します。Dockerソケットがワークロードにマウントされていれば、API駆動の権限昇格が現実的な経路であることを示します。CRI-O/OpenShift ノードであれば、SELinuxラベルや制限されたワークロードポリシーをすぐに考えるべきです。gVisor や Kata 環境であれば、古典的な runc ブレイクアウトのPoCが同じように振る舞うとは限らないとより慎重に考えるべきです。
だからこそ、コンテナ評価の最初のステップの一つは常に二つの簡単な質問に答えることです:どのコンポーネントがコンテナを管理しているか、そしてどのランタイムが実際にプロセスを起動したか。これらの答えが明確になれば、残りの環境は通常ずっと理解しやすくなります。
Runtime Vulnerabilities
すべてのコンテナエスケープがオペレータの誤設定から来るわけではありません。時にはランタイム自体が脆弱なコンポーネントであることがあります。これは重要です。というのも、ワークロードが慎重に構成されているように見えても、低レベルランタイムの欠陥によって露出する可能性があるからです。
古典的な例は runc の CVE-2019-5736 で、悪意あるコンテナがホストの runc バイナリを上書きし、後の docker exec や類似のランタイム呼び出しが攻撃者制御のコードをトリガーするのを待つ、というものです。このエクスプロイト経路は単純なbind-mountやcapabilityのミスとは非常に異なり、execハンドリング中にランタイムがどのようにコンテナプロセス空間に再入するかを悪用します。
red-teamの視点からの最小限の再現ワークフローは:
go build main.go
./main
次に、ホストから:
docker exec -it <container-name> /bin/sh
重要な教訓は、過去の正確なエクスプロイト実装そのものではなく、評価上の含意である:もし runtime version が脆弱であれば、通常の in-container code execution だけで host を侵害できる可能性があり、可視化された container 設定が一見して明白に弱く見えなくてもそうなり得る。
最近の runtime CVE(例:CVE-2024-21626 in runc)、BuildKit mount races、及び containerd parsing bugs は同じ点を強調する。Runtime version と patch level は単なるメンテナンスの雑事ではなく、セキュリティ境界の一部である。
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。


