
こんにちは。よっしーです(^^)
背景
この連載では、Claude Codeの公式ドキュメントを1ページずつ読み解いていきます。公式ドキュメントは情報が網羅されている分、「結局どの機能を、どんな場面で使えばいいのか」は自分で考える必要があり、読むのに意外と時間がかかります。そこで、私が実務で使うために読み込んだ内容を「使う場面→実例コード」の順に整理して残していくことにしました。専門家の解説というより、一次情報を読んだ記録です。推測や動作を確認していない部分には、その都度そう書きます。
公式ドキュメント:https://code.claude.com/docs/ja/agent-sdk/secure-deployment
1. 一言でいうと
Claude Code や Agent SDK のエージェントは、読み込んだ内容(ファイル、Web ページ、ユーザー入力)に影響されて、運用者が想定しない動きをすることがあります。このページは、その被害を小さくするための守り方を、「分離」「認証情報の管理」「ネットワークの制御」「ファイルシステムの制御」の4つの軸で整理したガイドです。中心にある考え方は、「エージェントがおかしくなっても、大事なもの(認証情報、外へのデータ送信の経路)はエージェントの手の届かない境界の外に置く」ことです。
第94回のホスティングで「サンドボックスの中で動かす」「秘密はコンテナの外で差し込む」「出ていく通信はエグレスプロキシに通す」と何度も出てきて、具体的な設定はこのページに回されていました。今回はその本体です。
2. どういう場面で役立つか
シーン1:信頼できない内容をエージェントに読ませる
他人のリポジトリ、外部から届いた文書、ユーザーがアップロードしたファイルをエージェントに処理させる場合です。原文の例では、リポジトリの README に異常な指示が書かれていると、Claude Code がそれを行動に取り込むことがあります。読ませる内容を選べないなら、読んだ結果としてできることを狭めておく必要があります。
シーン2:複数の顧客のデータを扱う
マルチテナントの環境で顧客データを処理する場合、1つのセッションが乗っ取られたときに、他の顧客のデータや共通の認証情報まで届いてしまうのが最悪の事態です。原文は、プロキシで認証情報を差し込む方式が「マルチテナントのデプロイや信頼できない内容を扱う場合に役立つ」と書いています。
シーン3:CI/CD でエージェントを無人で動かす
人が承認ボタンを押さない環境では、権限の確認だけに頼れません。原文は、単独の開発者や CI/CD の多くの用途では、後述の sandbox-runtime が少ない手間で大きな改善になると書いています。
不要・向かないケース
- すべての配置に最大限の守りが要るわけではない:原文自身が冒頭でそう断っています。開発者がノートパソコンで Claude Code を動かす場合と、企業が顧客データを扱う場合とでは要件が違います。手元での開発なら、権限システムやサンドボックスモードといった組み込みの機能(3-1)から始めれば足ります。
- このページだけで設定を完成させたい:このページは選択肢と考え方のガイドで、sandbox-runtime の設定ファイルの書き方、seccomp プロファイルの中身、Envoy の設定例などは載っていません。それぞれのツールのドキュメントに当たる必要があります。
3. コードと仕組みの解説
原文の fenced コードブロックは8本です(sandbox-runtime のインストール、強化した docker run、gVisor 用の daemon.json と実行コマンド、プロキシを指す環境変数2組、読み取り専用マウント、tmpfs の書き込み場所)。どれも1か所ずつで重複がないので全数を引用します。コードは原文から機械的に抜き出したもので、変えていません。
3-0. 前提条件とバージョン要件
原文には Claude Code や Agent SDK のバージョン要件の記載はありません。バージョンが出てくるのは1か所だけで、Node.js の fetch() に環境変数のプロキシ設定を読ませる NODE_USE_ENV_PROXY=1 が Node 24 以降という点です(3-6)。
ページ全体の大前提として、原文は次の注記を置いています。
- 以下のどの構成でも、Claude Code(または Agent SDK のアプリケーション)は分離の境界(サンドボックス、コンテナ、VM)の中で動く。 以下の制御は、エージェントがその境界の中から何に触れられるかを制限するものです。
3-1. 脅威モデルと組み込みの守り
何を恐れるのか
エージェントは、プロンプトインジェクション(処理する内容に埋め込まれた指示)か、モデルの誤りのどちらかによって、意図しない行動をとることがあります。原文は、Claude のモデルはこれに耐えるように設計されている(詳しくはモデル概要とシステムカード)としたうえで、それでも多層防御が良い習慣だと書いています。例として、顧客データを外部サーバーに送るよう指示する悪意あるファイルをエージェントが処理しても、ネットワークの制御があればそのリクエスト自体を止められます。
つまり、このページの考え方は「モデルが騙されないこと」に賭けず、「騙されても届かない」構造を作ることです。
Claude Code に最初から入っている4つの守り
| 機能 | 何をするか | 限界・補足 |
|---|---|---|
| 権限システム | ツールと bash コマンドごとに、許可・ブロック・ユーザーへの確認を設定。glob パターンで「npm コマンドはすべて許可」「sudo を含むコマンドはブロック」のようなルールを書ける。組織は全ユーザーに効くポリシーを設定できる | 詳細は第16回(permissions)、SDK では第80回 |
| 権限のためのコマンド解析 | bash コマンドを実行前に AST(構文木)に解析し、権限ルールと照合する。きれいに解析できないもの、許可ルールに一致しないものは明示的な承認が要る。eval などの少数の構文は、許可ルールに関係なく常に承認が要る | これは権限の関門であってサンドボックスではない。rm・rmdir の重要パスのチェックや保護パスのリストを除き、対象のパスや効果から「危険かどうか」を推測しない |
| Web 検索の要約 | 検索結果は生の内容をそのままコンテキストに入れず、要約して渡す | 悪意ある Web の内容によるインジェクションのリスクを下げる |
| サンドボックスモード | Bash コマンドを、ファイルシステムとネットワークへのアクセスを制限した環境で動かす | 詳細は第17回(sandboxing) |
表の「限界・補足」の列は筆者の整理です。2行目の「権限の関門であってサンドボックスではない」は、このページで最も大事な区別の1つです。権限ルールは「このコマンドの形を許すか」を判定するだけで、許されたコマンドが実際に何を壊すかは見ません。第80回で見た「Bash(rm *) は /bin/rm を捕まえない」のような話と同じ構図で、権限ルールだけでは、許可したコマンドの中身の悪用は止まらないので、以下の分離が必要になります(筆者の指摘)。
3-2. 3つの原則
組み込みの機能を越えて守りを固めるときの原則として、原文は3つを挙げています。
セキュリティ境界
信頼の度合いが違う部品を、境界で分けることです。守りを固めた配置では、認証情報のような機微な資源を、エージェントを含む境界の外に置きます。エージェントの環境で何かが起きても、境界の外の資源は守られたままです。
例として、エージェントに API キーを直接持たせる代わりに、エージェントの環境の外で動くプロキシがキーをリクエストに差し込みます。エージェントは API を呼べますが、認証情報そのものは見えません。
最小権限
エージェントを、そのタスクに必要な機能だけに絞ります。原文の表です。
| 資源 | 絞り方 |
|---|---|
| ファイルシステム | 必要なディレクトリだけをマウントし、読み取り専用を優先する |
| ネットワーク | プロキシ経由で特定のエンドポイントだけに制限する |
| 認証情報 | 直接見せず、プロキシ経由で差し込む |
| システムの機能 | コンテナ内の Linux ケーパビリティを落とす |
多層防御
守りの固い環境では、複数の制御を重ねます。選択肢は、コンテナによる分離、ネットワークの制限、ファイルシステムの制御、プロキシでのリクエストの検証です。どれを組み合わせるかは、脅威モデルと運用の要件で決まります。
3-3. 分離の技術を選ぶ
分離の技術は、強さ・性能・運用の手間のあいだで、それぞれ違う妥協をしています。原文の比較表です。
| 技術 | 分離の強さ | 性能のオーバーヘッド | 複雑さ |
|---|---|---|---|
| Sandbox runtime | 良好(安全な既定値) | 非常に低い | 低い |
| コンテナ(Docker) | 設定次第 | 低い | 中程度 |
| gVisor | 優秀(正しく設定すれば) | 中程度〜高い | 中程度 |
| VM(Firecracker、QEMU) | 優秀(正しく設定すれば) | 高い | 中程度〜高い |
「設定次第」「正しく設定すれば」という但し書きがあるとおり、技術を選んだだけでは強さは決まりません。以下、順に見ます。
(a) Sandbox runtime:コンテナなしの軽い分離
sandbox-runtime は、OS の機能でファイルシステムとネットワークの制限を強制します。最大の利点は簡単さで、Docker の設定もコンテナイメージもネットワーク設定も要りません。プロキシとファイルシステムの制限が組み込まれています。
| 対象 | 仕組み |
|---|---|
| ファイルシステム | OS の基本機能(Linux は bubblewrap、macOS は sandbox-exec)で、設定したパスへの読み書きを制限 |
| ネットワーク | Linux はネットワーク名前空間を外し、macOS は Seatbelt プロファイルを使って、通信を組み込みのプロキシ経由にする |
| 設定 | ドメインとファイルシステムのパスを JSON の許可リストで書く |
インストールは次のコマンドです。
npm install @anthropic-ai/sandbox-runtime
その後、許可するパスとドメインを書いた設定ファイルを作ります(設定ファイルの書式は原文に載っていません)。
原文は、セキュリティ上の注意を2つ挙げています。
- ホストのカーネルを共有する:VM と違い、サンドボックスの中のプロセスはホストと同じカーネルを使います。カーネルの脆弱性があれば、理論上は抜け出せます。脅威モデルによっては許容できますが、カーネル単位の分離が要るなら gVisor か VM を使います。
- TLS の中身を検査しない:組み込みのプロキシは、クライアントが示すホスト名でドメインを許可リストと照合するだけで、暗号化された通信を終端も検査もしません。そのため、サンドボックスの中のコードがドメインフロンティングのような手口で、許可リスト外のホストに届く可能性があります。より強い保証が要るなら、TLS を終端するプロキシ(3-6)を置きます。
2点目には続きがあります。許可したドメインに対して、エージェントが広い権限の認証情報を持っている場合、そのドメインを使って別のリクエストを起こしたりデータを持ち出したりできないようにする必要があります。許可リストは「どこに行けるか」を絞るだけで、「行った先で何ができるか」は絞らない、ということです。たとえば書き込み権限付きのトークンで GitHub を許可していれば、許可された GitHub そのものがデータの持ち出し先になりえます(例は筆者のもの)。
(b) コンテナ:強化した docker run
コンテナは Linux の名前空間で分離します。各コンテナはファイルシステム・プロセスツリー・ネットワークスタックを自分だけのものとして見ますが、ホストのカーネルは共有します。原文が示す、守りを固めたコンテナの設定です。
docker run \
--cap-drop ALL \
--security-opt no-new-privileges \
--security-opt seccomp=/path/to/seccomp-profile.json \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--tmpfs /home/agent:rw,noexec,nosuid,size=500m \
--network none \
--memory 2g \
--cpus 2 \
--pids-limit 100 \
--user 1000:1000 \
-v /path/to/code:/workspace:ro \
-v /var/run/proxy.sock:/var/run/proxy.sock:ro \
agent-image
各オプションの意味を、原文の表を日本語で整理します。
| オプション | 目的 |
|---|---|
--cap-drop ALL | NET_ADMIN や SYS_ADMIN のような、権限の昇格につながりうる Linux ケーパビリティを外す |
--security-opt no-new-privileges | setuid のバイナリを通じてプロセスが権限を得るのを防ぐ |
--security-opt seccomp=... | 使えるシステムコールを制限する。Docker の既定は約44をブロックし、独自のプロファイルでさらに絞れる |
--read-only | コンテナのルートファイルシステムを書き換え不可にし、エージェントが変更を残せないようにする |
--tmpfs /tmp:... | コンテナが止まると消える、書き込み可能な一時ディレクトリ |
--network none | ネットワークインターフェースをすべて外す。エージェントはマウントした Unix ソケット経由で通信する |
--memory 2g | メモリを 2GB に制限して資源の枯渇を防ぐ |
--pids-limit 100 | プロセス数を制限してフォーク爆弾を防ぐ |
--user 1000:1000 | root でないユーザーで動かす |
-v ...:/workspace:ro | コードを読み取り専用でマウントし、分析はできるが変更はできないようにする。~/.ssh・~/.aws・~/.config のような機微なホストのディレクトリはマウントしない |
-v .../proxy.sock:... | コンテナの外で動くプロキシにつながる Unix ソケットをマウントする |
コマンドにある --cpus 2 と --tmpfs /home/agent:rw,noexec,nosuid,size=500m は、原文の表に説明がありません。--cpus 2 は CPU の上限、/home/agent の tmpfs はホームディレクトリを書き込み可能な一時領域にするものと読めます(筆者の解釈)。第94回で見たとおり、SDK はセッションの記録をホームの下(~/.claude/projects/)に書くので、--read-only のコンテナでもホームを tmpfs にしておけば書けますが、コンテナを止めれば消えます。残したい記録は第93回の SessionStore で外に写すことになります(筆者の指摘)。
また、第94回は出発点の目安を「1 GiB の RAM」としていましたが、ここの例は --memory 2g です。どちらも例示で、実際の値は第94回の方法(ピーク時の RSS を測る)で決めます。
Unix ソケットの構成
--network none のコンテナにはネットワークインターフェースがありません。外の世界に届く唯一の道は、マウントした Unix ソケットで、それはホストで動くプロキシにつながっています。プロキシは、ドメインの許可リストを強制し、認証情報を差し込み、すべての通信を記録できます。
原文は、これが sandbox-runtime と同じ構成だと書いています。プロンプトインジェクションでエージェントが乗っ取られても、任意のサーバーにデータを持ち出せません。 通信はプロキシ経由でしかできず、届くドメインはプロキシが決めるからです。
なお、Claude Code がコンテナの中からこの Unix ソケットを使って API に届く具体的なつなぎ方(ソケットを HTTP プロキシとして見せる中継など)は、原文には書かれていません(筆者の指摘)。sandbox-runtime はこの部分を組み込みで持っている、という位置づけです。
追加の強化オプション
| オプション | 目的 |
|---|---|
--userns-remap | コンテナ内の root を、ホストの特権のないユーザーに対応づける。デーモンの設定が要るが、コンテナから抜け出されたときの被害を抑える |
--ipc private | プロセス間通信を分離し、コンテナをまたぐ攻撃を防ぐ |
(c) gVisor:システムコールを手前で受け止める
通常のコンテナはホストのカーネルを共有するので、コンテナ内のコードのシステムコールは、ホストを動かしているのと同じカーネルに直接届きます。カーネルに脆弱性があれば、コンテナから抜け出されるおそれがあります。
gVisor は、システムコールをユーザー空間で受け止め、ほとんどを本物のカーネルに渡さずに自前の互換層で処理します。エージェントが(たとえばプロンプトインジェクションのせいで)悪意あるコードを動かし、カーネルの脆弱性を突こうとしても、まず gVisor のユーザー空間の実装を破る必要があり、本物のカーネルへの経路は限られます。攻撃面がずっと小さくなる、ということです。
Docker で使うには、runsc ランタイムを入れてデーモンに登録します。
{
"runtimes": {
"runsc": {
"path": "/usr/local/bin/runsc"
}
}
}
そのうえで、ランタイムを指定してコンテナを動かします。
docker run --runtime=runsc agent-image
性能への影響は処理の種類で大きく違います。
| 処理 | オーバーヘッド |
|---|---|
| CPU を使う計算 | ほぼ 0%(システムコールの横取りがない) |
| 単純なシステムコール | 約2倍遅い |
| ファイル I/O が多い処理 | ファイルを大量に開いたり閉じたりする場合、最大10〜200倍遅い |
コーディングエージェントはファイルを読み書きし、ビルドやテストで多数のファイルを開くので、3行目に当たりやすい作業です(筆者の指摘)。原文は、マルチテナントの環境や信頼できない内容を扱う場合は、この追加の分離に価値があることが多いと書いています。
(d) 仮想マシン
VM は CPU の仮想化支援機能によって、ハードウェアの層で分離します。各 VM は自分のカーネルを動かすので、境界が強く、ゲストのカーネルの脆弱性がホストを直接脅かすことはありません。
ただし原文は、VM が自動的に gVisor などより「安全」なわけではないと注意しています。VM の安全性は、ハイパーバイザーとデバイスエミュレーションのコードに大きく依存するからです。
Firecracker は軽量なマイクロ VM の分離のための設計で、125ms 以下で起動し、メモリのオーバーヘッドは 5 MiB 未満、不要なデバイスエミュレーションを省いて攻撃面を減らしています。第94回の「エフェメラルなパターンは1秒未満の起動が必要」という条件にも収まる数字です(筆者の対応づけ)。
この構成では、エージェントの VM は外部のネットワークインターフェースを持たず、vsock(仮想ソケット)で通信します。すべての通信は vsock でホスト上のプロキシに送られ、プロキシが許可リストを強制し、認証情報を差し込んでから転送します。コンテナの Unix ソケットと同じ形です。
(e) クラウドでの配置
クラウドでは、上のいずれかの分離技術を、クラウドのネットワーク制御と組み合わせます。原文の手順は5つです。
- エージェントのコンテナを、インターネットゲートウェイのないプライベートサブネットで動かす
- クラウドのファイアウォールルール(AWS のセキュリティグループ、GCP の VPC ファイアウォール)で、プロキシ以外への送信をすべて止める
- リクエストを検証し、ドメインの許可リストを強制し、認証情報を差し込み、外部 API に転送するプロキシを動かす(例:
credential_injectorフィルター付きの Envoy) - エージェントのサービスアカウントには最小限の IAM 権限だけを与え、機微なアクセスはプロキシ経由にする
- 監査のため、プロキシですべての通信を記録する
どの分離技術でも共通する形は、「エージェントからの出口はプロキシ1つだけ。プロキシが行き先・認証情報・記録を握る」です(筆者のまとめ)。
3-4. 認証情報の管理:プロキシパターン
エージェントは、API を呼び、リポジトリにアクセスし、クラウドのサービスを使うために認証情報を必要とすることがよくあります。課題は、認証情報そのものを見せずに、アクセスだけを与えることです。
原文が推奨するのは、エージェントのセキュリティ境界の外でプロキシを動かし、出ていくリクエストに認証情報を差し込む方式です。エージェントは認証情報なしでリクエストを送り、プロキシが付け足して宛先に転送します。利点は4つです。
- エージェントは本物の認証情報を見ない
- プロキシが、許可するエンドポイントのリストを強制できる
- プロキシが、すべてのリクエストを監査のために記録できる
- 認証情報は各エージェントに配られず、1つの安全な場所に置かれる
3-5. Claude Code をプロキシ経由にする2つの方法
Claude Code は、モデルへのリクエスト(原文の言葉では「サンプリングリクエスト」)をプロキシに通す方法を2つ持っています。
方法1:ANTHROPIC_BASE_URL(簡単だが、モデル API へのリクエストだけ)
export ANTHROPIC_BASE_URL="http://localhost:8080"
Claude Code と Agent SDK は、Claude API に直接ではなく、このプロキシにリクエストを送ります。プロキシは暗号化されていない HTTP のリクエストを受け取るので、中身を検査・変更(認証情報の差し込みを含む)してから本物の API に転送できます。
方法2:HTTP_PROXY/HTTPS_PROXY(システム全体)
export HTTP_PROXY="http://localhost:8080"
export HTTPS_PROXY="http://localhost:8080"
Claude Code と Agent SDK はこの標準の環境変数に従い、すべての HTTP の通信をプロキシに通します。ただし HTTPS の場合、プロキシは暗号化された CONNECT トンネルを作るだけで、TLS を横取りしない限り、リクエストの中身を見ることも変えることもできません。
ANTHROPIC_BASE_URL | HTTP_PROXY/HTTPS_PROXY | |
|---|---|---|
| 対象 | モデル API へのリクエストのみ | すべての HTTP 通信 |
| プロキシから中身が見えるか | 見える(平文の HTTP で受け取る) | HTTPS は見えない(トンネルのみ)。TLS 終端が必要 |
| 認証情報の差し込み | できる | HTTPS では TLS 終端なしにはできない |
表は筆者の整理です。第94回の「ANTHROPIC_BASE_URL を設定して、コンテナの外でキーを差し込むプロキシ経由でモデルを呼ぶ」は、方法1のことです。
プロキシの選択肢
自作もできますし、既存のものも使えます。原文が挙げるのは次の4つです。
| プロキシ | 特徴 |
|---|---|
| Envoy Proxy | 本番品質。認証ヘッダーを足す credential_injector フィルターがある |
| mitmproxy | HTTPS の通信を検査・変更する、TLS 終端型のプロキシ |
| Squid | アクセス制御リスト付きのキャッシングプロキシ |
| LiteLLM | 認証情報の差し込みとレート制限を持つ LLM ゲートウェイ |
3-6. モデル API 以外のサービスの認証情報
エージェントは、モデル API のほかに、git のリポジトリ、データベース、社内 API などへの認証付きアクセスが必要になることがよくあります。原文は方法を2つ挙げています。
(a) カスタムツール
MCP サーバーやカスタムツールでアクセスを提供し、リクエストをエージェントのセキュリティ境界の外で動くサービスに回します。エージェントはツールを呼ぶだけで、認証付きの本当のリクエストは外で行われます。
原文の例では、git の MCP サーバーがエージェントからのコマンドを受け、ホストで動く git プロキシに転送し、そのプロキシがリモートのリポジトリにつなぐ前に認証を足します。エージェントは認証情報を見ません。
利点は2つで、TLS の横取りが要らない(外部のサービスが認証付きのリクエストを直接行う)ことと、認証情報が外に留まる(エージェントに見えるのはツールの窓口だけ)ことです。第83回の自作ツール、第84回の外部 MCP サーバーが、ここでは「認証情報を隠す壁」として使われています。
ただし、第83回で見たインプロセス MCP サーバー(createSdkMcpServer など)はアプリケーションと同じプロセスで動くので、そこに認証情報を持たせると、置き場所はエージェントのサブプロセスと同じコンテナの中になります。境界の外に置くという趣旨を守るなら、ツールの処理本体を境界の外のサービスに置く構成にする必要があります(筆者の指摘)。
(b) 通信の転送(TLS 終端プロキシ)
モデル API の呼び出しは ANTHROPIC_BASE_URL で平文のまま検査・変更できます。しかし GitHub、npm のレジストリ、社内 API のような他の HTTPS サービスは、通信が端から端まで暗号化されていることが多く、HTTP_PROXY でプロキシに通しても、プロキシには中身の見えない TLS トンネルしか見えず、認証情報を差し込めません。
カスタムツールを書かずに任意のサービスへの HTTPS 通信を変えたいなら、通信を復号し、検査・変更し、再暗号化して転送するTLS 終端プロキシが要ります。必要なのは3つです。
- エージェントのコンテナの外でプロキシを動かす
- プロキシの CA 証明書を、エージェントの信頼ストアに入れる(エージェントがプロキシの証明書を信頼するように)
HTTP_PROXY/HTTPS_PROXYを設定して通信をプロキシに通す
カスタムツールを書かずに HTTP ベースのサービスを扱えますが、証明書の管理が複雑になります。
環境変数を無視するプログラムがある
すべてのプログラムが HTTP_PROXY/HTTPS_PROXY に従うわけではありません。curl、pip、npm、git などほとんどは従いますが、変数を飛ばして直接つなぐものもあります。原文の例は Node.js の fetch() で、既定ではこの変数を無視します。Node 24 以降なら NODE_USE_ENV_PROXY=1 で対応を有効にできます。
変数を無視するツールには、proxychains でネットワーク呼び出しを横取りするか、iptables で外向きの通信を透過プロキシに向け直す方法があります。透過プロキシはネットワークの層で通信を横取りするので、クライアント側の設定が要りません。通常のプロキシはクライアントが明示的につなぎ、HTTP CONNECT か SOCKS で話す必要がありますが、透過プロキシ(Squid や透過モードの mitmproxy など)は、向け直された生の TCP 接続を扱えます。
どちらの方法でも、TLS 終端プロキシと信頼された CA 証明書は必要です。違いは、通信を確実にプロキシに届かせる手段だけです。
ここで、HTTP_PROXY だけで出口を絞った「つもり」の構成が抜けうることが分かります。変数を無視するプログラムは素通りするので、出口を強制するのは環境変数ではなく、--network none やファイアウォールのようなネットワーク側の仕組みであるべきです。3-3 のコンテナやクラウドの手順がネットワーク自体を断っているのはそのためだと読めます(筆者の指摘)。
3-7. ファイルシステムの設定
ファイルシステムの制御は、エージェントがどのファイルを読み書きできるかを決めます。
読み取り専用でマウントする
エージェントがコードを分析するだけで変更しないなら、ディレクトリを読み取り専用でマウントします。
docker run -v /path/to/code:/workspace:ro agent-image
原文はここに警告を置いています。読み取り専用でも、認証情報が漏れることはあるからです。マウントする前に除外するか中身を消しておくべき、代表的なファイルは次のとおりです。
| ファイル | リスク |
|---|---|
.env、.env.local | API キー、データベースのパスワード、シークレット |
~/.git-credentials | 平文の git のパスワード/トークン |
~/.aws/credentials | AWS のアクセスキー |
~/.config/gcloud/application_default_credentials.json | Google Cloud の ADC トークン |
~/.azure/ | Azure CLI の認証情報 |
~/.docker/config.json | Docker レジストリの認証トークン |
~/.kube/config | Kubernetes クラスターの認証情報 |
.npmrc、.pypirc | パッケージレジストリのトークン |
*-service-account.json | GCP のサービスアカウントキー |
*.pem、*.key | 秘密鍵 |
原文は、必要なソースファイルだけをコピーするか、.dockerignore のような形でふるい分けることを勧めています。読み取り専用は「書き換えられない」だけで「読まれない」わけではなく、読めたものはネットワーク経由で持ち出されうる、という点で 3-3 の出口制御と組み合わせて考える必要があります(筆者の指摘)。
書き込める場所
エージェントがファイルを書く必要がある場合、変更を残すかどうかで選択肢が変わります。
コンテナ内の一時的な作業場所なら、メモリ上にだけ存在しコンテナ停止で消える tmpfs を使います。
docker run \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--tmpfs /workspace:rw,noexec,size=500m \
agent-image
この例では /workspace が noexec 付きの tmpfs です。noexec はそのファイルシステム上のファイルを直接実行できなくする指定なので、エージェントが作業場所でビルドした実行ファイルや、実行権限を付けたスクリプトをそのまま動かす作業とは相性が悪い可能性があります(筆者の解釈。原文は noexec の影響に触れていません)。エージェントに何をさせるかに合わせて調整が要るでしょう。
それ以外の選択肢は次のとおりです。
| 目的 | 方法 |
|---|---|
| 消えてよい作業場所 | tmpfs マウント(上の例) |
| 残す前に変更を確認したい | オーバーレイファイルシステム。元のファイルを変えずに書け、変更は別の層に保存されるので、検査・適用・破棄を選べる |
| 完全に残す出力 | 専用のボリュームをマウントする。ただし機微なディレクトリとは分ける |
表は原文の記述を筆者がまとめたものです。オーバーレイは、第88回のファイルチェックポイントが Bash の変更を戻せないのに対し、ファイルシステムの層でまとめて捨てられる、という意味で補い合う関係にあります(筆者の対応づけ)。
4. まとめ
- エージェントは読んだ内容に影響される(プロンプトインジェクション)か、単に誤る。モデルの耐性に加えて多層防御で「騙されても届かない」構造を作る。ただし守りの強さは配置の要件に合わせて選ぶ。
- 組み込みの守りは権限システム・コマンド解析・Web 検索の要約・サンドボックスモード。コマンド解析は権限の関門であってサンドボックスではなく、許可したコマンドの効果は見ない。
- 原則はセキュリティ境界(機微な資源をエージェントの境界の外へ)・最小権限・多層防御。
- 分離は sandbox-runtime(簡単・カーネル共有・TLS 非検査)/コンテナ(設定次第)/gVisor(攻撃面が小さいがファイル I/O で最大10〜200倍遅い)/VM(強いがハイパーバイザー次第。Firecracker は 125ms 以下・5 MiB 未満)。
- 強化した
docker runは--cap-drop ALL・no-new-privileges・seccomp・--read-only・tmpfs・--network noneと Unix ソケットのプロキシ・メモリ/PID 制限・非 root・読み取り専用のコード。 - 出口はプロキシ1つにして、行き先・認証情報・記録をプロキシが握る。VM なら vsock、クラウドならプライベートサブネットとファイアウォール。
- 認証情報はプロキシで差し込む。モデル API は
ANTHROPIC_BASE_URLで平文のまま扱える。HTTPS_PROXYだけでは HTTPS の中身に触れない。 - 他サービスは、境界の外で動くカスタムツール/MCP サーバーか、TLS 終端プロキシ+CA 証明書。Node の
fetch()のように環境変数を無視するものがあるので、出口はネットワーク側で強制する。 - 読み取り専用のマウントでも
.envや~/.aws/credentialsなどは漏れる。マウント前に除く。書き込みはtmpfs・オーバーレイ・専用ボリュームを使い分ける。
次回予告
次回は 「可観測性」(agent-sdk/observability) を取り上げる予定です。
今回、プロキシですべての通信を記録して監査に使う、という守り方を見ました。第94回では、OpenTelemetry の環境変数を設定すると、エージェントのスパン・メトリクス・ログをコレクターに送れることにも触れています。次回は、エージェントの中で何が起きたか(どのツールが動き、どれだけ時間がかかり、どこで止まったか)を外から追うために、どんな情報がどの形で出てくるのか、プロンプトのような機微なデータの扱いをどう決めるのかを見ていきます。

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)

コメント