どうして? WSL2上のCodexからSSHできない
WSL上でCodexを使っていてデプロイ先のリモートのLinuxホストへSSHさせようとしたところ、こんなエラーに遭遇しました
socket: Operation not permitted
ssh: connect to host 100.64.x.x port 22: failure
WSLのターミナルからは普通にSSHできるのに、 CodexにSSH接続をさせると接続できない
昨日は何の問題もなかったのに...
最終的には Codexのsandbox設定でネットワークアクセスを許可する ことで解決しました
さらにその後にsystem SSH configに関する別の問題も出てきたので、その切り分けも含めて残しておきます
環境
今回の構成は概ね以下です
Windows
└─ WSL (Debian)
├─ VS Code
├─ Codex IDE拡張 / CLI
└─ OpenSSH
│
│ Tailscale
▼
Linuxホスト (Debian)
接続先にはTailscale経由でSSHしています
通常のWSLターミナルからは、
ssh debian
で接続できます
問題になったのは Codex自身にSSHコマンドを実行させた場合 です
最初の症状:socket: Operation not permitted
CodexからSSHを実行すると、
socket: Operation not permitted
ssh: connect to host 100.64.x.x port 22: failure
となりました
最初はTailscaleやWSLのルーティングを疑いました
ルーティングを確認
ip route get 100.64.x.x
結果は、
100.64.x.x via 172.26.xxx.1 dev eth0 src 172.26.xxx.xxx uid 1000
cache
経路は存在しています
TCP/22を直接確認
nc が入っていなかったので、bashの /dev/tcp を使いました
timeout 5 bash -c '</dev/tcp/100.64.x.x/22' \
&& echo "TCP/22 OK" \
|| echo "TCP/22 NG"
結果:
TCP/22 OK
つまり、
WSL → Tailscale → 接続先:22
の通信そのものは成立しているようです
さらに通常のWSLターミナルから、
ssh -vvv debian
を実行すると、
PTY allocation request accepted
shell request accepted
Linux debian ...
debian@debian:~$
正常に接続できていました
ここまで確認すると、Tailscaleやsshdを疑うよりも、
「Codexがコマンドを実行する環境」と「自分がWSLのシェルから実行する環境」の違い
なようです
原因:Codex sandboxのネットワークアクセス
Codexにはコマンド実行時のsandboxがあります
今回、~/.codex/config.toml に以下を設定しました
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = true
これでworkspaceへの書き込みを許可したsandboxから、外部ネットワークへ接続できるようにします
設定変更後、 新しいCodexセッションを開始 します
既存セッションではなく、 新しいセッション で確認するのがポイントです
これによってCodexからSSH接続できるようになり、最初の
socket: Operation not permitted
は解消しました(ヤレヤレ
TOMLの記述位置で一度ハマった
ここでもう一つ罠がありました
最初、既存の config.toml の末尾にそのまま、
[tui.model_availability_nux]
gpt-6-astra = 1
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = true
と追加してました
するとCodex起動時に、
invalid configuration: invalid type: string "workspace-write",
expected u32 in `tui.model_availability_nux`
というエラー
TOMLではテーブル宣言が継続する
原因は、
[tui.model_availability_nux]
です
この後に、
sandbox_mode = "workspace-write"
と書いても、自動的にトップレベルへ戻るわけではありません
実質、
[tui.model_availability_nux]
gpt-6-astra = 1
sandbox_mode = "workspace-write"
として解釈されてしまったようです(お恥ずかしい
model_availability_nux は整数値を期待しているため、"workspace-write" を渡されてエラーになっていました
修正版
トップレベルの設定は冒頭にまとめました
model = "gpt-6-luna"
model_reasoning_effort = "medium"
service_tier = "default"
sandbox_mode = "workspace-write"
# 以下、各テーブル
そして後ろに、
[sandbox_workspace_write]
network_access = true
を定義します
TOMLに慣れていないと地味にハマりました
SSHできた……と思ったら第二の問題
network_access = true によってネットワーク接続自体は可能になりました
ところがCodexから通常通り、
ssh debian
を実行させると、今度は、
/etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf
の所有者・権限に関するエラーで停止しました
しかし、
ssh -F ~/.ssh/config debian
のように ユーザーSSH設定を明示すると成功 します
しかも、
- SSH接続
- SSH認証
- リモートコマンド実行
まで問題ありません
本当に /etc/ssh の権限がおかしいのか?
エラーをそのまま信じて chmod や chown する前に、実際の状態を確認しました
ls -ld /etc/ssh /etc/ssh/ssh_config.d
ls -l /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf
対象ファイルはシンボリックリンクでした
/etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf
-> /usr/lib/systemd/ssh_config.d/20-systemd-ssh-proxy.conf
そこでリンク先も確認
ls -ld /usr/lib/systemd /usr/lib/systemd/ssh_config.d
ls -l /usr/lib/systemd/ssh_config.d/20-systemd-ssh-proxy.conf
stat -L /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf
結果は、
/etc/ssh root:root 0755
/etc/ssh/ssh_config.d root:root 0755
/usr/lib/systemd root:root 0755
/usr/lib/systemd/ssh_config.d root:root 0755
20-systemd-ssh-proxy.conf root:root 0644
特におかしなところはありません
さらに、通常のWSLターミナルでは、
ssh -vvv debian
で正常に接続できました
状況はこんな感じです
| 実行環境 | コマンド | 結果 |
|---|---|---|
| WSL通常シェル | ssh debian |
成功 |
| Codex | ssh debian |
system SSH config関連で失敗 |
| Codex | ssh -F ~/.ssh/config debian |
成功 |
この状態なら、 正常に動いているOS側のSSH設定を変更する理由はありません
最終的な運用
Codexからdebianへ接続するときは、ユーザー設定を明示することにしました
ssh -F ~/.ssh/config debian
さらにCodexがSSHエラーを見て /etc/ssh を勝手に修正しないよう、AGENTS.md に運用ルールを入れておくのも有効ですね
## SSH access
When connecting to `debian` from Codex, explicitly use the user SSH configuration:
ssh -F ~/.ssh/config debian
Do not modify `/etc/ssh`, system SSH configuration, file ownership, or
permissions to work around SSH connection issues.
まとめ
今回のポイントは、 「Codexが実行したコマンド」と「自分がターミナルで実行したコマンド」は、同じWSL上でも実行条件が同じとは限らない ということです
切り分けとしては、
- WSLから対象IPへのrouteを確認
- TCP/22への接続を確認
- 通常のWSLから
ssh -vvvで接続確認 - 通常のWSLだけ成功するならCodex側の実行環境を疑う
- Codex sandboxの
network_accessを確認 - system SSH configだけ問題になるなら
ssh -F ~/.ssh/configで切り分け - OS側が正常なら安易に
chmod/chownしない
という順番で手をつけていきました
AIエージェントにデプロイ先や別ホストを操作させるようになると、 OSのネットワークだけでなく「エージェントのsandbox境界」もトラブルシュート対象になる というのが今回の学びでした
この点は、従来のSSHトラブルとは少し違うところだと思いました