「外部通信禁止」と言われたので、Copilot CLIをWSL2に閉じ込めた

>100 Views

November 09, 26

スライド概要

扱う情報によって、求められる機密性は異なります。それでもAIは使いたい。
そんな要望のいいとこどりをすべく、案件ごとにGitHub Copilot CLIをWSL2へ閉じ込める環境を作りました。
外部通信を禁止された案件でもAIを使い続けるための構成と、その判断の過程をお話しします。

ゆるよな Gh-CUG #08(2026/11/09)での発表資料です。
Web版(スピーカーノート付き):https://in0ho1no.github.io/copilot-cli-wsl2-isolation/

profile-image

普段は組み込み開発。C言語一筋10年。趣味でPythonを数年。 AIは個人利用が主で、業務での利用を推進中。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

GitHub Copilot CLI × WSL2 「外部通信禁止」と言われたので、 Copilot CLIをWSL2に閉じ込めた inoinoino GitHub: in0ho1no

2.

自己紹介 inoinoino GitHub: in0ho1no / X: @in0ho1no 普段は組み込み開発 C言語一筋10年 / 趣味でPythonを数年 AIは個人利用が主 業務での利用は推進中

3.

01 背景 扱う情報によって、求められる機密性は違う 多くの案件 ある案件 AIを普通に使える。Web検索もMCPサーバも 使える AIの「Web検索」をオフにするよう 求められた。これを「外部通信禁止」と 解釈した それでも、AIは使いたい。いいとこどりをしたい。

4.

01 背景 求められたことは2つ 1 2 外部通信の遮断 案件の分離 公式サーバ(GitHub)以外へ通信しない 案件Aの情報を、案件Bの作業に混ぜない (ファイル、会話履歴、認証情報) しかも「設定し忘れ」や「AIによる設定の書き換え」で崩れないこと

5.

先に結論 エージェント自身が、遮断を認めた これを案件ごとに、設定し忘れても崩れない形で作る

6.

02 Copilot Chatでは足りなかった VS CodeのSandboxを有効にしても、通信は止まらない 外向き通信 既定で許可。トグルはオン・オフだけで、通信は止まらない fetch・統合ブラウザ サンドボックスの対象外。別のポリシーで止める必要がある Localセッション 対象外。効くのはAgent Hostセッションだけ

7.

02 Copilot Chatでは足りなかった 案件単位で強制できない 分離 起動 VS Code Serverが、案件をまたいで 共有される 起動のしかたを揃えられず、案件ごとの 設定を強制する入口がない 案件ごとにプロセスを分けて起動できる、Copilot CLIを選んだ

8.

03 Copilot CLIをWSL2に閉じ込める なぜ、WSL2の専用ディストリなのか Copilot CLIのサンドボックスは、WindowsではMXCでも動く。それでもWSL2を選んだ Claude Codeも見据える 案件分離を意識させる Claude Codeのサンドボックスは、 ネイティブWindowsでは動かない。 WSL2なら同じ構成で揃えられる ディストリを丸ごと分ける。プロンプトの ホスト名で、今どの案件にいるかが見える

9.

03 Copilot CLIをWSL2に閉じ込める 構成:案件ごとに専用ディストリを作る Gitリポジトリ AI-caseA(専⽤ディストリ) AI-caseB(専⽤ディストリ) user-data (cloud-init) wsl.conf:Windowsに届かない wsl.conf:Windowsに届かない ランチャー:環境変数を絞る ランチャー:環境変数を絞る 保護スクリプト サンドボックス:AIのコマンド サンドボックス:AIのコマンド 1ファイルから、 案件ごとに構築する Copilot CLI本体 Copilot CLI本体 ランチャー・管理設定 通信するのは CLI本体だけ 公式サーバ(GitHub)

10.

03 Copilot CLIをWSL2に閉じ込める 3つの層で、止めるものを分担する サンドボックス+管理設定 止める:AIが実行するコマンド bubblewrapとslirp4netnsで、通信と作業フォルダ外を遮断。管理設定で、緩められない下限を置く ランチャー 止める:起動の条件のばらつき 許可リスト外の環境変数を捨て、決まった引数で起動する。直接起動は案内に置き換える 専用ディストリ 止める:案件をまたぐ参照 案件ごとに分ける。wsl.confで、Windowsのファイル( /mnt/c )とアプリ( powershell.exe )への 経路を断つ

11.
[beta]
03 Copilot CLIをWSL2に閉じ込める

管理設定で、緩められない下限を置く
/etc/github-copilot/managed-settings.json

"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowBypass": false,
"auth": { "git": false, "gh": false },
"userPolicy": { "network": {
"allowOutbound": false,
"allowLocalNetwork": false
} }
}

root所有で置く
他のユーザが書き込めると無視される
ここより緩められない
ユーザ設定、リポジトリの設定、
起動時の引数のどれでも
効いているかを見る

/sandbox の表示に(managed)と
出るか

12.

