認証情報とワイヤ境界
エージェント型コーディングセッションには認証情報が必要です。Claude と通信するための Anthropic キー、プッシュするための GitHub トークン、デプロイするための AWS キーなどです。同時にこの環境は、任意のコードを実行し、任意のパッケージをインストールし、自らが書いたわけではないファイルの指示に従います。そのような環境に本物のシークレットを渡すことこそ、キーが窃取マルウェアの受信箱に流れ着く原因になります。
Bromure Agentic Coding はこの緊張関係をワイヤ境界によって解決します。VM 内のエージェントが目にするのは、常に偽のプレースホルダートークンだけです。本物の認証情報は macOS ホスト上に暗号化されて保管され、ホスト側の MITM プロキシによって、可能な限り最後の瞬間に — リクエストが VM を離れた後、かつその認証情報が属するホスト宛てである場合に限って — ワイヤ上で差し替えられます。VM 内のファイル、環境変数、プロセスのいずれも、本物の API キー、OAuth トークン、AWS シークレット、SSH 秘密鍵を保持することは決してありません。
本章では、この仕組みを端から端まで説明したうえで、サポートされるすべての認証情報の種類とそのライフサイクル、利用ごとの承認システム、侵害検出器、そして境界を自分で検証する方法を順に見ていきます。
メモ: 本章では概念と実行時の挙動を扱います。設定ペインのフィールドごとのリファレンスについては、設定 → 認証情報を参照してください。
ワイヤ境界の概要
このモデルは 3 つの原則で定義されます。
- VM 内は偽物。 設定したすべての認証情報は、VM 内では構造を保持した偽物に置き換えられます。偽物はバリデーターが期待する形状を保ちます — Anthropic の偽物は
sk-ant-api03-brm-で始まり、GitHub の偽物はghp_に 36 文字が続きます — そのためclaude、gh、doctlのようなツールは問題なくそれらを受け入れます。 - 本物はワイヤ上のみ。 VM が行うすべての HTTPS リクエストはホストプロキシへトンネリングされ、プロキシがそれを復号し、偽物を本物の値に差し替え、上流へ向けて再暗号化します。差し替えは、その認証情報が発行された宛先ホストに限定されます。
- フェイルクローズ。 何かがプロキシを迂回した場合、そのリクエストは偽物しか運ばず、上流での認証は失敗します。本物のシークレットが偶発的に漏洩する経路は存在しません。
偽物は決定論的です。各偽物は、本物の値とインストールごとの 32 バイトのソルトから HKDF-SHA256 によって導出されます。同じ本物のキーは、あなたの Mac 上で常に同じ偽物にマッピングされるため、キーをフィンガープリントするクライアント(たとえば Claude Code はキーのハッシュをキャッシュします)は、セッションをまたいで認証情報が「ローテーション」するのを目にすることはありません。
| 認証情報 | VM 内での偽物の形状 |
|---|---|
| Anthropic API キー | sk-ant-api03-brm-… |
| OpenAI API キー | sk-brm-… |
| xAI API キー | xai-brm-… |
| GitHub トークン | ghp_ + 36 文字(合計 40) |
| GitLab トークン | glpat- + 20 文字 |
| DigitalOcean PAT | dop_v1_ + 16 進(合計 64 文字) |
| Linear API キー | lin_api_ + 40 文字(合計 48) |
| MCP ベアラートークン | brm-mcp_… |
| Docker レジストリパスワード | brm-docker-…(最低 40 文字) |
| Kubernetes ベアラートークン | brm-k8s-… |
| データベースシークレット | brm-db-…(最低 32 文字) |
| 汎用の手動トークン | brm_… |
この境界にオン/オフのスイッチはありません。プロキシは VM の唯一の egress 経路であり、差し替えは単にこのアプリにおける認証情報の動作方式そのものです。
差し替えが端から端までどう機能するか
認証されたリクエスト 1 件の完全な往復は次のとおりです。
- セッション起動 — トークンプラン。 ワークスペース VM が起動すると、アプリは各本物の認証情報をその導出された偽物と対応づけた、ワークスペースごとのトークンプランを構築します。偽物は VM 内に書き込まれます。すなわち環境変数(
ANTHROPIC_API_KEY、GH_TOKEN、LINEAR_API_KEYなど)と設定ファイル(~/.git-credentials、~/.docker/config.json、~/.kube/config、~/.aws/config、~/.config/doctl/config.yaml、MCP 設定)です。本物の値は、それぞれが属する宛先ホストをキーとして、プロキシのインメモリの差し替えマップに読み込まれます。 - リクエストが VM を離れる。 ゲストの HTTPS トラフィックは、virtio ソケット(vsock ポート 8443)を経由してホストプロキシへトンネリングされます。VM にはネットワークへの他の経路はありません。
- TLS 終端。 プロキシは、偽造されたホストごとのリーフ証明書 — CN および SAN として宛先ホスト名、ホストごとの EC キー — を提示し、これは Bromure Agentic Coding Root CA によって署名されています。この CA の公開証明書は起動時に VM のトラストストアにインストールされているため、ゲストの TLS クライアントは接続を受け入れ、プロキシは平文のリクエストを読み取ることができます。
- 差し替え。 プロキシはリクエスト(ヘッダー、およびオプトインした認証情報の種類についてはボディ)に現れるすべての偽トークンを探し、宛先ホストがその認証情報のスコープと一致すれば、それを本物の値に置き換えます。
- 上流への再暗号化。 書き換えられたリクエストは、Apple の
URLSession、すなわち macOS 自身の TLS スタックを介して本物の宛先へ再送出され、それが上流サーバーの本物の証明書を検証します。レスポンスはトンネルを通ってゲストへストリーミングで戻ります。
宛先が偽物のスコープと一致しない場合、偽物はそのまま送出され(そして上流の認証に失敗し)— あるいは、その不一致が持ち出しのように見える場合、リクエストは即座にブロックされます(以下の侵害検出器を参照)。
Bromure Agentic Coding Root CA
CA はインストールごとに存在し、~/Library/Application Support/BromureAC/ca/(cert.pem とモード 0600 の key.pem)に置かれています。そのサブジェクトは「Bromure Agentic Coding Root CA」、組織は「Bromure」です。知っておくと役立つ特性は次のとおりです。
- CA の有効期間は 10 年です。偽造されたホストごとのリーフ証明書は有効期間 1 年で、24 時間さかのぼって日付が設定されているため、サスペンド/レジューム中に時刻がずれたゲストでも受け入れられます。リーフはアプリのプロセスが生きている間、ホストごとにキャッシュされます。
- 公開証明書は起動時にすべての VM のトラストストアにインストールされます(メタ共有を通じて配信され、
update-ca-certificatesで適用されます)。それはあなたのマシンを離れることはなく、あなたの VM 以外の何ものにも信頼されません。 - CA をローテーションするには、アプリを終了して
ca/ディレクトリを削除します。次回の起動時に新しい CA が発行され、各 VM は次回の起動時に新しい公開証明書を取り込みます。ローテーションはそれ以外の何も無効化しません — ワークスペースのシークレットとprofile.jsonのメタデータはそのまま保たれます。
ホストスコーピング
各差し替えエントリはホストスコープに束縛されます。マッチングは完全一致またはサブドメインで、大文字小文字を区別せず、部分文字列では決してマッチしません。openai.com にスコープされた認証情報は api.openai.com にはマッチしますが openai.com.evil.example にはマッチしません — 見た目のよく似たホストが、プロキシを騙して本物のキーでリクエストを飾らせることはできません。手動トークンのルールは、意図的に空白のホストフィルターを使うことができ、それは「任意のホストで注入する」ことを意味します。それはエントリごとにあなたが行う明示的な選択です(汎用 API キーを参照)。
構造としてのフェイルクローズ
この設計は、秘匿性のためにプロキシが不可避であることに決して依存しません — シークレットがそこに存在しないことに依存します。
- 何らかの形でプロキシをスキップしたリクエストは偽トークンを運びます。上流の API はそれを拒否します。
- VM 内で署名された AWS リクエストは偽のシークレットキーで署名されます。それらが AWS に直接到達した場合、
InvalidSignatureExceptionで失敗します(以下の AWS を参照)。 - SSH 秘密鍵のバイト列は VM 内にはまったく存在しません。境界を越えるのは署名だけです。
ワークスペースエディタで認証情報を管理する
認証情報はワークスペースごとに設定します。ワークスペースのエディタ(ワークスペースを編集)を開き、サイドバーで認証情報を選択します。
このペインは、まず Git アイデンティティ(VM 内の ~/.gitconfig に書き込まれる名前とメールアドレス。git のデフォルトを保つには両方を空白のままにします — プレースホルダーは単なる例であり、認証情報ではありません)で始まり、続いてあなたが設定した認証情報だけのリストが、カテゴリ見出し(エージェント、Git、Cloud、Databases、SSH、Other)の下にグループ化されて表示されます。下部には 2 つのボタンがあります。認証情報を追加は認証情報の種類のピッカー — Git トークン、SSH キー、AWS 認証情報、DigitalOcean トークン、Linear API キー、Kubernetes、コンテナレジストリ、Database、その他の API キー — を開き、env ファイルをインポート…は .env や ~/.bashrc から一括インポートします。プライマリエージェント自身のキーはエージェントペインにあり、次に説明します。保存をクリックします。次のセッション起動時に、偽物が VM に書き込まれ、本物がプロキシに読み込まれます。
認証情報ごとの承認ゲート(使用前に確認)と、各サービスの書き込みポリシーは、ここではなくガードレールペインで設定します — 認証情報ペインはもはやそれらのコントロールを持ちません。フィールドごとのリファレンスについては設定 → 認証情報を参照してください。
6 つのプロバイダーは自動処理されます — Anthropic、OpenAI、GitHub、GitLab、DigitalOcean、Kubernetes は手動のトークンルールを必要とせず、それぞれの専用セクションで扱われます。それ以外はすべてその他の API キーを通じて処理します。
env ファイルからのインポート。 **env ファイルをインポート…**は、既存の .env ファイル — あるいは ~/.bashrc — を読み込み、その変数を認証情報に変換します。パーサーは KEY=VALUE と export KEY=VALUE を扱い、囲みの引用符と末尾のコメントを取り除き、シェルによる評価が必要になるもの($VAR の展開や $(…) の置換)は意図的にスキップするため、本物の .bashrc を指定しても安全です。続いてレビューシートが、マスクされた値とともに変数を表示します。認識された名前(ANTHROPIC_API_KEY、OPENAI_API_KEY、XAI_API_KEY、GH_TOKEN/GITHUB_TOKEN、GITLAB_TOKEN、AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN、DIGITALOCEAN_ACCESS_TOKEN、LINEAR_API_KEY)はそれぞれの認証情報の種類に自動マッピングされ、認識されない名前は、あなたが指定するカンマ区切りのホストスコープとともに汎用の手動トークンとしてインポートできます。すでに設定済みのエントリはフラグが立てられ、チェックが外された状態のままになるため、再インポートがシークレットを黙って上書きすることはありません。
認証情報の種類
プライマリエージェントの API キー(Anthropic、OpenAI、xAI)
ワークスペースのプライマリエージェント用のキーはエージェントペインで設定します。ここでは各エージェントカードが認証モードのセレクターを提供します。
API トークンを選び、キーをフィールドに貼り付けます(Claude Code では Anthropic API キー、Codex では OpenAI API キー、Grok Build では xAI キー)。ライフサイクルは次のとおりです。
- VM 内:
ANTHROPIC_API_KEY/OPENAI_API_KEY/XAI_API_KEYとしてエクスポートされ、プロバイダーの形状の偽物(sk-ant-api03-brm-…、sk-brm-…、xai-brm-…)を保持します。 - ワイヤ上: プロバイダーのホスト(それぞれ
anthropic.com、openai.com、x.ai)へのリクエストで本物のキーに差し替えられます。 - 承認: 各セッションでの最初の使用をゲートするには、ガードレールペインでエージェントのキーの使用前に確認をオンにします(利用ごとの承認を参照)。デフォルトではオフです。
セレクター上の他の認証モード — サブスクリプション(インタラクティブログイン)、Bedrock(AWS)、ローカルモデル — については以下およびローカルモデルで扱います。CLI からは、同じ選択が bromure-cli workspaces create の --auth token|subscription|bedrock|local(およびその場限りのワークスペース向けの bromure-cli vm run では token|subscription|bedrock)に対応します。
Claude、Codex、Grok のサブスクリプション
API キーではなく Claude、ChatGPT(Codex)、Grok のサブスクリプションをお持ちの場合、エージェントは通常インタラクティブな OAuth ログイン — サンドボックス化された VM では本物のトークンで完了できない(し、すべきでもない)ブラウザフロー — によって認証します。Bromure Agentic Coding は 2 つの仕組みでサブスクリプションをサポートします。どちらも同じ地点に行き着きます。本物の OAuth トークンはホスト上にのみ存在し、ゲストはダミーキーで動作します。
Claude / ChatGPT / Grok で登録する(推奨)
エージェントの認証モードを**サブスクリプション(インタラクティブログイン)**に設定し、Register… をクリックします。何が起こるかは次のとおりです。
- アプリはプロキシが実行中であることを確認し(そうでなければ登録は拒否されます)、Register with Claude(または ChatGPT / Grok)と題した説明シートを表示します。Continue をクリックします。
- 使い捨ての登録用 VM が起動します — 一時的で隔離されており、ワークスペースフォルダのマウントも認証情報の差し替えマップもありません。その中で本物のログインコマンド(
claude login、codex login、または Grok の相当コマンド)が実行されます。 - Mac のデフォルトブラウザがプロバイダーのサインインページを開きます。いつも通りサインインします。フローがタイムアウトするまでおよそ 4 分あります。
- 得られた OAuth トークンはホスト上でキャプチャされ、暗号化されて保管されます。使い捨ての VM は破棄されます。
- ワークスペースエディタから登録を開始した場合、アプリは Share with every workspace? と尋ねます — サブスクリプションを共有デフォルトとして保管するには Every workspace を、そうでなければ Just this workspace を選びます。アプリの環境設定から開始した登録は、尋ねることなく常に共有デフォルトとして保管します。
以降、すべてのセッションのゲストは、決定論的なダミー認証情報とともに API キーモードで動作します — Claude には偽の ANTHROPIC_API_KEY、Codex にはダミーの遠い将来の有効期限を持つ JWT を含むシードされた ~/.codex/auth.json(そのためクライアントは自らそれをリフレッシュしようとしません)、Grok にはプレースホルダーの ~/.grok/auth.json です。プロキシはダミー値を認識し、ワイヤ上で有効な Authorization: Bearer アクセストークン(および Claude の場合は OAuth ベータヘッダー)を注入します。
トークンの保管とリフレッシュは完全にホスト側です。ホストは有効期限の約 5 分前に、プロバイダーのトークンエンドポイント(Claude は platform.claude.com/v1/oauth/token、Codex は auth.openai.com/oauth/token、Grok は auth.x.ai/oauth2/token)に対してトークンをリフレッシュするため、1 回のリフレッシュが実行中のすべての VM に役立ち、ゲストがリフレッシュトークンを保持することはありません。新しくキャプチャされたレコードは、意図的にすでに過ぎた有効期限で保管され、最初の使用時にリフレッシュを強制します — 依存する前にリフレッシュ経路が機能することを証明します。
認証モードセレクターの隣にあるコントロールがライフサイクルを完結させます。Re-register… はキャプチャを繰り返し(たとえば上流でセッションを取り消した後に)、Forget は保管されたサブスクリプションをホストから削除します。
セッション内のトークン差し替え
あるいは、エージェントが VM 内で自らログインする場合(セッション内で claude login を実行する場合)、プロキシは本物のサブスクリプション OAuth トークンがプロバイダーへ向かっているのに気づき、それを保管しようと申し出ます。シートが現れ — Swap Claude subscription token?(または Codex)— 本物のトークンをこの Mac に留めたまま、VM の認証情報ファイル内では偽物が置き換えることを説明します。アクセストークンとリフレッシュトークンの両方が一緒に差し替えられます。選択肢は次のとおりです。
| ボタン | 効果 |
|---|---|
| Swap | 本物のトークンはホストのストアへ移動します。VM の認証情報ファイルは偽物で書き換えられます。プロキシは以降ワイヤ上で本物のトークンを注入します。 |
| Not now | 今回のセッションでは何も変わりません。次回のセッションでプロンプトが再び表示されます。 |
| Never for this workspace | このワークスペースでのプロンプトを停止します。 |
このプロンプトの背後にあるワークスペースごとの状態は、エディタで Claude subscription token swap / Codex subscription token swap として表示されます(デフォルトでは未設定。選択後は「accepted」または「declined」)。ホストから VM への差し替えチャネルは意図的に一方向です。ホストは偽物を VM に書き込むことしかできず、VM は本物をホストに送り出すことしかできません — VM が本物のトークンを返してもらうよう要求できる RPC は存在しません。加えて VM 内のエージェントは、brm- の偽物プレフィックスを持たない認証情報の書き込みを拒否するため、たとえ不正に振る舞うホストであっても、ゲストの認証情報ファイルを本物の値で破損させることはできません。
メモ: Codex はゲスト内でサブスクリプションモードに留まります(その API キーモードは異なるバックエンドを対象とします)。また Grok のトークンは vsock エージェントではなくファイル
~/.grok/auth.jsonを経由して移動します。これらは実装の詳細です。保管モデルは同一です。
AWS
AWS はどのプロバイダーよりも深く扱われます。なぜなら AWS リクエストはベアラートークンで認証されるのではなく、署名されるからです(SigV4)。ワークスペースエディタで認証情報 → AWSを開きます。セグメントコントロールで Static keys と SSO / Identity Center のいずれかを選びます。
静的キーとホストの再署名器
Access key ID と Secret access key(さらにオプションの STS Session token と Default region)を貼り付けます。ライフサイクルは次のとおりです。
- VM 内:
~/.aws/configは credential_process ヘルパーを指し、これは vsock ポート 8445 経由で、本物の Access key ID と 40 文字の偽の Secret access key の組を提供し、セッショントークンは省略します。あらゆる AWS SDK、awsCLI、terraform、boto3 がこれをネイティブに取り込みます。ツール固有のセットアップは不要です。 - ゲストが行うこと: 偽のシークレットでリクエストに署名し、構文的には有効だが暗号学的には破綻した SigV4 署名を生成します。
- ワイヤ上: ホストの AWS 再署名器は
*.amazonaws.comと*.amazonaws.com.cn(GovCloud、ISO、リージョン別、バケットスタイルの S3 ホストを含む)宛てのリクエストを検出し、ゲストの署名を取り除き、セッショントークンが存在する場合は本物のX-Amz-Security-Tokenを注入し、リクエストが Mac を離れる前に本物のシークレットで再署名します。再署名が成功するたびに、マスクされたアクセスキーを伴うcredential.aws_sign監査イベントが発行され、トレースで確認できます。
これは最も強い意味でフェイルクローズです。本物のシークレットキーはいかなる形でも VM 内に存在せず、プロキシを迂回したリクエストは AWS によって InvalidSignatureException で拒否されます。
次の 3 つのリクエスト形式はサポートされておらず、暗黙の失敗ではなくゲストに明確なエラーを返します。チャンク化されたストリーミング S3 アップロード(STREAMING-AWS4-HMAC-SHA256-PAYLOAD、501 で応答)、SigV4A 非対称署名、および事前署名されたクエリ文字列 URL(署名を再署名器が置き換えられない位置に埋め込むもの)です。
SSO / IAM Identity Center
組織が IAM Identity Center を使用している場合、長期キーを貼り付ける代わりに SSO / Identity Center を選びます。
- Grant access to ~/.aws をクリックし、フォルダアクセスのプロンプトを承認します(セキュリティスコープ付きの許可です。フォルダはホスト上で読まれ、VM にマウントされることはありません)。
- SSO profile ピッカーからプロファイルを選びます。アプリは
~/.aws/config内でsso_start_url、sso_account_id、sso_role_nameを持つ[profile …]セクションを見つけ、[sso-session …]参照を解決します。アカウント ID とロールは読み取り専用で表示されます。 - セッション開始時、ホストは SSO トークンキャッシュ(
~/.aws/sso/cache)から一時的なロール認証情報を解決します。キャッシュされたトークンが期限切れの場合、aws sso loginのためにブラウザが開きます — これはホスト上で、/usr/local/bin/awsから実行されます。
解決された一時キーは、静的キーと同じ再署名器に供給されます。VM は依然としてシークレットを目にすることはありません。認証情報は、有効期限の約 5 分前にホスト上で自動リフレッシュされます。
Bedrock
エージェントの認証モードセレクター上の Bedrock(AWS) は、ワークスペースに設定された任意の AWS 認証情報(静的または SSO)を用いて AWS Bedrock に対して Claude Code を実行します — これはプライマリツールの認証モードであり、別個の認証情報ではありません。認証モードを設定し、認証情報 → AWSを構成し、必要に応じてワークスペースに Bedrock のモデル ID を設定します。Bedrock のエンドポイントは *.amazonaws.com ホストであるため、署名は同じ再署名器の経路を通ります。
Git HTTPS トークン(GitHub、GitLab、Bitbucket、セルフホスト)
git-over-HTTPS 用のパーソナルアクセストークンは、GitHub Tokens / GitLab Tokens / Bitbucket Tokens(総称して HTTPS トークン)の下にあります。各エントリはホスト、ユーザー名、トークンを受け取ります。セルフホストの GitLab や Gitea のインスタンスは、ホストフィールドを設定することで機能します。ライフサイクルは次のとおりです。
- VM 内: 偽物が
~/.git-credentialsおよびgh/glabの設定に書き込まれます。GH_TOKENとGITLAB_TOKENがエクスポートされ、CLI が自動的に認証します。偽物の形状は各ベンダーのバリデーターに一致するため(GitHub はghp_+ 36、GitLab はglpat-+ 20、それ以外はbrm_…)、ghとglabのプレフィックスと長さのチェックを通過します。 - ワイヤ上: そのエントリの git ホストへのリクエストで本物のトークンに差し替えられます。
- 承認: 各エントリはガードレールペインに独自の使用前に確認の行を持ちます。
SSH 経由の git push だけが必要なら、HTTPS トークンはまったく不要かもしれません — 以下の SSH キーを参照してください。
汎用 API キー(その他の API キー / 手動トークンルール)
アプリが自動処理しない任意の API については、その他の API キー(手動トークンルール、MITM token swap としても表示されます)の下にエントリを追加します。Add token をクリックし、次を指定します。
| フィールド | 意味 |
|---|---|
| Name | エントリのラベル。 |
| Value | 本物のシークレット(ホスト上に暗号化されて保管されます)。 |
| Env var name | VM 内で偽物がエクスポートされる変数。コードからこれを参照します。 |
| Host filter (optional) | 差し替えのホストスコープ。 |
2 つのエッジケースが意図的に用意されています。
- 空の env var name: 何もエクスポートされません。セッションのウェルカムバナーから偽物をコピーし、ツールが必要とする場所に配置します。
- 空白のホストフィルター: 本物の値が、尋ねることなく任意のホストで注入されます。これは明示的な常時オンの選択であり — 多くのリージョン別ホスト名を持つ API に便利です — が、認証情報のスコープがもはやそれを保護しないことを意味します。スコープのないシークレットをゲートするには、ガードレールペインでそれの使用前に確認をオンにします(あるいは結局のところホストフィルターを与えます)。
Anthropic、OpenAI、GitHub、GitLab、DigitalOcean、Kubernetes は、ここで手動エントリを必要とすることは決してありません。
1Password シークレット参照(op://)
本物のシークレットを貼り付ける代わりに、その他の API キーの値は 1Password シークレット参照 — op://vault/item/field、または op inject や .env.op ファイルが使用する波括弧形式 {{ op://vault/item/field }} — にできます。ディスク上に保管されるのは参照だけであり、シークレット自体はホストや VM のどこにも書き込まれません。エディタはこの参照を認識し、平文で表示し(それはシークレットではありません)、1Password を通じて解決されることを注記します。
各ワークスペースの起動時に、Bromure は 1Password CLI(op read)でホスト側で参照を解決し、参照文字列から偽物を発行し(そのためシークレットがローテーションしても偽物は安定して保たれます)、その偽物だけを VM にエクスポートします。その後 MITM プロキシは、貼り付けられたシークレットに対してそうするのとまったく同じように、ワイヤ上で偽物を解決された値に差し替えます — そして2 分ごとに再解決するため、1Password でアイテムをローテーションしても、再起動なしに数分以内に反映されます。
これには op CLI がインストールされ、サインインしている必要があります — 1Password アプリによる生体認証のロック解除、またはターミナルでの op signin です。op が見つからない場合、エディタは Get 1Password CLI リンクを表示し、ワークスペースは起動時にインストール手順を提示します。解決が失敗した場合(サインインしていない、またはアイテムが存在しない場合)、Bromure はエラーを提示するので、それを修正してワークスペースを再起動できます。
.env または .env.op ファイルのインポート(エディタの Import from .env…)は、op:// の値を自動的に認識し — ANTHROPIC_API_KEY のような認識された名前でも STRIPE_KEY のような任意の名前でも — それぞれを参照を保持する手動トークンとして保管します。
DigitalOcean
認証情報 → DigitalOcean の下にパーソナルアクセストークンを貼り付けます(Open DigitalOcean token page in your browser リンクはトークン生成へ移動します)。偽物(dop_v1_ + 16 進、64 文字)は DIGITALOCEAN_ACCESS_TOKEN としてエクスポートされ、~/.config/doctl/config.yaml に書き込まれるため、doctl auth init は不要です。差し替えは digitalocean.com へのリクエストを対象とし、加えて registry.digitalocean.com に対する docker login / doctl registry login で使用される base64 の Basic 認証ブロブ用の 2 つ目のエントリもあるため、レジストリのプッシュとプルも解決されます。
Linear
認証情報 → Linear の下にパーソナル API キーを貼り付けます(リンク: Open Linear API settings in your browser。キーは linear.app → Settings → API から取得します)。偽物(lin_api_ + 40)は LINEAR_API_KEY としてエクスポートされ、Linear SDK、MCP サーバー、CLI ツールが自動的に取り込みます。差し替えは linear.app に厳密にスコープされます(api.linear.app の GraphQL と mcp.linear.app の MCP)。ワークスペース上の Linear キーは、Linear イシューの自動化トリガーの前提条件でもあります — 自動化 & CLIを参照してください。
MCP サーバーのベアラートークン
MCP ペインで構成された HTTP トランスポートの MCP サーバーは、同じ扱いを受けます。本物のベアラートークンはホスト上に留まり、brm-mcp_… の偽物がエージェントの読む MCP 設定に注入され、プロキシがサーバーのホストにスコープしてワイヤ上で差し替えます。差し替えエントリを受け取るのは、空でないベアラートークンを持つ、有効な HTTP トランスポートのサーバーだけです。
ひとつ追加の配慮があります。brm-mcp_ エントリを持つホストについては、プロキシは OAuth/OIDC のディスカバリーパス(.well-known の authorization-server、protected-resource、OpenID configuration の各エンドポイント)に 404 で応答します。すると Claude Code は、そのサーバーを事前認証済みとして扱い、自身の OAuth フローを試みなくなります — いずれにせよ VM 内では決して完了できないフローです。
コンテナレジストリ(Docker Hub、GHCR など)
認証情報 → Container Registries は、docker pull/push 用の HTTP Basic 認証を管理します。Docker Hub(docker.io)、GitHub Container Registry(ghcr.io)、GitLab Container Registry(registry.gitlab.com)のプリセットがあります。その他のレジストリはホストで追加できます。ライフサイクルは次のとおりです。
- VM 内:
~/.docker/config.jsonに偽の auth ブロブ — ユーザー名と導出されたbrm-docker-…パスワードを組み合わせた base64 — が含まれるため、Docker はログイン済みだと信じます。 - ワイヤ上: プロキシは一致するレジストリホストで本物の base64 ブロブに差し替えます。distribution-spec のトークンのやり取りも処理されます。既知の認証レルム用に差し替えエントリが追加されます(Docker Hub は
auth.docker.ioに対して、DigitalOcean のレジストリはapi.digitalocean.comに対して認証します)。 - インポート: Import config.json… をクリックして、ホスト上の既存の
~/.docker/config.jsonからエントリを取り込みます。credsStore/credHelpersに委譲されたエントリはスキップされます — それらのパスワードはファイルではなく OS のキーチェーンにあります — そしてインポートの要約は、いくつがなぜスキップされたかを報告します。 - 承認: レジストリごとに、ガードレールペインの使用前に確認を通じて行います。Remove this registry はエントリを削除します。
Kubernetes コンテキスト
認証情報 → Kubernetes は、kubeconfig のコンテキストをプロキシ経由のクラスターアクセスに変えます。Import kubeconfig をクリックして既存の kubeconfig を解析し、コンテキストごとに 1 行にする(current-context が最初、認証タイプは自動検出)か、Add context でサーバー URL、認証情報、名前空間、クラスター CA を手動で入力します。いずれの場合も、VM は合成された ~/.kube/config を受け取ります。ゲスト内の kubectl は(Bromure CA を通じて信頼される)プロキシと通信し、API サーバーと直接通信することは決してありません。
認証タイプごとに次のとおりです。
- ベアラートークンコンテキストは VM 内で
brm-k8s-…のプレースホルダーを受け取り、ワイヤ上で本物のトークンに差し替えられます。 - クライアント証明書コンテキストは VM 内で使い捨ての自己署名証明書とキーを受け取ります。本物の証明書とキーはホスト上に
SecIdentityとして登録され、上流の mTLS に使用されます。 - Exec プラグインコンテキストは、VM 内でプラグインをまったく実行しません。exec プラグインポーラーが、リフレッシュ間隔(デフォルト 600 秒、下限 60)ごとにホスト上でコマンドを実行し、
ExecCredentialJSON を解析し、新鮮なトークンを差し替えマップに供給します。リフレッシュはエントリの同意状態を保持します。
kubeconfig がクラスター自身の CA を供給する場合、それが転送され、プロキシが上流の API サーバーを検証できます。インポートされた kubeconfig 内のファイルパスのフィールド(CA、証明書、キー)は、インポート時に先読みで読まれます — ディスク上のそれらのファイルへの後の変更は取り込まれません。各コンテキストはガードレールペインに独自の使用前に確認の行を持ち、そこでは書き込みポリシーが、バイトが転送される前に破壊的な動詞(kubectl delete、AWS の Delete*/Terminate*、docker push、git push)をホスト側で追加的に取り除くこともできます — 認証情報の差し替えとは別の層です。
HTTP データベース(MongoDB、ClickHouse、Elasticsearch)
認証情報 → Databases(MongoDB / ClickHouse / Elasticsearch のセクション)は、HTTPS を話すデータベースエンドポイント — Mongo Data API、ClickHouse の HTTP インターフェース、Elastic — を扱います。各エンドポイントは、エンジン、ホスト、シークレット、ユーザー名、認証タイプ、および brm-db-… の偽物がエクスポートされる 1 つ以上の env var 名(カンマ区切り)を受け取ります。コードや接続文字列からそれらの変数を参照します。
データベース認証情報は、差し替えがヘッダーとクエリパラメータだけでなくリクエストボディも走査する唯一のファミリーです。なぜなら接続シークレットは、JSON や SQL のペイロードの中に日常的に乗って移動するからです。プロキシはボディの差し替え後に Content-Length にパッチを当てます。他のトラフィックの無関係な multipart やバイナリのボディが触られることは決してありません(他のすべての差し替えはヘッダーにスコープされています)。Basic 認証エンドポイントは、その base64 のユーザーとシークレットのブロブも差し替えられます。エンドポイントごとの使用前に確認と書き込みポリシーは、ガードレールペインで設定します。
SSH キー
SSH はトークンをまったく使わずに処理されます。VM の SSH_AUTH_SOCK は、vsock(ポート 8444)経由の ssh-agent ブリッジによって支えられています。ゲストはアイデンティティを一覧表示し署名を要求できますが、秘密鍵のバイト列はホスト上にのみ存在し、VM 内から物理的に読み取ることも抽出することもできません。キーのソースは 2 つあり、どちらも認証情報 → SSH Keys の下にあります。
- ワークスペースごとのデフォルトキー。 共有のデフォルト ed25519 キーペアがアプリ起動時に生成され(Application Support の
default-ssh/の下に保管)、新しい各ワークスペースのエージェントディレクトリにコピーされます。ペインはワークスペースの公開鍵を表示するので、それを git ホストに貼り付けられます(GitHub の場合: github.com/settings/keys)。またbromure-cli workspaces ssh-keygen <workspace-id|name>で CLI から新鮮なキーを発行することもでき、これは新しい公開鍵を出力します。 - インポートされたキー。 Imported SSH keys の下の Import… / Import file… をクリックし、既存の秘密鍵ファイルをアプリに指定します — RSA、ed25519、ECDSA がサポートされ、暗号化されたキーも含まれます。暗号化されたキーは、インポート時に一度だけパスフレーズを求めます。パスフレーズは macOS のキーチェーン(サービス
io.bromure.agentic-coding.ssh-key-passphrases)に保管され、起動時にSSH_ASKPASSを介して供給され、決してログに記録されません。インポートされたキーの署名は、アプリが自身のために起動するプライベートな ssh-agent プロセス(一時ディレクトリ下のソケット上のssh-agent -D)を通ります — システム上の他の何とも分離されています。
インポートされたキーごとに、ガードレールペインで使用前に確認をオンにすると、VM 内のすべての署名リクエストが同意を求めるようになります。すべての署名 — デフォルトキーであれインポートされたキーであれ — は、キーの SHA256 フィンガープリントと、それが管理されたキーかインポートされたキーかを運ぶ credential.ssh_sign 監査イベントを発行します。
メモ: あなたの macOS ログインの ssh-agent(launchd のもの)は、意図的に 決して VM に公開されません。セッションから到達できるのは、ワークスペースごとのキーと、あなたが明示的にインポートしたキーだけです。
利用ごとの承認と付与期間
本章のあらゆる認証情報は使用前に確認のフラグを立てられます — ガードレールペインの認証情報ごとのチェックボックス(コントロール自体には Require approval to use と表示)で、デフォルトではオフであり、UI では「このセッションでこの認証情報が最初に使用されるときに確認ダイアログを表示します。」と説明されます。
ゲートされた認証情報がセッションで最初に使用されると、プロキシはリクエストを保留し、Allow "workspace name" to use credential? と題した同意ダイアログを表示します(ワークスペースの名前と認証情報のラベルが埋め込まれます)。4 つのボタンが提供されます。
| ボタン | 付与 |
|---|---|
| Allow for 5 minutes | 時間制限付き。認証情報は 5 分間、それ以上のプロンプトなしで流れます。 |
| Allow for 1 hour | 時間制限付き、1 時間。 |
| Allow for the rest of the session | セッションウィンドウが閉じるまで。 |
| Don't allow | リクエストは拒否されます。拒否は 5 分間記憶されるため、エージェントのリトライの嵐がダイアログの嵐を生み出しません。 |
知っておくと役立つ挙動は次のとおりです。
- 合体。 同じ認証情報を必要とする並行リクエストは、1 つのダイアログに集約されます — おしゃべりなエージェントが 12 個の並列 API 呼び出しを放っても 1 つのプロンプトになり、12 個すべてがあなたの決定に従います。
- 拒否が勝つ。 生きている拒否は、それより古い許可が参照される前に短絡します。
- 設計上、一時的。 付与と拒否はメモリ内にのみ保持され、セッションの終了時に取り消されます。「セッションの残り」がウィンドウの閉鎖を生き延びることは決してなく、アプリの実行をまたいで永続化されるものは何もありません。
- ヘッドレスセッション。 SSH またはヘッドレスセッションでは、プロンプトは GUI アラートとしてではなく、ワークスペースの tmux 内に現れます — リモートアクセスを参照してください。
AWS については、ゲートはすべてのホスト側の署名呼び出しに適用されます。SSH キーについては署名リクエストに、それ以外のすべてについてはセッションでの最初のワイヤ差し替えに適用されます。
ヒント: 同意ゲートは認証情報ごとであり、ホストごとではありません。スコープのない手動トークンを制御下に留めたいなら、承認がそのために設計された仕組みです。
認証情報の承認ウィンドウ
Window → Credential Approvals… は、現在のアプリの実行中に行われたすべての同意決定 — 時間制限付きの許可(5 分 / 1 時間 / セッションの残り)と記憶された拒否 — のライブビューを開きます。各行はワークスペース名と残り時間を表示し、Revoke を提供します。Revoke all(⌘⌫)はすべてを一度にクリアします。リストは 2 秒ごとに自動更新され、付与が期限切れになるにつれて自然に縮みます。
決定はメモリ内のみであるため、付与が期限切れになった後、セッションが閉じた後(セッションスコープの付与)、アプリが終了した後、ウィンドウは空になります。それは監査ログではなく、現在のためのコントロールパネルです — 履歴にはトレースを使ってください。
侵害検出器
偽物は二重の役割を果たします。シークレットの代役を務めるだけでなく、**トリップワイヤー(仕掛け線)**でもあります。偽トークンには、正当な宛先ファミリーがちょうど 1 つ — それが発行されたホストスコープ — だけあります。sk-ant-api03-brm-… が pastebin.example へのリクエストに現れる正直な理由はありません。そこでプロキシは、すべての送出リクエスト — ヘッダーとボディ — を、Aho-Corasick オートマトン(すべてに対して実行できるほど安価)で走査し、スコープの外へ向かうあらゆる偽物を探します。
それが見つかると、プロキシはそのリクエストを認証情報の持ち出しの試みとして扱います。
- リクエストは HTTP 451 でブロックされます。1 バイトも宛先に転送されません。
- VM は即座に一時停止されます。
- アラートが発火します。「Bromure は、発行されていないホストへセッション認証情報を漏洩させようとする送出の試みを検出しました。VM は一時停止されました。」
続いてワークスペースは侵害済みとしてマークされ — ワークスペースブラウザは Compromised — launching will prompt to wipe disk and home と表示します — 次回の起動には修復が必要になります。「続行するには、VM ディスクイメージと永続的なホームフォルダを消去する必要があります。あなたのトークン、SSH キー、ワークスペース設定は保持されます。」 続行するには Wipe and Launch をクリックします。付随する警告に注意してください。共有フォルダは消去されません。そのため侵害が共有フォルダ内のパッケージやファイルを通じて起きた場合、それはまだそこにあるかもしれません — 作業を再開する前にそれらのフォルダを確認してください。
侵害アラートへの推奨される対応は、トレースインスペクタ(⇧⌘I)を開くか bromure-cli trace leaks を実行して問題のホストとリクエストを確認し、プロジェクトの依存関係とプロンプトインジェクションされた指示のどちらが原因かを判断し(プロンプトインジェクションとサプライチェーンを参照)、その後に消去して再起動することです。
スコープの詳細は次のとおりです。
- スコープのない偽物は対象外。 ホストフィルターが空白の手動トークンは、設計上「任意のホスト」であり、検出器を作動させることはできません。ダミーのサブスクリプションプレースホルダーも同様に除外されます。
- ファーストパーティの兄弟は許容される。 マッチングは差し替えのスコープポリシーをミラーしますが、1 つだけ緩和があります。認証情報のプロバイダーと同じ登録済みドメイン配下のホスト(たとえば
anthropic.com配下の Claude または Codex のインフラ)はファミリーマッチを使用するため、正当なapi.anthropic.comトークンがmcp-tools.anthropic.comで見られても誤検知にはなりません。それ以外はすべて厳密です。 - 本物らしい漏洩もフラグされる。 偽物のトリップワイヤーとは独立に、プロキシは送出トラフィック内の差し替えられていない、本物らしいシークレット — 既知のプレフィックス(
sk-ant-、ghp_、AKIAなど)を持つBearerやx-api-keyの値、または 20 文字以上の不透明なトークン — をフラグします。これらはトレースインスペクタとbromure-cli trace leaksに漏洩警告として現れます。通常これは、本物のシークレットが手作業で VM に貼り付けられたことを意味し、ワイヤ境界はそれを不要にするために存在します。
有効化するものは何もありません — 検出器は常時オンです。
シークレットがホスト上のどこにあるか
機密性のあるものはすべて、インストールごとの 256 ビットのマスターキーの下、AES-GCM で保管時に暗号化されます — シークレットボールトです。マスターキーは macOS の Data Protection Keychain にあり、アプリの署名 ID にスコープされ、アクセシビリティは kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly で、iCloud 同期は無効です。それはプロンプトを出さず、同期せず、Mac を離れることは決してありません。キーチェーンに到達できない場合(署名なしまたはプロビジョニングされていないビルド)、アプリは暗号文の傍らに保管されたモード 0600 のキーファイルにフォールバックします — キーと暗号文が同じディスクを共有するため弱いですが、保管時の暗号化は機能し続けます。完全にプロビジョニングされたリリースはキーチェーンを使用します。
実際上の帰結は次のとおりです。
- バックアップとコピーは暗号文。 Time Machine のバックアップやコピーされた
Application Supportフォルダには、暗号化されたブロブしか含まれません。この Mac のキーチェーンエントリがなければ、それらは復号できません(ファイルフォールバックキーが使われ、一緒にコピーされていた場合を除く)。 - キーチェーンエントリを消去するとキーがローテーションされる。 既存の暗号化されたブロブは読めなくなり、認証情報を再入力することになります。
profile.json内の機密でないメタデータは影響を受けません。 - どこにも同期されない。 アプリ自身によって、認証情報、トークンストア、キーマテリアルがアップロード、同期、バックアップされることはありません。
ディスク上の場所は、特記なき限りすべて ~/Library/Application Support/BromureAC/ の下にあります。
| 場所 | 内容 |
|---|---|
ca/cert.pem、ca/key.pem | Bromure Agentic Coding Root CA(キーはモード 0600)。ローテーションするにはディレクトリを削除します。 |
fake-salt.bin | 偽物の導出の背後にある、インストールごとの 32 バイトの HKDF ソルト(0600)。これを削除すると、この Mac 上のすべての偽物がローテーションされます。 |
claude-subscription.enc、codex-subscription.enc、grok-subscription.enc | AES-GCM で暗号化されたサブスクリプション OAuth ストア(共有デフォルトとプロファイルごとのオーバーライド)、0600。 |
secrets-master.key | 0600 のフォールバックマスターキー — Data Protection Keychain に到達できない場合にのみ存在します。 |
default-ssh/id_ed25519.raw、default-ssh/id_ed25519.pub | 新しいワークスペースにコピーされる共有デフォルト SSH キーペア。 |
profiles/<id>/ssh/ | ワークスペースごとに発行された SSH キー(エージェントディレクトリ)。 |
Keychain: io.bromure.agentic-coding.master-key | AES-256 ボールトマスターキー(アカウント v1)、Data Protection Keychain。 |
Keychain: io.bromure.agentic-coding.ssh-key-passphrases | インポートされた SSH キーのパスフレーズ、プロファイル/キーファイルごとに 1 アイテム。 |
インポート用のホスト側の読み取り — ~/.aws/config、~/.aws/sso/cache/*.json、~/.docker/config.json、kubeconfig ファイル — はホスト上でのみ起こります。それらのファイルのいずれも VM にマウントされることは決してありません。暗号化されたトレースボディ(トレースを参照)は、同じボールトキーを使用します。
境界を自分で検証する
ワイヤ境界は、信頼で受け入れるのではなく、確認できるように設計されています。任意のセッション内のシェルから、次のようにします。
1. 環境は偽物を保持している。
echo "$ANTHROPIC_API_KEY"
# sk-ant-api03-brm-… ← a fake, not your key
env | grep -E 'TOKEN|KEY'
# every value is brm_/ghp_/glpat_/dop_v1_/lin_api_-shaped placeholder
2. 設定ファイルは偽物を保持している。
cat ~/.git-credentials # fake tokens per git host
cat ~/.docker/config.json # fake base64 auth blobs
grep -A2 credential_process ~/.aws/config # helper, not a secret key
3. それでもすべてが機能する。
aws sts get-caller-identity # succeeds — the host resigned the request
gh api user # succeeds — the fake was swapped on the wire
4. VM 内の TLS はプロキシで終端する。
openssl s_client -connect api.anthropic.com:443 -brief 2>&1 | head
# issuer: the Bromure Agentic Coding Root CA — not a public CA
5. SSH キーは存在しないが、署名は機能する。
ssh-add -L # lists public keys served by the vsock agent
ls ~/.ssh/id_* # no private key files to find
6. ホスト上で、差し替えが起こるのを見る。 ワークスペースのトレースを有効にし、次のようにします。
bromure-cli trace summary # per-request swap reports and leak warnings
bromure-cli trace leaks # only the suspicious ones
またはトレースインスペクタ(⇧⌘I)を開くと、差し替えられたリクエストには Never sent to VM — swapped by proxy と注釈が付きます。
もし VM 内で本物の認証情報を見つけたなら、それは 2 つの経路のいずれかでそこに至ったものです。あなた(またはあなたの指示によるエージェント)が手作業で貼り付けたか、共有フォルダを経由して届いたかです。差し替えの仕組みが本物をゲストに書き込むことは決してありません — そして侵害検出器がワイヤ上の本物の形状のシークレットを漏洩として扱うのは、まさにそれらがそこに存在すべきではないからです。
クイックリファレンス
ゲスト・ホスト境界上の vsock ポート:
| ポート | 目的 |
|---|---|
| 8443 | HTTPS MITM プロキシ — ゲストの egress のすべて。 |
| 8444 | SSH_AUTH_SOCK の背後にある ssh-agent ブリッジ。 |
| 8445 | AWS credential_process ヘルパー。 |
| 8446 | Claude サブスクリプショントークン差し替えエージェント — ローカル推論ブリッジと共有するポート(それらは異なるフローでセットアップされます。両方を使うセッションを診断する際はこれを念頭に置いてください — ローカルモデルを参照)。 |
| 8447 | Codex サブスクリプショントークン差し替えエージェント(アクセス、リフレッシュ、ID トークン)。 |
関連する CLI コマンド(完全なリファレンスは自動化 & CLIにあります):
| コマンド | 目的 |
|---|---|
bromure-cli workspaces create --auth token|subscription|bedrock|local | 認証モードを指定してワークスペースを作成します。 |
bromure-cli vm run --auth token|subscription|bedrock | VM を起動し、その場限りのワークスペースの認証モードを選択します。 |
bromure-cli workspaces ssh-keygen <workspace> | 新鮮なワークスペース SSH キーをホスト側で発行し、公開鍵を出力します。 |
bromure-cli trace summary [workspace] | 差し替えと漏洩警告を含む、トレースされたトラフィックを要約します。 |
bromure-cli trace leaks [workspace] | 認証情報の漏洩の可能性があるトレースされたリクエストを表示します。 |