sandbox.network.tlsTerminateは資格情報マスクに必須のTLS終端設定
sandbox.network.tlsTerminateは組み込みプロキシにTLSを終端させる実験的設定です。mask資格情報置換に必須な理由と、リポジトリ設定では有効化できない仕様を公式ドキュメントから解説します。
sandbox.network.tlsTerminateは、サンドボックスの組み込みプロキシにTLSを終端させ、HTTPS通信の中身を読めるようにする設定です。既定ではオフで、通信のホスト名しか見ません。オンにすると、資格情報を実値と入れ替えるmask機能が動くようになります。実験的機能扱いで、Claude Code v2.1.199以降が必要です。
sandbox.network.tlsTerminateとは
サンドボックス化されたBashコマンドの通信は、Claude Codeが手元のマシンで動かす組み込みプロキシを経由します。このプロキシは既定では通信先のホスト名だけを見て許可・拒否を判定し、HTTPSの中身までは終端も検査もしません。sandbox.network.tlsTerminateをオンにすると、このプロキシ自身がTLSを終端し、リクエストの中身を読めるようになります。
設定値は2通りです。{}を指定すると、そのセッション限りの一時的な認証局(CA)がその場で生成されます。caCertPathとcaKeyPathを指定すれば、自分で用意したCA証明書と秘密鍵を使わせることもできます。どちらの場合も、サンドボックス内のコマンドが見るのはClaude Codeのプロキシが発行した証明書であって、接続先が本来持つ証明書ではありません。
{
"sandbox": {
"network": {
"tlsTerminate": {}
}
}
}設定方法 — 一時CAと自前CAの違い
一時CA({})はセッションごとに使い捨てられるため、証明書の管理コストがかかりません。反面、CAをどこかに固定して他ツールに信頼させたい場合には向きません。自前CAを使う構成は、caCertPathとcaKeyPathにファイルパスを指定します。
{
"sandbox": {
"network": {
"tlsTerminate": {
"caCertPath": "~/.claude/sandbox-ca.pem",
"caKeyPath": "~/.claude/sandbox-ca.key"
}
}
}
}複数の設定ソースがこの値を同時に指定した場合、Claude Codeはmanaged settings、次に--settingsフラグ、最後にuser settingsという優先順で1つを採用します。設定は上書きではなく置き換えです。ソースをまたいで値をマージすることはありません。
mask機能はなぜこの設定を要求するか
sandbox.credentials.filesやsandbox.credentials.envVarsに"mode": "mask"を指定できます。するとサンドボックス内のコマンドには、本物の代わりにプレースホルダー(sentinel)が見えます。許可したホストへ通信が出ていく瞬間だけ、プロキシがsentinelを実際の値に差し替えます。差し替えはリクエストの中身に対して行われます。
差し替えを行うには、プロキシがリクエストの中身を読める状態でなければなりません。tlsTerminateが要るのはこのためです。平文HTTPのテストネットワーク限定なら、代わりにallowPlaintextInjectを使う選択肢もあります。
設定を忘れても、資格情報が漏れるわけではありません。サンドボックス内のコマンドが見るのは相変わらずsentinelで、それがそのまま宛先に届いて認証が通らなくなるだけです。Claude Codeはこの設定ミスを起動時に報告します。
maskが効くまでの流れは次のとおりです。
maskが効くまでの流れ
- 1
信頼できる設定ソースに書く
tlsTerminateとmaskエントリは、user settings・managed settings・--settingsフラグのどれかに置きます。リポジトリの.claude/settings.jsonでは無視されます。 - 2
宛先を許可リストに入れる
プロキシが差し替えるのは、ドメイン許可リストを通った接続だけです。
injectHostsに書くホストは、allowedDomainsにも入っている必要があります。 - 3
injectHostsで実値の行き先を絞る
injectHostsを省くと、allowedDomainsのすべてのホストが差し替え対象です。許可リストの外へ実値を送る抜け道にはなりません。 - 4
injectHostsの書き間違いを確かめる
injectHostsの書き間違いはclaude doctorが警告します(後述)。
環境変数をmaskする最小構成は次のとおりです。GH_TOKENの実値はapi.github.com宛のリクエストにだけ差し込まれます。NPM_TOKENにはinjectHostsがないので、allowedDomainsのどのホストへ向かう通信でも差し替えが走ります。
{
"sandbox": {
"network": {
"tlsTerminate": {},
"allowedDomains": ["api.github.com", "registry.npmjs.org"]
},
"credentials": {
"envVars": [
{ "name": "GH_TOKEN", "mode": "mask", "injectHosts": ["api.github.com"] },
{ "name": "NPM_TOKEN", "mode": "mask" }
]
}
}
}ゲートウェイ経由のDesktop 3p構成では、allowedDomainsが反映されない例も報告されています(参考: Claude DesktopのallowedDomains無視issue)。
ファイルをmaskする場合は、プラットフォームで見える内容が変わります。この機能にはv2.1.221以降が必要です。
ファイルmaskの見え方
LinuxとWSL2
サンドボックス内のコマンドは、実値をsentinelに置き換えたコピーを読みます。外部への送信時に、プロキシが実値へ差し替えます。ここでtlsTerminateが要ります。
macOS
対象ファイルはサンドボックス内から一切読めず、denyと同じ扱いです。sentinelのコピーは作られないので、そのファイルで認証するツールは動きません。
効いているかは、サンドボックス内でcat ~/.config/gh/hosts.ymlのようにファイルを読ませると確かめられます。LinuxとWSL2ではトークンの位置にsentinelが出て、macOSでは読み取りが失敗します。extractパターンが何にも一致しなかった場合は、既定のonExtractNoMatch(warn)でエントリが読み飛ばされ、実ファイルがそのまま読めてしまいます。macOSでは、ファイルシステム分離をオフにしたときだけこの結果になります。オンのときは、パターンの照合より先にmaskがdenyとして適用されるためです。onExtractNoMatchの値はwarn・deny・errorの3つで、errorは設定を直すまでサンドボックスの準備を止めます。秘密が存在するのにパターンが外れうるときは、maskではなくdenyモードで隠します。
対象がディレクトリやglobパターン、8MiBを超えるファイル、UTF-8以外のテキストである場合、Claude Codeは安全にmaskできないと判断しdenyへフォールバックします。maskは1ファイルずつ書く必要があります。
値そのものではなく値から導出した署名で認証するリクエスト(AWSのSigV4署名付きリクエストなど)は、単純な差し替えでは済みません。プロキシ側での再署名が必要で、AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYをどちらもmaskしていれば自動で連携します。ただし、aws-chunkedのストリーミングアップロード・署名済みURL・SigV4Aの3形式はプロキシが再署名できません。これらがmask対象の資格情報で署名されていた場合は、credentials.sigv4でフォームごとにpassthroughを指定します。プロキシのエラーではなく、AWS側からの本来のエラー応答を受け取れるようになります。
リポジトリ設定でオンにできない理由
maskは本物の資格情報を許可ホストへ送信する権限をプロキシに与える機能です。そのためtlsTerminate・maskエントリ・allowPlaintextInjectは、あなたか管理者が制御できる設定ソースからしか読まれません。具体的にはuser settings・managed settings・--settingsフラグの3つです。プロジェクトの.claude/settings.jsonや.claude/settings.local.jsonに書いても無視されます。
管理者がサーバー管理設定(server-managed settings)でこれらを配布する場合は、利用者側に承認ダイアログが出ます。組織のポリシーとしてmaskを配りたいときは、この承認を前提に運用を組む必要があります。
運用に効く点が2つあります。利用者がこの設定を拒否すると、Claude Codeは終了します。またsandbox.credentialsやtlsTerminateへの承認は、同じ配布設定に入っているsandbox.network.allowedDomainsの項目もカバーします。管理者がその項目を足したり外したりすると、ダイアログがもう一度出ます。ダイアログは、次回の起動時か、実行中の対話セッションでは1時間以内に設定を取得したときに出ます。
設定ソースを--setting-sourcesなどで除外した場合の扱いも分かれます。プロジェクト設定とローカル設定のcredentialsエントリは丸ごと適用されません(v2.1.246以降)。user settingsを除外すると、denyエントリは残り、ファイルのmaskエントリは「実値の差し替えを許可しない制限」として残り、環境変数のmaskエントリは捨てられます。v2.1.287のclaude --helpでは、このフラグは--setting-sources <sources>(user, project, localのカンマ区切り)と出ます。--settings <file-or-json>はファイルパスかJSON文字列を受け取るので、tlsTerminateを試したいときは一時ファイルを指定する手があります。
機能が入ったバージョンと、うまく動かないときの確認先
mask関連の機能は、一度に揃ったわけではありません。tlsTerminateが入るv2.1.199より前の環境では使えません。
mask周りの機能が入ったバージョン
- v2.1.199tlsTerminateと環境変数のmask
プロキシがTLSを終端できるようになり、環境変数のmaskが使えます。
- v2.1.221ファイルmaskとSigV4の再署名
LinuxとWSL2でファイルのmaskが使え、AWSのSigV4リクエストをプロキシが再署名します。
- v2.1.224awsPairsとsigv4
AWSの資格情報が変数名の違うものに入っている場合の組み合わせ指定と、再署名できない形式の扱い指定が加わります。
- v2.1.229doctorのinjectHosts検査
宛先に一致しないIPv6アドレスの書き方を
claude doctorが警告します。 - v2.1.246プロジェクト設定のcredentials無視
設定ソースを除外したとき、プロジェクトとローカルの
credentialsを適用しません。
IPv6の宛先は、injectHostsには角括弧なしの圧縮形(::1)で書き、allowedDomainsとは書き方が異なります。違う書き方だと一致せず、claude doctorが次の警告を出します。
Sandbox credential injectHosts entries can never match their destination強制終了したセッションが残したsentinelのファイルもclaude doctorが検出します。v2.1.257より前は、同じファイルが警告なしに残りました。
httpProxyPortとの違いをどう使い分けるか
サンドボックスにはTLSやプロキシに関わる設定が複数あり、目的が異なります。tlsTerminateは、Claude Code自身の組み込みプロキシがTLSを終端する設定です。外部プロキシへ接続を差し替えるhttpProxyPortや、macOS固有のenableWeakerNetworkIsolationとは別物です。
| 設定 | 何をするか | スコープ | 主な用途 |
|---|---|---|---|
sandbox.network.tlsTerminate | 何をするか組み込みプロキシ自身がTLSを終端し、通信の中身を読む | スコープUser or managed | 主な用途mask資格情報置換 |
sandbox.network.httpProxyPort | 何をするか組織独自の外部プロキシに接続を差し替える | スコープAny file(条件付き) | 主な用途HTTPS検査・フィルタリング・ログ収集 |
sandbox.enableWeakerNetworkIsolation | 何をするかmacOSのシステムTLS信頼サービスへのアクセスを許可 | スコープAny file(条件付き) | 主な用途MITMプロキシ利用時のGo製CLI証明書検証 |
enableWeakerNetworkIsolationは、httpProxyPortでMITMプロキシと独自CAを使う構成向けの設定です。ghやgcloud、terraformのようなGo製CLIが、証明書検証で失敗するのを防ぎます。tlsTerminateとは目的も動く場所も違います。オンにすると、システムのTLS信頼サービス経由でデータを持ち出せる経路が新たに開くため、セキュリティを下げる代償を伴います。
組織の外側にあるプロキシへ単に転送したいだけなら、httpProxyPortではなくHTTPS_PROXY/HTTP_PROXY/NO_PROXYという環境変数を使う経路もあります。この場合もClaude Code側のドメイン許可リストが先に働き、許可された接続だけが上流プロキシへトンネリングされます。一方httpProxyPortは、組み込みプロキシの代わりに、同じマシン上で自分が動かすプロキシ(のローカルポート)を指定する設定です。組織がhttpProxyPortで独自プロキシを差し込む動機は主に次の3つです。
- HTTPS通信を復号して中身を検査する
- 組織独自のフィルタリングルールを適用する
- すべてのリクエストをログに残す
組織側の外部プロキシで通信全体を検査したいならhttpProxyPort、Claude Code自身のプロキシにmaskだけ動かしたいならtlsTerminate、というのが基本の切り分けです。ドメイン許可リストやfilesystem.disabledといった他のサンドボックス設定と同様、こちらも既定ではオフになっている点は共通しています。httpProxyPort・socksProxyPortの設定手順と確認方法はsandbox.network.httpProxyPortの記事にまとめています。
TLSを終端してもドメインフロンティングは防げない
tlsTerminateをオンにしても、それだけでサンドボックスの通信が全面的に検査されるわけではありません。公式ドキュメントは、この設定が追加するのはmask置換のためのTLS終端だけで、コンテンツフィルタリングは追加しないと明記しています。
ドメインの許可判定は、依然としてクライアントが名乗ったホスト名ベースで行われます。そのため、サンドボックス内のコードがドメインフロンティングのような手法を使えば、許可リスト外のホストに到達する余地が理論上は残ります。github.comのような広いドメインを許可リストに入れるほど、この余地は広がります。
より強い保証が必要な脅威モデルでは、tlsTerminateではなく「カスタムプロキシ」構成(httpProxyPort/socksProxyPort)を選ぶ方が筋が通っています。TLSを終端・検査するプロキシを動かし、その独自CA証明書をサンドボックス内にインストールする構成です。tlsTerminateはmask機能のための最小限の仕組みであって、通信全体を監査する仕組みではありません。公式ドキュメントも、TLSを意識したより強いネットワーク分離を「活発に開発が進んでいる領域」と位置付けています。今のtlsTerminateはその途中にある実験的な機能で、恒久的な仕様として固定されたものではありません。この線引きを取り違えると、設定した安心感だけが先に立ってしまいます。
サンドボックスが分離するのはBashサブプロセスの通信だけという点も、設計の射程を見るうえで押さえておく価値があります。Read・Edit・Writeといった組み込みファイルツールは、サンドボックスを経由せず権限システムを直接使います。サブエージェントは親セッションと同じプロセスで動きます。そのため親セッションでサンドボックスが有効なら、サブエージェント内のBashコマンドにもtlsTerminateを含む同じ設定がそのまま適用されます。
まとめ — tlsTerminateが必要になる場面
sandbox.network.tlsTerminateが要るのは、sandbox.credentialsでmaskモードの資格情報保護を使いたい人だけです。denyで足りるならこの設定は要りません。maskを使うなら、tlsTerminateをuser settings・managed settings・--settingsのどれかに置きます。通信全体の検査まで求めるなら、見る先はhttpProxyPortのカスタムプロキシです。