Docker Sandboxes

安全性 — ポリシーと認証情報の境界

microVM が隔離したうえで、作業フォルダ・ネットワーク・認証情報・SSH エージェント転送のどこに 運用上の責任が残るのかを詳しく説明する。隔離の全体像は先に 仕組みを読む。

認証情報の境界SSH エージェント

検証: sbx v0.35.0・macOS (Apple Silicon)

先に動かしてみたい方へ

インストールと最初の実行は「はじめる」、日常操作は「使い方」、microVM の隔離モデルは「仕組み」へ。

1.安全性の詳細 — ポリシーとシークレット


ネットワークポリシー — 3 つのプリセット

初回起動時に 3 つのプリセットから選ぶ。これは個々のサンドボックスへ固定される設定ではなく、手元ポリシーの全体向けの土台になる。 個別ルールの追加・削除は実行中のサンドボックスにもすぐ反映される。プリセット自体を後から選び直すには sbx policy reset を使うが、常駐プロセスと実行中サンドボックスがいったん停止し、常駐プロセスは次の sbx コマンドで再起動する。

プリセット 挙動 向いている場面
Open 全トラフィック許可 とりあえず試す。隔離は microVM 境界のみに頼る
Balanced(推奨) デフォルト拒否+GitHub / npm / pip / Docker Hub など主要サイトを許可 日常の開発。まずこれで始めて足りない分を追加許可
Locked Down 明示的に許可した宛先以外すべて拒否 機密プロジェクト・厳格運用

足りないドメインは個別に許可する。ルールはデフォルトで全サンドボックスへ適用され、--sandbox を付けると 1 つに限定できる。 ブロックの原因調査には sbx policy log が便利。組織がガバナンスを有効にしている場合は組織ポリシーが手元のポリシーを置き換えるため、 手元のルールやプリセットを変えても有効にならない。

ポリシー管理
$ sbx policy allow network github.com:443          # グローバルに許可
$ sbx policy allow network --sandbox mybox example.com  # サンドボックス単位で許可
$ sbx policy deny  network --sandbox mybox evil.example.com
$ sbx policy ls --wide                             # ルール ID・リソースの確認
$ sbx policy rm network --resource example.com     # 許可/拒否ルールを削除(--id でも可)
$ sbx policy rm network --sandbox mybox --resource example.com
$ sbx policy log                                   # 何がブロックされたかを確認
$ sbx policy reset                                 # プリセット選択からやり直す

同じ宛先に allow と deny が両方ある場合、deny が優先される(sbx policy deny --help)。 いったん許可した宛先を拒否に切り替えたいときは、先に sbx policy rm network --resource … で allow を外してから deny する運用が分かりやすい。

ブロックされるとエージェント側にはこんなエラーが見える:

ブロック時の表示例
Blocked by network policy: domain github.com:443
detail: no matching allow rule — blocked by default deny policy

Kit(応用)の spec.yaml に書いておけば、サンドボックス作成時から許可リストを固定できる:

spec.yaml(抜粋)
network:
  allowedDomains:
    - api.anthropic.com:443
    - github.com:443
    - "*.amazonaws.com:443"
📋 ポリシー整備の流れ
  1. Locked Down(または Balanced)で始める。
  2. ブロックを sbx policy log で見る(組み込みエージェント向けの公式例と、実際に要るドメインがずれることもある。log を正とする)。
  3. 一時的に sbx policy allow network …
  4. 固まったら Kit の allowedDomains に落とし、サンドボックスを作り直して再現確認する。

シークレット管理 — 方式ごとの境界を区別する

サービス資格情報 — 生の値はホスト側プロキシが保持

anthropicopenaigithub などのサービス資格情報は、実値を環境変数として VM に渡すのではなく、 ホスト側プロキシが外向き HTTP リクエストに認証ヘッダとして注入する。 エージェントは資格情報の権限を使って通信できるが、生の値そのものは読めない。ツールによっては proxy-managed のようなプレースホルダーが環境変数に見えることがある。

サービス資格情報の登録
$ echo "$(gh auth token)" | sbx secret set -g github  # 今後作る全サンドボックス
$ ghtkn get myorg/read | sbx secret set mybox github -f  # mybox だけ・短命トークン

グローバル(-g)なサービス資格情報はサンドボックス作成時に適用されるため、登録・変更後に既存のサンドボックスへ反映するには作り直す。 サンドボックス名を指定した資格情報は、そのサンドボックスが実行中でも直ちに有効になる。

