Claude Codeの認証情報マスキングをサンドボックスで設定する方法
Claude Codeのsandbox.credentialsで、環境変数とファイルの認証情報をmode:"mask"で保護する設定を、JWTデコードとAWS SigV4再署名まで含めて解説します。
Claude Codeのサンドボックスは、sandbox.credentialsという設定でファイルと環境変数の認証情報を保護します。単純に読み取りを拒否するmode: "deny"に加えて、v2.1.199以降は環境変数を、v2.1.221以降はファイルを、実際の値を隠したまま外部通信だけ通すmode: "mask"で扱えます。v2.1.224ではJWTのデコードやAWSのSigV4署名の再計算まで対応が広がりました。この記事では、denyとmaskの使い分けから、AWS認証情報の再署名までを設定例つきで確認します。
Claude Codeの認証情報マスキングとは何か
認証情報マスキングとは、サンドボックス化されたコマンドに秘密情報の実値を見せず、通信が許可済みのホストへ出る瞬間だけ実値に差し替える仕組みです。sandbox.credentialsのfilesとenvVarsに、対象のパスや変数名とmodeを書きます。
mode: "deny"は単純です。ファイルの読み取りを拒否し、環境変数を実行前に外します。~/.aws/credentialsやGITHUB_TOKENを丸ごと使わせたくない場合に向いています。ただしghやnpmのように認証情報で実際に通信するツールは、denyだと認証自体ができず動かなくなります。
mode: "mask"はここを埋めます。サンドボックス内のコマンドにはセンチネル(sentinel、偽の値)を見せ、サンドボックスのプロキシが許可済みホストへの通信でだけ実値に差し替えます。コマンドとそのログには、実際の認証情報が一度も渡りません。
サンドボックスの既定動作を知っておくと、この設定の必要性がわかります。書き込みは作業ディレクトリとセッション一時ディレクトリに絞られますが、読み取りは~/.aws/credentialsや~/.ssh/を含め、コンピューター全体がほぼそのまま許可されています。sandbox.credentialsで明示的に列挙しない限り、これらのファイルはサンドボックス内のコマンドから素通しです。
sandbox.credentialsに組み込みの拒否リストはありません。列挙したファイルと変数だけが保護対象になります。サンドボックス設定全体の書き方はClaude Codeの設定完全ガイドにまとめてあります。
環境変数の認証情報をマスキングする設定
環境変数のmaskは、network.tlsTerminateを設定したうえでcredentials.envVarsにmode: "mask"を書くと有効になります。プロキシが暗号化通信の中身を書き換えるため、TLSを終端する設定が要ります。設定を忘れると、コマンドはセンチネルしか見ないまま、センチネルがそのままサーバーへ届いて認証に失敗します。この設定漏れはClaude Codeが起動時に警告します。
{
"sandbox": {
"enabled": true,
"network": {
"tlsTerminate": {},
"allowedDomains": ["*.github.com", "registry.npmjs.org"]
},
"credentials": {
"envVars": [
{ "name": "GH_TOKEN", "mode": "mask", "injectHosts": ["api.github.com"] },
{ "name": "NPM_TOKEN", "mode": "mask" }
]
}
}
}GH_TOKENはinjectHostsでapi.github.comだけに絞り、NPM_TOKENはinjectHostsを省略しているためnetwork.allowedDomainsに列挙した全ホストへ実値が届きます。injectHostsに書くホストは、allowedDomains側にも含めておく必要があります。
同じ変数にdenyとmaskが別スコープで重なると、denyが優先されます。
ファイルの認証情報をマスキングする設定
ファイルのmaskはv2.1.221で追加されました。LinuxとWSL2では、実ファイルの代わりにセンチネルへ置き換えたコピーを読ませ、外部通信の時点でプロキシが実値に差し替えます。macOSでは事情が違います。指定したファイルはそもそも読めなくなり、denyと同じ結果になります。
{
"sandbox": {
"enabled": true,
"network": {
"tlsTerminate": {},
"allowedDomains": ["*.github.com"]
},
"credentials": {
"files": [
{
"path": "~/.config/gh/hosts.yml",
"mode": "mask",
"extract": "oauth_token:\\s*(\\S+)",
"injectHosts": ["api.github.com"]
}
]
}
}
}extractは正規表現でファイルの中の秘密部分だけを狙い撃ちします。キャプチャグループ1が捕まえた範囲だけがセンチネルに置き換わるため、hosts.yml自体はghが引き続きパースできる形のまま残ります。extractを省略すると、ファイル全体が1個のセンチネルに置き換わります。単一の秘密しか持たないファイル向けの挙動です。
ファイル向けの設定はClaude Code v2.1.221のリリースノートにも整理されています。
JWTや構造化データだけを部分的にマスキングする
環境変数やファイルの値がJSON Web Token(JWT)であるとき、decode: "jwt"を指定すると挙動が変わります。Claude Codeは値がJWTであることを検証したうえで、構造だけ本物と同じ偽トークンに置き換えます。サンドボックス内でトークンをデコードして中身を読むコードも、そのまま動き続けます。
maskClaimsを添えると、ペイロードの特定のクレームだけを隠せます。指定していないクレームはそのまま読めるので、必要な情報だけ残す調整が可能です。
decodeとextractの併用ルールは、環境変数とファイルで異なります。環境変数向けのdecode: "jwt"はextractと併用できず、マッチする候補が見つからない場合は警告付きで元の値のまま素通しします。一方ファイル向けは、extractで正規表現によりJWTらしき部分を絞り込んだうえでdecode: "jwt"と組み合わせて使えます。ファイル向けのonExtractNoMatchはwarn・deny・errorの3択で、候補が見つからないときの挙動を選べる仕様で、環境変数のように強制的に素通しされるわけではありません。
DATABASE_URLのような構造化された値にはextractが使えます。接続文字列全体は残しつつ、パスワード部分だけを正規表現で狙い撃ちしてマスキングします。ただし環境変数向けのextractとdecode: "jwt"はv2.1.224からの対応です。ファイル向けのextractはv2.1.221から使えていたので、環境変数側は一歩遅れて追いついた形です。
AWSのSigV4署名をマスキングと両立させる
AWSのリクエストは、認証情報そのものではなく認証情報から導いたSigV4署名で認証します。値をそのままマスキングすると、署名の計算に使われた元の値とセンチネルが食い違い、署名が壊れてリクエストが失敗します。
この問題を解くのがawsPairsです。AWS_ACCESS_KEY_ID・AWS_SECRET_ACCESS_KEY・AWS_SESSION_TOKENという定番の変数名をまるごとマスキングしていれば、Claude Codeは自動でひとつの認証情報として紐づけます。変数名が違う場合だけ、awsPairsで明示的に組にします。
{
"sandbox": {
"credentials": {
"awsPairs": [
{
"accessKeyIdVar": "MY_KEY_ID",
"secretAccessKeyVar": "MY_SECRET_KEY",
"sessionTokenVar": "MY_SESSION_TOKEN"
}
]
}
}
}プロキシはアクセスキーのセンチネルからSigV4リクエストだと検知し、実値に差し替えたうえで署名を計算し直します。シークレットだけをマスキングしてアクセスキーIDを平文のまま残すと、プロキシが検知できず署名の壊れたリクエストがそのままAWSへ届いて失敗します。
再署名できないリクエスト形式も3つあります。
| リクエスト形式 | sigv4のキー | 再署名できない理由 |
|---|---|---|
| aws-chunkedのストリーミングアップロード | sigv4のキーstreaming | 再署名できない理由各チャンクの署名が先頭の署名から連鎖しており、本文の書き換えが必要になる |
| Presigned URL | sigv4のキーpresigned | 再署名できない理由署名がURL自体に埋め込まれ、Authorizationヘッダーを持たない |
| SigV4A(非対称署名) | sigv4のキーsigv4a | 再署名できない理由共有鍵によるHMACの再計算ができない |
credentials.sigv4で各形式をpassthroughに設定すると、プロキシはエラーで止めずセンチネル込みのまま転送します。呼び出し元のツールは、プロキシのエラーの代わりにAWS自身の認証エラーを受け取ります。これらの詳細はClaude Code v2.1.224のリリースノートにもまとまっています。
バージョンごとの対応表 — deny専用からSigV4再署名まで
sandbox.credentialsは一度に完成した機能ではありません。4回のバージョンにまたがって少しずつ範囲が広がってきました。
| バージョン | 追加された内容 |
|---|---|
| v2.1.187 | 追加された内容sandbox.credentialsを新設。files/envVarsのmode: "deny"で読み取り・環境変数を遮断 |
| v2.1.199 | 追加された内容envVarsにmode: "mask"を追加。network.tlsTerminate(実験的)でプロキシが実値へ差し替え |
| v2.1.221 | 追加された内容filesにmode: "mask"を追加(Linux/WSL2限定)。files向けextractで部分マスクに対応 |
| v2.1.224 | 追加された内容envVars向けextract・decode: "jwt"・maskClaims・awsPairs・sigv4を追加 |
設定のキー自体は早い段階からあっても、実際に使える機能は版によって違います。導入前に手元のバージョンを確認しておくと安全です。
claude --versiondeny/maskはどちらを選ぶべきか
同じsandbox.credentialsでも、denyとmaskのどちらを選ぶかで結果が変わります。判断の軸は、そのツールが認証情報を使って実際に通信する必要があるかどうかです。
| シーン | 推奨 | 理由 |
|---|---|---|
| SSH秘密鍵などツール自体を動かさせたくない秘密 | 推奨deny | 理由読み取りをそもそも拒否する。壊れる心配がない |
ghやnpmなど認証情報で実際に通信するツール | 推奨mask | 理由センチネルに差し替えつつ、許可ホストへは実値で届く |
| AWS CLIなどSigV4で署名するツール | 推奨mask + awsPairs | 理由署名の再計算まで自動化される |
| JWTを内部でデコードして検証するツール | 推奨mask + decode: "jwt" | 理由構造を保った偽トークンで検証ロジックが動き続ける |
| macOSでファイルの認証情報を扱う場合 | 推奨実質deny相当 | 理由ファイルのmaskはLinux/WSL2限定で、macOSは読み取り自体を拒否する |
迷ったときはdenyから始め、ツールが動かなくなった箇所だけmaskに切り替える進め方が手堅いです。すべてをmaskにすると、network.tlsTerminateのような追加設定が必要な箇所が増えます。
設定前に確認すべき落とし穴
ディレクトリ・globパターン・8MiB超のファイル・UTF-8以外のテキストは安全にマスクできないため、maskを指定しても自動でdenyにフォールバックします。狙った保護になっているかは、実際に読ませて確かめるのが確実です。
cat ~/.config/gh/hosts.ymlサンドボックス化したコマンドにこのコマンドを実行させると、Linux・WSL2ではセンチネル値が表示されます。設定が意図通りに効いているかを確かめる簡単な方法です。
OSレベルのmaskではなく実行環境ごとホストから切り離したい場合は、DevContainerでの隔離という選択肢もあります。
よくある質問
"mask"と"deny"はどちらを優先しますか
同じ変数やパスに両方が別スコープで指定された場合はdenyが優先されます。安全側に倒す設計のため、denyはどのスコープからでも追加して保護を強化できますが、他のスコープが追加したdenyをmaskで緩めることはできません。
JWTをマスキングすると中身は読めますか
decode: "jwt"単体では、構造の正しい偽トークンに丸ごと置き換わるため中身は読めません。特定のクレームだけ残したい場合はmaskClaimsで対象を絞り、それ以外のクレームは元の値のまま読める状態にできます。
maskで通信は遅くなりますか
network.tlsTerminateでプロキシがTLSを終端し、リクエストの中身を書き換えるため、素通しのプロキシより処理は増えます。公式ドキュメントに具体的な遅延の数値は示されていません。体感差が気になる場合は、対象を絞ってから運用に乗せる進め方が無難です。
macOSでファイルmaskが使えないのはなぜか
macOSのサンドボックスはSeatbeltというOS機能を使っており、Linux/WSL2でセンチネルコピーを用意しプロキシ側で実値に差し替えるbubblewrap前提の仕組みとは実装が異なります。ただし、フィルタシステム分離をオフにしている場合に限り、macOSでもextractやdecodeの指定が効きます。
まとめ
sandbox.credentialsは、v2.1.187のdenyから始まり、v2.1.199で環境変数のmask、v2.1.221でファイルのmask、v2.1.224でJWTデコードとAWS SigV4の再署名まで機能を広げてきました。
ツールが認証情報を使って通信する必要があるかどうかでdenyとmaskを使い分け、AWSやJWTのような構造化された値には専用のオプションを組み合わせます。設定はユーザー設定・管理設定・--settingsからしか効かない点と、macOSではファイルのmaskがdeny扱いになる点を、書く前に押さえておくと迷いません。
関連する記事
Claude Code をもっと見る →Claude Code(クロードコード)とは — CLI起点のエージェント型開発ツール
Claude Code v2.1.187 — サンドボックスの秘密情報読み取りを止め、組織がモデルを制限可能に
Claude Codeセキュリティ・権限ガイド — 個人 / チーム / 企業の3レイヤー別に実装推奨値を提示
Claude Codeのサンドボックス設計 — プロンプトインジェクションを前提に承認疲れを84% 減らす二層分離
Claude Codeの利用上限 — 6つのメッセージの見分け方とプラン別の対処
Claude Codeショートカット一覧 — 既定操作とkeybindings.jsonでのカスタマイズ