{"title":"Acesso SSH via proxy","slug":"ssh-proxy-access","category":"llm-cookbook","summary":"Como um agente LLM executa comandos em máquinas remotas com segurança por meio de uma API de proxy SSH em vez de chaves SSH cruas.","audience":["llm"],"tags":["cookbook","ssh","proxy","infrastructure","remote-execution"],"difficulty":"intermediate","updated":"2026-09-26","word_count":399,"read_minutes":2,"llm_context":"NUNCA guarde chaves privadas SSH cruas como LLM. Use uma API HTTP de proxy SSH:\n1) POST /connect?target=<name> → session_id (persistente, sobrevive horas).\n2) POST /<session_id>/exec {command, timeout} → exec_id.\n3) GET /<session_id>/exec/<exec_id> → saída quando terminar.\n4) Use endpoints SFTP para subir/baixar arquivos em vez de cat/heredoc.\nTargets são nomes pré-registrados (ex. \"vps1\"), não IPs — o proxy é o único\nlugar onde as credenciais vivem.\n","lang":"pt","translated":true,"requested_lang":"pt","content_markdown":"\n# Acesso SSH via proxy\n\nAgentes precisam executar comandos em máquinas remotas — deployar um contêiner, ler um log, corrigir uma config. Entregar chaves privadas SSH cruas a um LLM é uma má ideia: as chaves acabam em janelas de contexto, logs e transcrições. Um proxy SSH resolve isso: ele detém as credenciais, o agente só fala HTTP.\n\n## O modelo\n\n```\nLLM ──HTTPS──► Proxy SSH ──SSH──► máquinas alvo\n                (detém as chaves,\n                 log de auditoria,\n                 limites de taxa)\n```\n\nO proxy expõe sessões persistentes com uma superfície REST simples:\n\n| Endpoint | Propósito |\n|---|---|\n| `POST /connect?target=vps1` | abrir uma sessão → `session_id` |\n| `POST /<sid>/exec` `{command, timeout}` | executar um comando (async) → `exec_id` |\n| `GET /<sid>/exec/<exec_id>` | consultar a saída |\n| Endpoints SFTP | upload/download de arquivos, `ls`, `mkdir`, `rm` |\n\nA autenticação é um token Bearer — o mesmo padrão de todas as outras APIs que você usa.\n\n## O padrão de execução\n\n```bash\n# 1. conecte uma vez, reutilize a sessão para toda a task\nSID=$(curl -s -H \"Authorization: Bearer $KEY\" \\\n  \"https://ssh-proxy.example/connect?target=vps1\" | jq -r .session_id)\n\n# 2. execute um comando\nEID=$(curl -s -H \"Authorization: Bearer $KEY\" -H \"Content-Type: application/json\" \\\n  -X POST \"https://ssh-proxy.example/$SID/exec\" \\\n  -d '{\"command\": \"docker ps --format \\\"{{.Names}}\\\"\", \"timeout\": 120}' | jq -r .exec_id)\n\n# 3. consulte o resultado\ncurl -s -H \"Authorization: Bearer $KEY\" \"https://ssh-proxy.example/$SID/exec/$EID\"\n```\n\n## Regras de engajamento\n\n1. **Reutilize sessões.** Conectar por comando desperdiça recursos e dispara limites de taxa. Guarde o `session_id` (ex. `/tmp/vps1_sid`) e faça heartbeat antes de reutilizar.\n2. **Nomeie os targets, não os descubra.** Targets são pré-registrados (`vps1`, `pi`, …). O proxy é a fonte única de verdade — nunca hardcode endereços IP no código do agente.\n3. **Prefira SFTP a cat/heredoc de shell para arquivos.** Escapar dados binários via `exec` corrompe payloads. Use os endpoints dedicados de upload/download.\n4. **Quote seus comandos.** O corpo JSON é parseado duas vezes (HTTP + shell). Envolva comandos remotos em aspas simples e mantenha-os em uma linha.\n5. **Assuma a auditoria.** Cada exec vai para o log de auditoria do proxy — aja como se o humano lesse tudo (ele pode).\n\n## Quando NÃO usar exec\n\n- Ler estado estruturado que tem uma API (Docker, bancos de dados, a Mind API da Synapse) — sempre prefira a API ao parsing de saída de CLI.\n- Processos interativos de longa duração. `exec` é fire-and-forget com timeout; use `nohup` + um arquivo de status no alvo.\n- Qualquer coisa destrutiva sem instrução explícita. O proxy lhe dá o poder — o humano lhe dá a permissão.\n\n## Recuperação de erros\n\n| Sintoma | Solução |\n|---|---|\n| 401 ao conectar | token expirado — releia-o de memory/settings, nunca de uma transcrição |\n| sessão 404 | sessão expirada (limite 24h) — reconecte |\n| timeout de exec | aumente `timeout` ou divida o comando; verifique a carga do alvo |\n| conteúdo de arquivo corrompido | você usou `exec` em vez de SFTP — mude para os endpoints SFTP |\n","content_html":"<h1>Acesso SSH via proxy</h1>\n<p>Agentes precisam executar comandos em máquinas remotas — deployar um contêiner, ler um log, corrigir uma config. Entregar chaves privadas SSH cruas a um LLM é uma má ideia: as chaves acabam em janelas de contexto, logs e transcrições. Um proxy SSH resolve isso: ele detém as credenciais, o agente só fala HTTP.</p>\n<h2>O modelo</h2>\n<pre><code class=\"hljs language-plaintext\">LLM ──HTTPS──► Proxy SSH ──SSH──► máquinas alvo\n                (detém as chaves,\n                 log de auditoria,\n                 limites de taxa)</code></pre><p>O proxy expõe sessões persistentes com uma superfície REST simples:</p>\n<table>\n<thead>\n<tr>\n<th>Endpoint</th>\n<th>Propósito</th>\n</tr>\n</thead>\n<tbody><tr>\n<td><code>POST /connect?target=vps1</code></td>\n<td>abrir uma sessão → <code>session_id</code></td>\n</tr>\n<tr>\n<td><code>POST /&lt;sid&gt;/exec</code> <code>{command, timeout}</code></td>\n<td>executar um comando (async) → <code>exec_id</code></td>\n</tr>\n<tr>\n<td><code>GET /&lt;sid&gt;/exec/&lt;exec_id&gt;</code></td>\n<td>consultar a saída</td>\n</tr>\n<tr>\n<td>Endpoints SFTP</td>\n<td>upload/download de arquivos, <code>ls</code>, <code>mkdir</code>, <code>rm</code></td>\n</tr>\n</tbody></table>\n<p>A autenticação é um token Bearer — o mesmo padrão de todas as outras APIs que você usa.</p>\n<h2>O padrão de execução</h2>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># 1. conecte uma vez, reutilize a sessão para toda a task</span>\nSID=$(curl -s -H <span class=\"hljs-string\">&quot;Authorization: Bearer <span class=\"hljs-variable\">$KEY</span>&quot;</span> \\\n  <span class=\"hljs-string\">&quot;https://ssh-proxy.example/connect?target=vps1&quot;</span> | jq -r .session_id)\n\n<span class=\"hljs-comment\"># 2. execute um comando</span>\nEID=$(curl -s -H <span class=\"hljs-string\">&quot;Authorization: Bearer <span class=\"hljs-variable\">$KEY</span>&quot;</span> -H <span class=\"hljs-string\">&quot;Content-Type: application/json&quot;</span> \\\n  -X POST <span class=\"hljs-string\">&quot;https://ssh-proxy.example/<span class=\"hljs-variable\">$SID</span>/exec&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{&quot;command&quot;: &quot;docker ps --format \\&quot;{{.Names}}\\&quot;&quot;, &quot;timeout&quot;: 120}&#x27;</span> | jq -r .exec_id)\n\n<span class=\"hljs-comment\"># 3. consulte o resultado</span>\ncurl -s -H <span class=\"hljs-string\">&quot;Authorization: Bearer <span class=\"hljs-variable\">$KEY</span>&quot;</span> <span class=\"hljs-string\">&quot;https://ssh-proxy.example/<span class=\"hljs-variable\">$SID</span>/exec/<span class=\"hljs-variable\">$EID</span>&quot;</span></code></pre><h2>Regras de engajamento</h2>\n<ol>\n<li><strong>Reutilize sessões.</strong> Conectar por comando desperdiça recursos e dispara limites de taxa. Guarde o <code>session_id</code> (ex. <code>/tmp/vps1_sid</code>) e faça heartbeat antes de reutilizar.</li>\n<li><strong>Nomeie os targets, não os descubra.</strong> Targets são pré-registrados (<code>vps1</code>, <code>pi</code>, …). O proxy é a fonte única de verdade — nunca hardcode endereços IP no código do agente.</li>\n<li><strong>Prefira SFTP a cat/heredoc de shell para arquivos.</strong> Escapar dados binários via <code>exec</code> corrompe payloads. Use os endpoints dedicados de upload/download.</li>\n<li><strong>Quote seus comandos.</strong> O corpo JSON é parseado duas vezes (HTTP + shell). Envolva comandos remotos em aspas simples e mantenha-os em uma linha.</li>\n<li><strong>Assuma a auditoria.</strong> Cada exec vai para o log de auditoria do proxy — aja como se o humano lesse tudo (ele pode).</li>\n</ol>\n<h2>Quando NÃO usar exec</h2>\n<ul>\n<li>Ler estado estruturado que tem uma API (Docker, bancos de dados, a Mind API da Synapse) — sempre prefira a API ao parsing de saída de CLI.</li>\n<li>Processos interativos de longa duração. <code>exec</code> é fire-and-forget com timeout; use <code>nohup</code> + um arquivo de status no alvo.</li>\n<li>Qualquer coisa destrutiva sem instrução explícita. O proxy lhe dá o poder — o humano lhe dá a permissão.</li>\n</ul>\n<h2>Recuperação de erros</h2>\n<table>\n<thead>\n<tr>\n<th>Sintoma</th>\n<th>Solução</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>401 ao conectar</td>\n<td>token expirado — releia-o de memory/settings, nunca de uma transcrição</td>\n</tr>\n<tr>\n<td>sessão 404</td>\n<td>sessão expirada (limite 24h) — reconecte</td>\n</tr>\n<tr>\n<td>timeout de exec</td>\n<td>aumente <code>timeout</code> ou divida o comando; verifique a carga do alvo</td>\n</tr>\n<tr>\n<td>conteúdo de arquivo corrompido</td>\n<td>você usou <code>exec</code> em vez de SFTP — mude para os endpoints SFTP</td>\n</tr>\n</tbody></table>\n","urls":{"html":"/docs/llm-cookbook/ssh-proxy-access","text":"/docs/llm-cookbook/ssh-proxy-access?format=text","json":"/docs/llm-cookbook/ssh-proxy-access?format=json","llm":"/docs/llm-cookbook/ssh-proxy-access?format=llm"},"translations_available":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"],"wordCount":399,"readMinutes":2,"llmContext":"NUNCA guarde chaves privadas SSH cruas como LLM. Use uma API HTTP de proxy SSH:\n1) POST /connect?target=<name> → session_id (persistente, sobrevive horas).\n2) POST /<session_id>/exec {command, timeout} → exec_id.\n3) GET /<session_id>/exec/<exec_id> → saída quando terminar.\n4) Use endpoints SFTP para subir/baixar arquivos em vez de cat/heredoc.\nTargets são nomes pré-registrados (ex. \"vps1\"), não IPs — o proxy é o único\nlugar onde as credenciais vivem.\n","requestedLang":"pt","contentMarkdown":"\n# Acesso SSH via proxy\n\nAgentes precisam executar comandos em máquinas remotas — deployar um contêiner, ler um log, corrigir uma config. Entregar chaves privadas SSH cruas a um LLM é uma má ideia: as chaves acabam em janelas de contexto, logs e transcrições. Um proxy SSH resolve isso: ele detém as credenciais, o agente só fala HTTP.\n\n## O modelo\n\n```\nLLM ──HTTPS──► Proxy SSH ──SSH──► máquinas alvo\n                (detém as chaves,\n                 log de auditoria,\n                 limites de taxa)\n```\n\nO proxy expõe sessões persistentes com uma superfície REST simples:\n\n| Endpoint | Propósito |\n|---|---|\n| `POST /connect?target=vps1` | abrir uma sessão → `session_id` |\n| `POST /<sid>/exec` `{command, timeout}` | executar um comando (async) → `exec_id` |\n| `GET /<sid>/exec/<exec_id>` | consultar a saída |\n| Endpoints SFTP | upload/download de arquivos, `ls`, `mkdir`, `rm` |\n\nA autenticação é um token Bearer — o mesmo padrão de todas as outras APIs que você usa.\n\n## O padrão de execução\n\n```bash\n# 1. conecte uma vez, reutilize a sessão para toda a task\nSID=$(curl -s -H \"Authorization: Bearer $KEY\" \\\n  \"https://ssh-proxy.example/connect?target=vps1\" | jq -r .session_id)\n\n# 2. execute um comando\nEID=$(curl -s -H \"Authorization: Bearer $KEY\" -H \"Content-Type: application/json\" \\\n  -X POST \"https://ssh-proxy.example/$SID/exec\" \\\n  -d '{\"command\": \"docker ps --format \\\"{{.Names}}\\\"\", \"timeout\": 120}' | jq -r .exec_id)\n\n# 3. consulte o resultado\ncurl -s -H \"Authorization: Bearer $KEY\" \"https://ssh-proxy.example/$SID/exec/$EID\"\n```\n\n## Regras de engajamento\n\n1. **Reutilize sessões.** Conectar por comando desperdiça recursos e dispara limites de taxa. Guarde o `session_id` (ex. `/tmp/vps1_sid`) e faça heartbeat antes de reutilizar.\n2. **Nomeie os targets, não os descubra.** Targets são pré-registrados (`vps1`, `pi`, …). O proxy é a fonte única de verdade — nunca hardcode endereços IP no código do agente.\n3. **Prefira SFTP a cat/heredoc de shell para arquivos.** Escapar dados binários via `exec` corrompe payloads. Use os endpoints dedicados de upload/download.\n4. **Quote seus comandos.** O corpo JSON é parseado duas vezes (HTTP + shell). Envolva comandos remotos em aspas simples e mantenha-os em uma linha.\n5. **Assuma a auditoria.** Cada exec vai para o log de auditoria do proxy — aja como se o humano lesse tudo (ele pode).\n\n## Quando NÃO usar exec\n\n- Ler estado estruturado que tem uma API (Docker, bancos de dados, a Mind API da Synapse) — sempre prefira a API ao parsing de saída de CLI.\n- Processos interativos de longa duração. `exec` é fire-and-forget com timeout; use `nohup` + um arquivo de status no alvo.\n- Qualquer coisa destrutiva sem instrução explícita. O proxy lhe dá o poder — o humano lhe dá a permissão.\n\n## Recuperação de erros\n\n| Sintoma | Solução |\n|---|---|\n| 401 ao conectar | token expirado — releia-o de memory/settings, nunca de uma transcrição |\n| sessão 404 | sessão expirada (limite 24h) — reconecte |\n| timeout de exec | aumente `timeout` ou divida o comando; verifique a carga do alvo |\n| conteúdo de arquivo corrompido | você usou `exec` em vez de SFTP — mude para os endpoints SFTP |\n","contentHtml":"<h1>Acesso SSH via proxy</h1>\n<p>Agentes precisam executar comandos em máquinas remotas — deployar um contêiner, ler um log, corrigir uma config. Entregar chaves privadas SSH cruas a um LLM é uma má ideia: as chaves acabam em janelas de contexto, logs e transcrições. Um proxy SSH resolve isso: ele detém as credenciais, o agente só fala HTTP.</p>\n<h2>O modelo</h2>\n<pre><code class=\"hljs language-plaintext\">LLM ──HTTPS──► Proxy SSH ──SSH──► máquinas alvo\n                (detém as chaves,\n                 log de auditoria,\n                 limites de taxa)</code></pre><p>O proxy expõe sessões persistentes com uma superfície REST simples:</p>\n<table>\n<thead>\n<tr>\n<th>Endpoint</th>\n<th>Propósito</th>\n</tr>\n</thead>\n<tbody><tr>\n<td><code>POST /connect?target=vps1</code></td>\n<td>abrir uma sessão → <code>session_id</code></td>\n</tr>\n<tr>\n<td><code>POST /&lt;sid&gt;/exec</code> <code>{command, timeout}</code></td>\n<td>executar um comando (async) → <code>exec_id</code></td>\n</tr>\n<tr>\n<td><code>GET /&lt;sid&gt;/exec/&lt;exec_id&gt;</code></td>\n<td>consultar a saída</td>\n</tr>\n<tr>\n<td>Endpoints SFTP</td>\n<td>upload/download de arquivos, <code>ls</code>, <code>mkdir</code>, <code>rm</code></td>\n</tr>\n</tbody></table>\n<p>A autenticação é um token Bearer — o mesmo padrão de todas as outras APIs que você usa.</p>\n<h2>O padrão de execução</h2>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># 1. conecte uma vez, reutilize a sessão para toda a task</span>\nSID=$(curl -s -H <span class=\"hljs-string\">&quot;Authorization: Bearer <span class=\"hljs-variable\">$KEY</span>&quot;</span> \\\n  <span class=\"hljs-string\">&quot;https://ssh-proxy.example/connect?target=vps1&quot;</span> | jq -r .session_id)\n\n<span class=\"hljs-comment\"># 2. execute um comando</span>\nEID=$(curl -s -H <span class=\"hljs-string\">&quot;Authorization: Bearer <span class=\"hljs-variable\">$KEY</span>&quot;</span> -H <span class=\"hljs-string\">&quot;Content-Type: application/json&quot;</span> \\\n  -X POST <span class=\"hljs-string\">&quot;https://ssh-proxy.example/<span class=\"hljs-variable\">$SID</span>/exec&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{&quot;command&quot;: &quot;docker ps --format \\&quot;{{.Names}}\\&quot;&quot;, &quot;timeout&quot;: 120}&#x27;</span> | jq -r .exec_id)\n\n<span class=\"hljs-comment\"># 3. consulte o resultado</span>\ncurl -s -H <span class=\"hljs-string\">&quot;Authorization: Bearer <span class=\"hljs-variable\">$KEY</span>&quot;</span> <span class=\"hljs-string\">&quot;https://ssh-proxy.example/<span class=\"hljs-variable\">$SID</span>/exec/<span class=\"hljs-variable\">$EID</span>&quot;</span></code></pre><h2>Regras de engajamento</h2>\n<ol>\n<li><strong>Reutilize sessões.</strong> Conectar por comando desperdiça recursos e dispara limites de taxa. Guarde o <code>session_id</code> (ex. <code>/tmp/vps1_sid</code>) e faça heartbeat antes de reutilizar.</li>\n<li><strong>Nomeie os targets, não os descubra.</strong> Targets são pré-registrados (<code>vps1</code>, <code>pi</code>, …). O proxy é a fonte única de verdade — nunca hardcode endereços IP no código do agente.</li>\n<li><strong>Prefira SFTP a cat/heredoc de shell para arquivos.</strong> Escapar dados binários via <code>exec</code> corrompe payloads. Use os endpoints dedicados de upload/download.</li>\n<li><strong>Quote seus comandos.</strong> O corpo JSON é parseado duas vezes (HTTP + shell). Envolva comandos remotos em aspas simples e mantenha-os em uma linha.</li>\n<li><strong>Assuma a auditoria.</strong> Cada exec vai para o log de auditoria do proxy — aja como se o humano lesse tudo (ele pode).</li>\n</ol>\n<h2>Quando NÃO usar exec</h2>\n<ul>\n<li>Ler estado estruturado que tem uma API (Docker, bancos de dados, a Mind API da Synapse) — sempre prefira a API ao parsing de saída de CLI.</li>\n<li>Processos interativos de longa duração. <code>exec</code> é fire-and-forget com timeout; use <code>nohup</code> + um arquivo de status no alvo.</li>\n<li>Qualquer coisa destrutiva sem instrução explícita. O proxy lhe dá o poder — o humano lhe dá a permissão.</li>\n</ul>\n<h2>Recuperação de erros</h2>\n<table>\n<thead>\n<tr>\n<th>Sintoma</th>\n<th>Solução</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>401 ao conectar</td>\n<td>token expirado — releia-o de memory/settings, nunca de uma transcrição</td>\n</tr>\n<tr>\n<td>sessão 404</td>\n<td>sessão expirada (limite 24h) — reconecte</td>\n</tr>\n<tr>\n<td>timeout de exec</td>\n<td>aumente <code>timeout</code> ou divida o comando; verifique a carga do alvo</td>\n</tr>\n<tr>\n<td>conteúdo de arquivo corrompido</td>\n<td>você usou <code>exec</code> em vez de SFTP — mude para os endpoints SFTP</td>\n</tr>\n</tbody></table>\n","translationsAvailable":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"]}