典型的な使い方(GitHub トークンの例)
# ホスト側: サンドボックスを作る前に登録
$ gh auth token | sbx secret set -g github

# サンドボックス内: gh のリクエストへプロキシが資格情報を注入
# gh api user

v0.35 時点で登録できるサービスは anthropic / cursor / droid / github / google / groq / mistral / nebius / openai / openrouter / xaisbx secret set --help より)。エージェント自身の API キーもこの仕組みで注入できるほか、 xai があるので Grok 系 API のキーも扱える(エージェント別の使い方の Grok Build の CLI 認証は ブラウザ経由のログインでサンドボックス内に保存される別方式)。そのほか:

  • sbx secret ls / rm — 登録済みシークレットの一覧・削除
  • sbx secret import — ホストの環境変数から検出して取り込み

Git over SSH とコミット署名 — SSH エージェント転送

直前の github サービス資格情報は、HTTPS 経由の GitHub API / gh 向けの仕組みである。 一方、日常の Git 運用では次のような SSH 経路もよく使う。

  • リモートが git@github.com:org/repo.git 形式で、git fetch / git push が SSH になる
  • 社内 Git サーバや GitLab など、SSH 鍵認証しか使わないホストがある
  • コミットに SSH 署名を求められている

ここでやりがちな誤りは、~/.ssh/id_ed25519 をサンドボックスへ sbx cp したり、 作業フォルダ内に秘密鍵を置いたりすることだ。鍵ファイルが VM に入ると、エージェントから実値を読める。 Docker Sandboxes は代わりに、ホストの SSH エージェントだけをサンドボックスへ転送する。

仕組み(何が起きているか)

ホストで ssh-agent が動き、そこに秘密鍵がロードされているとする。 シェルにはエージェントのソケット経路が SSH_AUTH_SOCK として渡る。 sbx はこのソケットをサンドボックス内へ転送し、VM 内にも同じ環境変数を立てる。 サンドボックス内の ssh / git は「署名して」とホスト側のエージェントに依頼できるだけであり、 秘密鍵ファイルそのものはホストに残る(コピーされない)。 ただしエージェントに載っている鍵で可能な操作(その鍵が通る push、その鍵での署名)はコーディングエージェントに使わせることになるので、 載せる鍵と到達可能なホストは絞る。

前提チェック(ホスト側)

macOS ではログイン時に SSH エージェントが動いていることが多い。まず鍵が載っているかを確認する。

ホスト: エージェントと鍵の確認
$ echo "$SSH_AUTH_SOCK"                 # 空ならエージェントがシェルに渡っていない
$ ssh-add -l                            # ロード済み鍵の一覧。空なら未ロード
$ ssh-add --apple-use-keychain ~/.ssh/id_ed25519   # macOS で鍵をエージェントに載せる例
# Linux などでは: ssh-add ~/.ssh/id_ed25519
$ ssh-add -L                            # 公開鍵(署名設定で使う)

SSH_AUTH_SOCK が空のまま sbx run すると転送されない。 その状態でサンドボックス内の SSH は失敗する(鍵ファイルを VM に置いていない限り当然)。

状況 A: リモートへの Git 操作(HTTPS 推奨 / SSH は制約あり)

サービス資格情報の githubHTTPS 経由の GitHub API / gh 向けである。 GitHub へ push するだけなら、サンドボックスでも HTTPS リモート + github シークレットを第一選択にする方が簡単で、 ネットワークポリシーも 443 のドメイン許可で足りることが多い。

推奨: HTTPS で push / PR(エージェント転送不要)
# ホスト — これから作るサンドボックス向けなら全体向け(-g)
$ gh auth token | sbx secret set -g github
$ sbx run --name mybox claude               # mybox が未作成ならここで新規作成され、-g が適用される

# 既に mybox がある場合は -g は効かない(作成時にしか載らない)。名前付きで入れる:
# $ gh auth token | sbx secret set mybox github
# $ sbx run --name mybox

# サンドボックス内: リモートが SSH なら HTTPS に切り替えてもよい
# git remote set-url origin https://github.com/org/repo.git
# gh api user
# gh pr create --fill

