プロキシ経由のSSHアクセス
LLMエージェントが生のSSH鍵ではなくSSHプロキシAPIを通じてリモートマシン上で安全にコマンドを実行する方法。
プロキシ経由のSSHアクセス
エージェントはリモートマシンでコマンドを実行する必要があります — コンテナをデプロイ、ログを読む、設定を直す。生のSSH秘密鍵をLLMに渡すのは悪い考えです:鍵はコンテキストウィンドウ、ログ、トランスクリプトに入り込んでしまいます。SSHプロキシはこれを解決します:資格情報を保持するのはプロキシで、エージェントはHTTPだけを話します。
モデル
LLM ──HTTPS──► SSHプロキシ ──SSH──► ターゲットマシン
(鍵を保持、
監査ログ、
レート制限)プロキシはシンプルなRESTサーフェスで永続セッションを公開します:
| エンドポイント | 目的 |
|---|---|
POST /connect?target=vps1 |
セッションを開く → session_id |
POST /<sid>/exec {command, timeout} |
コマンドを実行(非同期)→ exec_id |
GET /<sid>/exec/<exec_id> |
出力をポーリング |
| SFTPエンドポイント | ファイルのアップ/ダウンロード、ls、mkdir、rm |
認証はBearerトークンです — 使っている他のすべてのAPIと同じパターンです。
実行パターン
# 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"運用規則
- セッションを再利用する。 コマンドごとに接続すると資源を浪費し、レート制限に触れます。
session_idを保存し(例:/tmp/vps1_sid)、再利用前にハートビートさせましょう。 - ターゲットを名前で呼び、発見しない。 ターゲットは事前登録済みです(
vps1、pi…)。プロキシが唯一の信頼源です — エージェントコードにIPアドレスをハードコードしてはいけません。 - ファイルにはシェルのcat/heredocよりSFTPを優先する。
execを通じたバイナリデータのエスケープはペイロードを壊します。専用のアップ/ダウンロードエンドポイントを使いましょう。 - コマンドをクォートする。 JSONボディは2回パースされます(HTTP + シェル)。リモートコマンドはシングルクォートで包み、1行に保ちましょう。
- 監査を前提とする。 すべての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エンドポイントに切り替え |