33800 Docs

← Retour

Backlog: Ameliorations SSH Connector

Date: 26/01/2026 Priorite: HAUTE Status: TERMINE Dependance: SSH Connector v1.0 (TERMINE)

Contexte

Le connecteur SSH de base est fonctionnel. Ces ameliorations le rendront plus puissant pour des cas d'usage avances.


1. Double SSH / Jump Host (ProxyJump)

Probleme

Certains serveurs ne sont accessibles que via un bastion/jump host:

Local -> Bastion (public) -> Serveur cible (prive)

Solution

Config instance SSH etendue

{
  "host": "192.168.1.10",
  "port": 22,
  "username": "admin",
  "auth_method": "key",
  "private_key_encrypted": "...",

  "jump_host": {
    "host": "bastion.example.com",
    "port": 22,
    "username": "jump-user",
    "auth_method": "key",
    "private_key_encrypted": "..."
  }
}

Implementation technique

La librairie ssh2 supporte le tunneling:

// Connect to jump host
const jumpConn = new Client();
jumpConn.connect({ host: jumpHost, ... });

jumpConn.on('ready', () => {
  // Create tunnel to target
  jumpConn.forwardOut('127.0.0.1', 0, targetHost, 22, (err, stream) => {
    // Connect to target through tunnel
    const targetConn = new Client();
    targetConn.connect({ sock: stream, ... });
  });
});

UI Frontend

Taches


2. Support SFTP

Probleme

Upload/download actuels utilisent cat et heredoc = texte uniquement. Besoin de transferer des fichiers binaires (images, archives, etc.)

Solution

Nouveaux endpoints

POST /api/ssh/sftp/upload
{
  "instance_id": "uuid",
  "local_content_base64": "...",
  "remote_path": "/path/to/file",
  "mode": "644"
}

POST /api/ssh/sftp/download
{
  "instance_id": "uuid",
  "remote_path": "/path/to/file"
}
Response: { "content_base64": "...", "size": 12345 }

POST /api/ssh/sftp/list
{
  "instance_id": "uuid",
  "remote_path": "/var/log"
}
Response: { "entries": [{ "name": "...", "type": "file|dir", "size": ..., "mtime": ... }] }

Implementation technique

import { SFTPWrapper } from 'ssh2';

conn.sftp((err, sftp: SFTPWrapper) => {
  // Upload
  const writeStream = sftp.createWriteStream(remotePath);
  writeStream.write(buffer);

  // Download
  const readStream = sftp.createReadStream(remotePath);

  // List
  sftp.readdir(remotePath, (err, list) => { ... });
});

UI Frontend

Taches


3. Terminal WebSocket Temps Reel

Probleme

L'interface actuelle est "one-shot": commande -> attente -> resultat. Pas de shell interactif (vim, htop, logs live, etc.)

Solution

Architecture

┌─────────────┐     WebSocket      ┌─────────────┐      SSH PTY      ┌─────────────┐
│   Browser   │ <----------------> │  WS Server  │ <----------------> │   Serveur   │
│  xterm.js   │                    │  (Bun)      │                    │   distant   │
└─────────────┘                    └─────────────┘                    └─────────────┘

Endpoint WebSocket

ws://connectors.33800.nowhere84.com/api/ssh/shell
Query: ?instance_id=uuid&token=jwt

Messages:
- Client -> Server: { "type": "input", "data": "ls -la\n" }
- Server -> Client: { "type": "output", "data": "..." }
- Server -> Client: { "type": "resize", "cols": 80, "rows": 24 }

Implementation technique

// Bun WebSocket
app.ws('/api/ssh/shell', {
  open(ws) {
    const { instance_id, token } = ws.data;
    // Verify auth
    // Connect SSH with PTY
    conn.shell({ term: 'xterm-256color', cols: 80, rows: 24 }, (err, stream) => {
      stream.on('data', (data) => ws.send({ type: 'output', data: data.toString() }));
      ws.onmessage = (msg) => stream.write(msg.data);
    });
  }
});

Frontend avec xterm.js

import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';

const term = new Terminal();
const ws = new WebSocket(`wss://connectors.../api/ssh/shell?instance_id=${id}`);

term.onData(data => ws.send(JSON.stringify({ type: 'input', data })));
ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === 'output') term.write(msg.data);
};

Taches


Estimation et Priorites

Feature Complexite Valeur Priorite
Double SSH Moyenne Haute 1
SFTP Moyenne Moyenne 2
WebSocket Haute Haute 3

Dependances npm a ajouter

Backend

Frontend

Securite

Tests

Notes

Issue PasswordAuthentication (27/01/2026)

Le serveur SSH prod-portainer (192.168.1.12) avait PasswordAuthentication no dans /etc/ssh/sshd_config. La librairie ssh2 ne pouvait pas s'authentifier par mot de passe.

Solution appliquee: Active PasswordAuthentication yes temporairement.

Solution recommandee: Utiliser l'option "auto-certif" qui genere une cle SSH et l'installe sur le serveur. Cela evite les problemes d'auth par mot de passe et est plus securise.