一方、リモートがどうしても git@… の SSH のとき、または社内 Git が SSH のみのときは SSH エージェント転送が必要になる。 ここで重要な制約がある。 SSH のような非 HTTP の TCP は、ホスト名ベースのポリシーでは許可できない (透過プロキシがこの文脈でホスト名を IP に解決できない。公式 Troubleshooting: SSH and other non-HTTP connections)。

⚠️ sbx policy allow network github.com:22 では通らない

構文としては受け付けられても、非 HTTP の SSH には効かない。 許可には 宛先 IP アドレスとポートが必要である。 GitHub のように IP が多数・変動するサービスでは、IP 許可リストの維持が現実的でないことが多い。 その場合は上の HTTPS 経路に寄せるか、組織のネットワーク担当と IP 範囲を調整する。

SSH が必要なとき(固定 IP の Git サーバ向け)
# ホスト: 接続先の IP を調べてから allow(例は仮の IP)
$ dig +short git.example.com A
$ sbx policy allow network "10.1.2.3:22"   # ホスト名:22 ではなく IP:22
$ sbx run --name mybox claude               # このシェルで SSH_AUTH_SOCK が見えていること

# サンドボックス内
# echo "$SSH_AUTH_SOCK"                     # 転送されていれば値が入る
# ssh -T git@git.example.com
# git remote -v                             # origin が git@... であること
# git push -u origin HEAD

失敗時は sbx policy log でブロック履歴を確認する。UDP / ICMP はポリシーでは開けない。 社内 Git で IP が安定している場合に SSH+エージェント転送が現実的で、GitHub.com への日常 push は HTTPS の方が扱いやすい。

状況 B: サンドボックス内で SSH コミット署名する

組織ポリシーで署名付きコミットが必須のときも、秘密鍵を VM に置かずエージェント経由で署名できる (公式 Workflows の Commit signing と同じ手順)。 ホスト側パス(例: ~/.ssh/id_ed25519.pub)をサンドボックスの user.signingkey に書いても、 そのファイルは VM から見えないので失敗する。転送済みエージェント上の公開鍵文字列を使う。 署名の作成自体はネットワーク通信を必要としないため、状況 A の SSH ポリシー制約とは独立している。

ホスト: 署名に使う鍵をエージェントに載せる
$ ssh-add ~/.ssh/id_ed25519
$ ssh-add -L                                # 表示される行が署名に使う公開鍵
サンドボックス内: Git に SSH 署名を設定
# git config --global gpg.format ssh
# git config --global user.signingkey "key::$(ssh-add -L | head -n 1)"
# git config --global commit.gpgsign true   # 毎回 -S を付けたくない場合
# git commit -S -m "feat: my change"
# git log --show-signature -1               # 署名が付いたことの簡易確認(下記注意)

鍵が複数ロードされていると head -n 1 が意図しない鍵を掴むことがある。 その場合は ssh-add -L の出力から使う 1 行を目で選んで key::ssh-ed25519 AAAA... comment の形で直接書く。 毎回の手設定を避けたい場合は、コミュニティ Kit の git-ssh-sign を使う方法もある。

署名の「作成」と「ローカルでの信頼検証」は別

