Docker分離:最初の防衛線
5つのハードニングフラグでAIエージェントをDocker分離する。読み取り専用ファイルシステム、ケーパビリティ削除、非rootユーザー、リソース制限、ネットワーク制限を実装する。
プレミアムコースコンテンツ
このレッスンはプレミアムコースの一部です。Proにアップグレードすると、すべてのプレミアムコースとコンテンツを利用できます。
- すべてのプレミアムコースを利用
- 1,000以上のAIスキルテンプレート付き
- 毎週新しいコンテンツを追加
コンテナは魔法ではない(でも大いに助ける)
🔄 Quick Recall: 前回のレッスンで、OWASP、AWSスコーピングマトリクス、Rule of Twoを使って脅威モデルを構築した。Docker分離を過剰なエージェンシー(A2)とツール悪用(A1)に対する最初の防御として特定した。今度はそれを実装する。
SecurityScorecardは135,000以上のOpenClawインスタンスがインターネットに露出していることを発見。デフォルト設定がすべてのネットワークインターフェースにバインドするため。Docker設定の1つの変更——localhostへのバインド——がそれらの露出すべてを防いだはず。
このレッスンはまさにそれについて:最大のセキュリティインパクトを持つ、具体的で実践的な変更。
このレッスンの終了時にできるようになること:
- AIエージェント固有の5つのハードニングフラグでDockerコンテナを設定できる
- 標準コンテナからMicroVMまでの分離スペクトラムを説明できる
Dockerが実際にやっていること
Dockerは2つのLinuxカーネル機能を使って分離環境を作る:
ネームスペースはコンテナに独自のシステムビューを与える——独自のプロセスID、ネットワークインターフェース、ファイルシステムマウント、ユーザーID。コンテナは自分がマシン上に単独でいると思っている。
cgroupsはコンテナが使用できるホストリソースの量を制限する——CPU、メモリ、ディスクI/O。コンテナがいくら試しても全RAMを消費できない。
これらが合わさって境界を作る。エージェントは内側で実行される。個人ファイル、他のアプリケーション、システム設定は外側に住む。侵害されたエージェントは境界内部のものしか破壊できない。
限界: ネームスペースとcgroupsの両方がホストカーネルに依存する。コンテナはマシンとカーネルを共有する。カーネル脆弱性があれば、攻撃者がコンテナから完全に脱出できる可能性がある。
個人使用では、ハードニングフラグ付きDockerで十分。高セキュリティ環境では、MicroVM(後述)が独自カーネルを実行することでより強力な分離を提供する。
5つのハードニングフラグ
ComposioのRAKフレームワーク(Root, Agency, Keys)とDocker自身のセキュリティガイダンスは、AIエージェントにとって最も重要な5つのフラグに収束する:
フラグ1:--read-only
コンテナのファイルシステムを読み取り専用にする。エージェントはシステムディレクトリに書き込み、自身の設定を変更、永続的バックドアを作成することができなくなる。
# docker-compose.yml
services:
agent:
read_only: true
tmpfs:
- /tmp
- /app/data
エージェントが正当に書き込む必要があるディレクトリに書き込み可能なtmpfs(インメモリ)ボリュームをマウントする。それ以外はすべて凍結。
なぜ重要か: Zenityの研究では、悪意あるスキルがSOUL.md(エージェントのメモリファイル)に書き込むことで永続化できることを示した。読み取り専用ファイルシステムがこれを防ぐ——メモリディレクトリを明示的に書き込み可能にマウントしない限り。その場合は監視(レッスン6)と組み合わせる。
フラグ2:--cap-drop=ALL
Linuxケーパビリティはきめ細かな特権:ファイルシステムのマウント(CAP_SYS_ADMIN)、ネットワーク設定の変更(CAP_NET_ADMIN)、カーネルモジュールのロード(CAP_SYS_MODULE)。デフォルトでDockerコンテナはこれらのいくつかを取得する。
--cap-drop=ALLはすべてのケーパビリティを削除する。エージェントは昇格された特権ゼロで実行される。
services:
agent:
cap_drop:
- ALL
エージェントが特定のケーパビリティを必要とする場合(AIエージェントでは稀)、cap_addで明示的に追加する。デフォルトを残さない。
フラグ3:非rootユーザー
デフォルトでDockerコンテナ内のプロセスはrootで実行される。攻撃者がコンテナを脱出すると、ホスト上にrootとして着地する。
services:
agent:
user: "1000:1000"
またはDockerfileで:
RUN addgroup --system agent && adduser --system --ingroup agent agent
USER agent
なぜ重要か: Argusセキュリティ監査では、OpenClawのファイル権限が0o600(オーナーのみ)に設定されているがプロセスがrootで実行されていることが判明——権限制限が無意味。非rootユーザーでの実行がファイル権限を実際に機能させる。
✅ Quick Check: AIエージェントコンテナがデフォルトのケーパビリティでrootとして実行されている。攻撃者がコンテナ脱出脆弱性を見つけた。何を得るか?(答え:昇格されたLinuxケーパビリティ付きでホストマシンへのrootアクセス。コンテナが–cap-drop=ALL付きで非rootユーザーとして実行されていれば、攻撃者はケーパビリティなしの非特権ユーザーとしてホストに着地——被害を劇的に制限。)
フラグ4:リソース制限
侵害された(または単にハルシネーションしている)エージェントがすべてのCPUとメモリを消費し、事実上自分のマシンをDoS攻撃する可能性がある。
services:
agent:
deploy:
resources:
limits:
memory: 2G
cpus: "1.0"
reservations:
memory: 512M
cpus: "0.5"
これでエージェントは2GB RAMと1 CPUコアに制限される。それ以上使おうとすると、Dockerがプロセスをキルする。マシンのレスポンスは維持される。
フラグ5:ネットワーク制限
これが最も重要。localhostへのバインドでリモートアクセスを防止。さらにネットワーク分離も可能:
services:
agent:
ports:
- "127.0.0.1:18789:18789" # localhostのみ
networks:
- agent-internal
networks:
agent-internal:
internal: true # インターネットアクセスなし
ネットワークでinternal: trueを設定すると、コンテナはインターネットにまったくアクセスできなくなる。これで致命的な三要素の1つ(外部通信)を排除し、認証情報の外部流出を防ぐ。
トレードオフ: 多くのエージェント機能にはインターネットアクセスが必要(Web検索、API呼び出し)。すべてをブロックするのではなく、プロキシを通じて特定のドメインを選択的に許可する必要があるかもしれない。
✅ Quick Check: エージェント用に内部Dockerネットワークを設定したが、エージェントが1つの特定のAPIを呼び出す必要がある。最も安全なアプローチは?(答え:特定のAPIドメインとポートのみを許可するHTTPプロキシまたはファイアウォールルールを使用。エージェントは任意のインターネット宛先にアクセスできないが、必要な1つのAPIは動作する。これがネットワーキングに適用された最小権限の原則。)
完全なハードニング設定
5つのフラグをすべて組み合わせた本番環境対応のdocker-compose.yml:
version: "3.8"
services:
agent:
image: openclaw/openclaw:latest
read_only: true
user: "1000:1000"
cap_drop:
- ALL
ports:
- "127.0.0.1:18789:18789"
deploy:
resources:
limits:
memory: 2G
cpus: "1.0"
tmpfs:
- /tmp
- /app/data
environment:
- GATEWAY_TOKEN=${GATEWAY_TOKEN}
volumes:
- ./agent-data:/app/workspace:rw
networks:
- agent-net
networks:
agent-net:
internal: true
これをマシン上で直接OpenClawを実行する場合と比較:ファイルシステム保護なし、rootアクセス、リソース制限なし、すべてのネットワークインターフェースが露出。ハードニングされたDocker版はエージェントに必要なものだけを与え、それ以上は何も与えない。
分離スペクトラム
Dockerが唯一の選択肢ではない。異なる分離技術の比較:
| 技術 | 分離レベル | 起動時間 | オーバーヘッド | 最適な用途 |
|---|---|---|---|---|
| コンテナなし | なし | N/A | 0% | 開発のみ |
| 標準Docker | プロセスレベル(共有カーネル) | 約1秒 | 約2% | ほとんどの個人使用 |
| Docker+ハードニングフラグ | ハードニングされたプロセスレベル | 約1秒 | 約2% | 推奨ベースライン |
| gVisor | システムコール傍受 | 約2秒 | I/O 10-30% | 計算重視のエージェント |
| MicroVM(Firecracker) | ハードウェア仮想化 | 約125ms | <5 MiB | 高セキュリティ環境 |
MicroVMは軽量仮想マシン内で独自カーネルを実行する。ホストのカーネル脆弱性がMicroVMに影響しない(逆も同様)。AWS Firecrackerは約125msで起動し、5 MiB未満のメモリオーバーヘッド——インタラクティブ使用に十分な速さ。
gVisorはシステムコールを傍受しユーザースペースカーネルで実行する。標準Dockerより強力だがMicroVMより弱い。10-30%のI/Oオーバーヘッドがディスク集約型ワークフローには不向き。
このコースでは、ハードニングフラグ付きDockerが実用的な推奨。レッスン1で文書化された最も一般的な攻撃をブロックしつつ、セットアップと維持が容易。
Key Takeaways
- 5つのハードニングフラグ:
--read-only、--cap-drop=ALL、非rootユーザー、リソース制限、127.0.0.1バインド - 読み取り専用ファイルシステムがSOUL.mdポイズニングのような永続的バックドアを防ぐ
- ケーパビリティ削除でコンテナ脱出時に攻撃者が得る昇格された特権をゼロにする
- localhostバインドだけで135,000以上の露出インスタンスを防げた
- 内部ネットワークが外部通信を排除——致命的な三要素の1つを除去
- MicroVMはコンテナより強力な分離を提供するが、ハードニング付きDockerが実用的なベースライン
Up Next
レッスン4:権限境界と認証情報分離——エージェントはコンテナ化された。しかしコンテナ化だけでは不十分——コンテナ内部でエージェントができることも制御する必要がある。最小権限、スコープ付きトークン、APIキーがエージェントに直接触れないようにする方法を学ぶ。
理解度チェック
まず上のクイズを完了してください
レッスン完了!