03 Copilot CLIをWSL2に閉じ込める 検証結果:何がどう遮断されたか 確認したこと 結果 シェルからの通信(curl) 名前解決できずに失敗。ネットワークはloだけ Web取得・GitHub MCP 接続できず、ツールは使えない 作業フォルダ外のファイル シェルからは存在ごと隠れ、組み込みツールは拒否 トークン・設定ファイル ~/.copilot/config.json は読めず、 ~/.copilot にも書けない 環境変数の鍵 ランチャーで除かれる( GITHUB_TOKEN は未設定) Windowsアプリ command not found 別の案件 別ディストリのファイルは見えない メモリ機能 有効だと全リポジトリ共通の記憶に入った。無効化後は 作業フォルダのAGENTS.mdへ Copilot CLI 1.0.107、Ubuntu 24.04.5、bubblewrap 0.9.0、slirp4netns 1.2.1で確認

13.

03 Copilot CLIをWSL2に閉じ込める エージェント側からは緩められない 起動時の引数 作業フォルダの設定 フック --no-sandbox を付けても エージェントが書き込める 場所に緩める設定を 書いても、効かない disableAllHooksでも 作業フォルダのフックは 動いた。ただしフックも サンドボックス内で動き、 通信できない 無視される --no-sandbox was ignored because an enterprise policy requires the sandbox. 別ターミナルでの人の操作は、対象外。運用ルールで扱う

14.

03 Copilot CLIをWSL2に閉じ込める 遮断は、無害な結果に見えることがある $ cat ~/outside/secret.txt No such file or directory ファイルは実在する。サンドボックスが 存在ごと隠している $ touch ~/probe ~/.copilot/probe (作成できたと表示) 実際のホームには残っていない。仮の ホームに書かれて捨てられる 防御としては問題ない。ただ、利用者が混乱しないよう「遮断されるとこう見える」を 周知しておく

15.

04 運用に落とす 利用者へのお願いは「ランチャーから起動する」だけ $ copilot Copilot CLIはランチャー(/opt/aienv/launch-copilot.sh)から起動してください $ /opt/ai-env/launch-copilot.sh ランチャーがやること 許可リスト以外の環境変数を 捨てる Gitリポジトリを保護してから 起動する --sandbox と --disablebuiltin-mcps を付ける 直接起動はガード関数で案内に置き換える。設定し忘れる余地を作らない

16.

04 運用に落とす Git:コミットはエージェント、Pushは人 エージェント 人(別ターミナル) コミット:できる fine-grained PATでPushする Push:できない 対象リポジトリだけ、Contentsの読み 書きだけ、有効期限は短く。 credential.helperのcacheでメモリに 1時間だけ持つ Could not resolve host: github.com 使わない:gh auth login、credential.helper store、SSH鍵。どれもディスクに残るため

17.

04 運用に落とす 仕込まれたフックは、人の操作で動く 保護する前は、エージェントが置いたフックが、人のコミットをきっかけにWSL2内でも、 Windows側のVS Codeからも実行された 対象 所有者と権限 .git root:worker 3775(作れるが消せない) .git/config root:root 0644(書き換えられない) .git/hooks root:root 0755(追加できない) 自動で保護する ランチャーの起動前と、1分ごとの タイマーで実行。既に怪しい フックや設定があれば警告する

18.

04 運用に落とす 消すときは、トークンを取り消してから 1 2 3 4 取り出す 取り消す 確かめる 削除する ディストリ内の トークン。値は 表示しない GitHubのRevoke API(202) そのトークンが 401になるまで待つ 名前を 再入力してから 登録を解除 どこかで失敗したら、ディストリは消さずに止まる 先に wsl --unregister で消すと、トークンを取り出せず手作業で取り消すしかない。手作業は 必ず漏れる

19.

04 運用に落とす VS Codeは、制限モードでAI機能なしで使う WSL拡張では接続できない automountを切っているため。VS Code Serverの 導入に /mnt/c を使う \\wsl.localhost経由で開く Windows側のVS Codeで、案件ディストリの作業フォルダを 直接開く 信頼しない、AIを使わない 制限モードでtasks.jsonなどの自動実行を防ぐ。AI拡張は サンドボックスを通らないので使わない

20.

05 まとめ 「これで保証」ではなく、多層防御の一層 残る制約 扱い 管理設定が、契約形態や更新で効かなくなる可能性 構築時に(managed)の表示を確認する Copilot CLIは自動で更新される 更新後に、同じ手順で再検証する 別ターミナルでの人の操作 運用ルールで扱う Windows側からの参照( \\wsl.localhost ) 運用ルールで扱う 意図的な迂回( command copilot 、 wsl -e ) サンドボックスは外れない。残りは 運用ルール

21.

05 まとめ 機密性に応じて環境を選び、 外部通信禁止の案件でもAIを使い続ける 案件ごとの専用ディストリ + サンドボックス + 管理設定 + 運用ルール ありがとうございました