git log --show-signature -1 は、コミットに SSH 署名が埋め込まれたことの確認程度に使う。 ローカルで署名者を「信頼済み」として検証するには、通常 gpg.ssh.allowedSignersFile に公開鍵を登録する必要がある (未設定だと信頼レベルが undefined になり、git verify-commit が失敗しうる)。 この設定は署名の作成には不要。GitHub に push したあとの検証は、アカウントに登録した SSH signing key 側で行われる(公式 Troubleshooting の Sandbox commits aren't signed も同趣旨)。

⚠️ 運用上の注意
  • HTTPS の github シークレットと SSH エージェントは別経路gh pr create や HTTPS の Git は前者、git push git@... は後者。
  • SSH エージェントに載せた鍵の権限がそのままコーディングエージェントに渡る。 個人の強力な鍵を常時ロードしたまま YOLO 運用しない。用途を分けた鍵や、作業後の ssh-add -d を検討する。
  • 外向き SSH はデフォルト拒否かつホスト名ルール不可ホスト名:22 ではなく IP:22 を許可する。GitHub では HTTPS 推奨。
  • ホストの ~/.ssh をマウントしない。known_hosts や設定を共有したくても、秘密鍵ディレクトリごと渡すのは避ける。
  • clone モードでもリモートへの書き込み(HTTPS / SSH いずれでも)は、許可と資格情報の範囲で可能なままである。

カスタムシークレット — VM にはプレースホルダーを置く

sbx secret set-custom は上記リスト外のサービス向け(Experimental)。VM 内の環境変数には実値ではなく 生成されたプレースホルダーを設定し、対象ホストへのリクエスト中に現れたプレースホルダーをプロキシが実値へ置換する。 「環境変数には何も現れない」のではなく、実値の代わりになる文字列が見える方式である。

レジストリ資格情報 — サービス資格情報とは別扱い

非公開の OCI レジストリからテンプレートや Kit を取得したり、サンドボックス内の Docker からイメージを取得・送信したりするための資格情報。指定する範囲で用途が変わる。

指定 用途 安全上の扱い
--registry HOST ホスト側でテンプレート / Kit を取得 ホスト限定。サンドボックスには渡さない
-g --registry HOST ホスト側+今後作る全サンドボックス VM 内から読める前提で扱う
SANDBOX --registry HOST ホスト側+指定したサンドボックス VM 内から読める前提で扱う
レジストリ資格情報
# ホスト限定: テンプレート / Kit の取得用
$ gh auth token | sbx secret set --registry ghcr.io --password-stdin

# mybox 内の docker pull / push にも使わせる
$ gh auth token | sbx secret set mybox --registry ghcr.io --password-stdin
⚠️ v0.35.0 の説明に食い違いがある

ローカルの sbx secret set --help は全体向け / サンドボックス単位のレジストリ資格情報について 「プロキシが注入し、実値はサンドボックスに入らない」と説明する。一方、2026-07-20 時点の 公式の認証情報ドキュメント~/.docker/config.json に書かれ、エージェントから読めると明記している。 食い違いが解消するまではVM 内から読めるものとして扱い、全体向け(-g)を避け、対象サンドボックス限定・最小権限・短命の資格情報を使うのが安全。

⚠️ ヘッダ注入が効かない認証もある

この仕組みは HTTP ヘッダベースの認証(GitHub トークン等)にのみ有効。 AWS SigV4 のような署名ベースの認証はヘッダ注入では扱えないため、 従来どおり環境変数で渡すことになり、その分セキュリティは下がる(VM 内から値が見える)。 aws-vault で短命クレデンシャルを発行して渡すなどの緩和策を。

Clone モード — ホストの Git 作業ツリーを直接変更しない

通常はカレントディレクトリがホストと同じ絶対パスに読み書きマウントされるが、 --clone を付けるとエージェントはプライベートな Git クローンの中だけで作業する (virtiofs で実装。ホスト側は読み取り専用)。ファイル変更は VM 内に閉じるので、 成果は Git 経由(push や patch)で取り出す運用になる。ただし、許可済みの通信先と付与した資格情報を使った push、Issue / PR 更新、外部 API 操作までは防がない。

Clone モード
$ sbx run --clone --name fix-issue claude
📂 clone で「見える」範囲

対象になるのは、sbx run --clone を実行した起動ディレクトリ(プライマリワークスペース)配下だけ。 隣の兄弟ディレクトリや、その外側に置いた機密フォルダは clone 対象外で、VM からは見えない。 編集先は VM 内のプライベート clone。ホスト側の作業ツリーは読み取り専用の別マウントとしても VM 内に見えることがあるが、 そのパスは版によって異なりうる(断定しない)。ホスト側で直した内容は読み取り専用側に反映されうる一方、 clone 側への書き込みはホストの作業ツリーを直接は壊さない。成果物の回収は 応用。起動法の手順は 使い方のワークスペース節

  • Git リポジトリであることが必須
  • 作成後にモードは変更できない(clone ⇄ 通常マウントの切り替え不可)
  • ブランチは自動作成されない(エージェントに指示して切らせる)
  • メインの worktree 以外の Git worktree からは作成できない
  • sbx rm 前に必要なコミットを push / fetch するか、ファイルを sbx cp で回収する(push してホスト側で PR/MR を開く運用は、レビュー機能付きリモートがある場合。詳細は応用を参照)

2.注意点・制限事項


🛡 microVM が守ってくれるもの ✓ 作業フォルダ外のホストファイル・プロセス ✓ ホストの Docker 環境(イメージ・ボリューム) ✓ 未許可ドメインへの通信(デフォルトは拒否) ✓ プロキシ管理のサービス資格情報(実値) ✓ 生の TCP / UDP / ICMP(層ごと遮断) ⚠ 自分で締めるべきもの ✗ 許可済みドメインへ「何を」送るか ✗ 渡したトークンの権限の範囲内の操作 ✗ 環境変数で渡した認証情報(AWS 等) ✗ 直接マウントした作業フォルダへの変更 → 最小権限・短命トークン・許可は必要最小限に
隔離が肩代わりしてくれる範囲と、運用側の責任として残る範囲

日常で詰まったときの「症状 → 原因 → コマンド」は 使い方のよくある失敗へ。

  • Experimental 段階 — 破壊的変更が頻繁。sbx exec --env-file が動かない、 といった挙動もある(確認: sbx v0.35.0。後続版で直っている可能性があるので、使う前に再確認する)。 リリースノート(docker/sbx-releases)を追うこと。 一時的に旧版へ戻すなら brew install docker/tap/sbx@0.34.0 のようにピン留めできる(常用推奨ではない)。
  • シークレット注入は HTTP ヘッダ認証限定 — AWS SigV4 等の署名ベース認証は環境変数渡しになり、隔離の恩恵が薄れる。
  • レジストリ資格情報は別扱い — VM 内の Docker に使わせる資格情報は、サンドボックスから読める前提で範囲と権限を絞る。
  • ネットワークポリシーはドメイン粒度 — 「github.com のうち特定リポジトリだけ許可」のようなパス/リポジトリ単位の制限はできない。 public API でも広範に届きうるので、write の誤爆半径は GitHub App / 短命トークン / インストール先リポジトリ制限などトークン側で絞る(上の ghtkn 例と接続)。
  • 直接マウントは作業ツリーを隔離しない — 書き込みは即ホストへ反映され、.git/hooks など通常の差分に出ない変更もありうる。
  • clone モードは後から切り替え不可 — 作成時に決める。Git リポジトリ必須・ブランチ自動作成なし・メイン worktree 以外からは作成不可。
  • 削除前に成果を回収 — clone モードのサンドボックスを sbx rm すると VM 内のクローンも消える。必要なコミットやファイルを先に push・fetch・コピーする。
  • ディスク消費と掃除 — サンドボックスごとに VM、Docker イメージ / ボリューム、パッケージを保持し、イメージ層はサンドボックス間で共有しない。macOS では状態の多くが ~/Library/Application Support/com.docker.sandboxes/ 配下に置かれる(詳細は Architecture: Storage 参照)。 掃除の範囲を取り違えないこと:
    • 不要なサンドボックスを 1 つ消す → sbx rm <名前>
    • Docker Sandboxes の状態をすべて初期化する → sbx reset(取り消せない)
    • シークレットだけ残して初期化する → sbx reset --preserve-secrets
    sbx reset は実行中のサンドボックスとエージェントを止め、全サンドボックスと未回収の作業・イメージキャッシュ・内部レジストリ・ポリシー・保存済みシークレットを消し、ログアウトして常駐プロセスと設定・状態・キャッシュを取り除く。 あわせて、Docker 公式の AI アシスタント(Gordon。Docker Desktop や docker ai から使うもの)のセッションと履歴も消える。使っていなければ実害はない。 clone モードで残したい成果がある場合は、実行前に push / fetch / sbx cp で回収する。 sbx 自体を外すなら brew uninstall docker/tap/sbx のあと、残データディレクトリの要否を確認する。
  • 社内プロキシ — ホスト側の HTTP_PROXY / HTTPS_PROXY、または DOCKER_SANDBOXES_PROXY 経由で外へ出る。PAC ファイルは未対応。設定は常駐プロセス起動前に行い、変更後はデーモン再起動が必要なことがある (Architecture: Upstream proxy)。
  • 一つのリポジトリに複数パッケージがあるとき — サブディレクトリだけだと .git/ が見えない。ルートをマウントし作業ディレクトリを移す手順は 使い方
  • ライセンス — クローズドソース。現時点では Docker Desktop のライセンスなしで無料で商用利用可能とされるが、 組織向けガバナンス機能は有料。将来変わりうるので 公式ドキュメントと利用条件を都度確認する。
  • 万能ではない — microVM はホストを守るが、許可したドメインへの通信・渡したトークンの権限の範囲では エージェントは何でもできる。トークンは最小権限・短命に、許可ドメインは必要最小限に。

3.参考リンク・出典


主な情報ソース

公式ドキュメント・リポジトリ