# プロキシ経由のSSHアクセス エージェントはリモートマシンでコマンドを実行する必要があります — コンテナをデプロイ、ログを読む、設定を直す。生のSSH秘密鍵をLLMに渡すのは悪い考えです:鍵はコンテキストウィンドウ、ログ、トランスクリプトに入り込んでしまいます。SSHプロキシはこれを解決します:資格情報を保持するのはプロキシで、エージェントはHTTPだけを話します。 ## モデル ``` LLM ──HTTPS──► SSHプロキシ ──SSH──► ターゲットマシン (鍵を保持、 監査ログ、 レート制限) ``` プロキシはシンプルなRESTサーフェスで永続セッションを公開します: | エンドポイント | 目的 | |---|---| | `POST /connect?target=vps1` | セッションを開く → `session_id` | | `POST //exec` `{command, timeout}` | コマンドを実行(非同期)→ `exec_id` | | `GET //exec/` | 出力をポーリング | | SFTPエンドポイント | ファイルのアップ/ダウンロード、`ls`、`mkdir`、`rm` | 認証はBearerトークンです — 使っている他のすべてのAPIと同じパターンです。 ## 実行パターン ```bash # 1. 一度だけ接続し、タスク全体でセッションを再利用 SID=$(curl -s -H "Authorization: Bearer $KEY" \ "https://ssh-proxy.example/connect?target=vps1" | jq -r .session_id) # 2. コマンドを実行 EID=$(curl -s -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -X POST "https://ssh-proxy.example/$SID/exec" \ -d '{"command": "docker ps --format \"{{.Names}}\"", "timeout": 120}' | jq -r .exec_id) # 3. 結果をポーリング curl -s -H "Authorization: Bearer $KEY" "https://ssh-proxy.example/$SID/exec/$EID" ``` ## 運用規則 1. **セッションを再利用する。** コマンドごとに接続すると資源を浪費し、レート制限に触れます。`session_id`を保存し(例:`/tmp/vps1_sid`)、再利用前にハートビートさせましょう。 2. **ターゲットを名前で呼び、発見しない。** ターゲットは事前登録済みです(`vps1`、`pi`…)。プロキシが唯一の信頼源です — エージェントコードにIPアドレスをハードコードしてはいけません。 3. **ファイルにはシェルのcat/heredocよりSFTPを優先する。** `exec`を通じたバイナリデータのエスケープはペイロードを壊します。専用のアップ/ダウンロードエンドポイントを使いましょう。 4. **コマンドをクォートする。** JSONボディは2回パースされます(HTTP + シェル)。リモートコマンドはシングルクォートで包み、1行に保ちましょう。 5. **監査を前提とする。** すべてのexecはプロキシの監査ログに残ります — 人間がすべて読むつもりで振る舞いましょう(実際に読めます)。 ## execを使うべきでないとき - APIを持つ構造化された状態を読むとき(Docker、データベース、SynapseのMind API)— CLI出力の解析より常にAPIを優先します。 - 長時間の対話的プロセス。`exec`はタイムアウト付きのfire-and-forgetです。代わりにターゲット上で`nohup` + 状態ファイルを使いましょう。 - 明示的な指示のない破壊的な操作すべて。プロキシが力を与えます — 許可を与えるのは人間です。 ## エラー回復 | 症状 | 修正 | |---|---| | connectで401 | トークン失効 — memory/settingsから読み直す。トランスクリプトからは絶対に | | セッション404 | セッション失効(24h上限)— 再接続 | | execタイムアウト | `timeout`を上げるかコマンドを分割;ターゲットの負荷を確認 | | ファイル内容の破損 | SFTPの代わりに`exec`を使った — SFTPエンドポイントに切り替え |