Cliente SSH sgcIndy Componente Delphi

· Componentes

La administración remota de servidores, los despliegues automatizados, la gestión de configuraciones y la monitorización de infraestructura — todo ello depende de un acceso shell seguro. Tanto si necesitas ejecutar un único comando en un host remoto, abrir una sesión interactiva de terminal o montar un túnel de redirección de puertos, SSH es el protocolo que lo hace posible.

El paquete sgcIndy incluye TIdSSHClient — un componente cliente SSH nativo de Delphi que implementa el protocolo SSH-2 con soporte completo para ejecución de comandos, shells interactivos, asignación de pseudoterminales, redirección de puertos, keep-alive y algoritmos criptográficos modernos. Sin ejecutables SSH externos, sin wrappers de DLL — arquitectura de componente Delphi pura con una API basada en eventos.

Este artículo recorre las funcionalidades principales y ofrece ejemplos de código en Delphi para los casos de uso SSH más habituales.

Funcionalidades clave

Ejecución de comandos
Ejecuta comandos remotos y captura stdout, stderr y códigos de salida. Método de conveniencia en una línea o control completo basado en canales.
Shell interactiva
Abre sesiones de shell interactivas con soporte de pseudoterminal. Envía comandos, recibe la salida de forma asíncrona y gestiona el redimensionado del terminal.
Redirección de puertos
Configura túneles TCP/IP directos y redirección inversa. Accede a servicios remotos a través de túneles SSH cifrados.
Criptografía moderna
Curve25519, ECDH, AES-GCM, claves Ed25519. Negociación de algoritmos configurable con valores por defecto seguros desde el primer momento.
Varios métodos de autenticación
Autenticación por contraseña, por clave pública (RSA, ECDSA, Ed25519) y keyboard-interactive. Verificación de la clave del host mediante callback de evento.
Multicanal
Hasta 10 canales concurrentes por conexión. Ejecuta varios comandos, shells o túneles simultáneamente sobre una única sesión SSH.

Inicio rápido — ejecutar un comando remoto

El caso de uso más sencillo: conectarse, ejecutar un comando, obtener la salida y desconectarse — todo en unas pocas líneas.

var
  oSSH: TIdSSHClient;
  vOutput: string;
begin
  oSSH := TIdSSHClient.Create(nil);
  Try
    oSSH.Host := 'server.example.com';
    oSSH.Port := 22;
    oSSH.Authentication.Username := 'admin';
    oSSH.Authentication.Password := 'secret';
    oSSH.Connect;
    // Execute a command and capture the output
    vOutput := oSSH.Execute('df -h');
    WriteLn(vOutput);
    oSSH.Disconnect;
  Finally
    oSSH.Free;
  End;
end;

En una línea. El método Execute abre un canal, ejecuta el comando, espera el resultado y devuelve la salida como cadena — perfecto para automatización por scripts.

Autenticación

Se admiten tres métodos de autenticación. Los tres están activados por defecto y el cliente los negocia automáticamente con el servidor.

Contraseña

oSSH.Authentication.Username := 'admin';
oSSH.Authentication.Password := 'secret';

Clave pública

oSSH.Authentication.Username := 'deploy';
oSSH.Authentication.PrivateKeyFile := 'C:\keys\id_ed25519';
oSSH.Authentication.PublicKeyFile := 'C:\keys\id_ed25519.pub';
oSSH.Authentication.Passphrase := 'keypassphrase';

Keyboard-Interactive

Gestiona prompts de autenticación multietapa (MFA, OTP, preguntas de seguridad) mediante el evento OnSSHKeyboardInteractive.

oSSH.OnSSHKeyboardInteractive := OnKeyboardInteractive;
procedure TForm1.OnKeyboardInteractive(Sender: TObject;
  const aName, aInstruction: string;
  aPrompts: TStrings; aEchos: TList; aResponses: TStrings);
begin
  // Respond to each prompt (e.g., "Password:", "OTP:")
  if aPrompts.Count > 0 then
    aResponses.Add('mypassword');
end;

Verificación de la clave del host

oSSH.OnSSHHostKey := OnHostKey;
procedure TForm1.OnHostKey(Sender: TObject;
  const aHostKeyType, aFingerprint: string;
  var aAction: TIdSSHHostKeyVerification);
begin
  // Accept or reject based on known fingerprint
  aAction := sshHostKeyAccept;
end;

Ejecución de comandos

Dos enfoques para ejecutar comandos remotos: el método de conveniencia Execute para casos sencillos o la API basada en canales para tener control total sobre entrada, salida y estado de salida.

Sencillo: método Execute

// Execute and get output (30-second timeout by default)
vOutput := oSSH.Execute('ls -la /var/log');
// Custom timeout (10 seconds)
vOutput := oSSH.Execute('cat /etc/hostname', 10000);

Avanzado: ejecución basada en canales

Para ejecución asíncrona con manejo separado de stdout/stderr y seguimiento del estado de salida.

// Open a channel and execute a command
var
  vChannelId: Cardinal;
begin
  vChannelId := oSSH.OpenChannel;
  oSSH.RequestExec(vChannelId, 'tar czf /tmp/backup.tar.gz /data');
  // Output arrives via OnSSHChannelData event
  // Exit status arrives via OnSSHChannelExitStatus event
end;
// Handle stdout
procedure TForm1.OnChannelData(Sender: TObject;
  aChannelId: Cardinal; const aData: TIdBytes);
begin
  Memo1.Lines.Add(BytesToString(aData));
end;
// Handle stderr
procedure TForm1.OnChannelExtendedData(Sender: TObject;
  aChannelId: Cardinal; aDataType: Cardinal; const aData: TIdBytes);
begin
  MemoErrors.Lines.Add(BytesToString(aData));
end;
// Handle exit status
procedure TForm1.OnExitStatus(Sender: TObject;
  aChannelId: Cardinal; aExitStatus: Integer);
begin
  WriteLn('Command exited with code: ' + IntToStr(aExitStatus));
end;

Interactive Shell Sessions

Open a pseudo-terminal and interact with a remote shell — ideal for building SSH terminal emulators or automating interactive CLI workflows.

// Open channel, request PTY, then request shell
var
  vChannelId: Cardinal;
begin
  vChannelId := oSSH.OpenChannel;
  // Request a pseudo-terminal (xterm, 80x24)
  oSSH.RequestPTY(vChannelId, 'xterm', 80, 24);
  // Start the shell
  oSSH.RequestShell(vChannelId);
  // Send commands to the shell
  oSSH.SendChannelData(vChannelId, 'cd /var/log' + #13#10);
  oSSH.SendChannelData(vChannelId, 'tail -f syslog' + #13#10);
end;

Redimensionado del terminal y señales

// Notify the server of terminal resize
oSSH.SendWindowChange(vChannelId, 120, 40, 0, 0);
// Send Ctrl+C (interrupt signal)
oSSH.SendSignal(vChannelId, 'INT');
// Set an environment variable before running commands
oSSH.SetEnvironmentVariable(vChannelId, 'LANG', 'en_US.UTF-8');
// Signal end of input
oSSH.SendEOF(vChannelId);

Redirección de puertos (túneles SSH)

Crea túneles cifrados para acceder a servicios remotos como si fueran locales. Útil para acceder de forma segura a bases de datos, paneles de administración o APIs internas detrás de firewalls.

Tunelización TCP/IP directa (local forward)

// Tunnel to a remote database through SSH
var
  vTunnelId: Cardinal;
begin
  vTunnelId := oSSH.OpenDirectTCPIP(
    'db-internal.example.com',  // Remote host
    5432,                        // Remote port (PostgreSQL)
    '127.0.0.1',                 // Originator IP
    0);                           // Originator port
  // Send/receive data through the tunnel
  oSSH.SendChannelData(vTunnelId, vDatabaseQuery);
end;

Redirección inversa (remote forward)

// Ask the server to forward a remote port to us
oSSH.RequestForwarding('0.0.0.0', 8080);
// Cancel the forwarding
oSSH.CancelForwarding('0.0.0.0', 8080);

Keep-alive y opciones de conexión

Evita que firewalls o balanceadores de carga cierren conexiones inactivas gracias al mecanismo keep-alive integrado.

// Send keep-alive every 30 seconds, disconnect after 3 failures
oSSH.KeepAlive.Enabled := True;
oSSH.KeepAlive.Interval := 30;
oSSH.KeepAlive.MaxCount := 3;
// Connection options
oSSH.SSHOptions.ConnectTimeout := 10000;  // 10 seconds
oSSH.SSHOptions.ReadTimeout := 30000;     // 30 seconds
oSSH.SSHOptions.MaxChannels := 10;       // Concurrent channels

Configuración de algoritmos criptográficos

Los valores por defecto son seguros y modernos. Personaliza la negociación de algoritmos cuando lo exijan políticas de cumplimiento o compatibilidad con servidores antiguos.

Categoría Algoritmos admitidos
Intercambio de claves Curve25519, ECDH (P-256, P-384, P-521), DH Group14/16
Claves de host Ed25519, ECDSA (P-256, P-384, P-521), RSA (SHA2-256, SHA2-512)
Cifrados AES-256/192/128-CTR, AES-256/128-GCM
MAC HMAC-SHA2-256, HMAC-SHA2-512, HMAC-SHA1
// Customize algorithm preferences
oSSH.Algorithms.KexAlgorithms := 'curve25519-sha256';
oSSH.Algorithms.Ciphers := 'aes256-gcm@openssh.com'
		,aes256-ctr';
oSSH.Algorithms.HostKeyAlgorithms := 'ssh-ed25519,rsa-sha2-256';
oSSH.Algorithms.MACs := 'hmac-sha2-256';
// Force re-keying to refresh encryption
oSSH.Rekey;

Referencia de eventos

El componente proporciona callbacks de evento granulares para cada etapa del ciclo de vida SSH.

Evento Se dispara cuando
OnSSHConnectse establece la conexión SSH
OnSSHDisconnectla conexión SSH se cierra (con motivo y código)
OnSSHErrorocurre un error de SSH
OnSSHAuthSuccess / OnSSHAuthFailurela autenticación tiene éxito o falla
OnSSHHostKeyla clave del host necesita verificación (aceptar/rechazar)
OnSSHChannelDatase reciben datos (stdout) en un canal
OnSSHChannelExtendedDatase reciben datos extendidos (stderr) en un canal
OnSSHChannelExitStatusse recibe el código de salida del comando remoto
OnSSHChannelExitSignalel proceso remoto se termina por una señal (con el nombre de la señal)
OnSSHKeyboardInteractiveel servidor solicita respuestas keyboard-interactive
OnSSHAuthBannerel servidor envía un mensaje de banner de autenticación

Ejemplo completo: script de despliegue automatizado

Un cliente SSH completamente configurado que se conecta con autenticación por clave, ejecuta comandos de despliegue y captura el estado de salida.

uses
  IdSSHClient, IdSSHClasses;
var
  oSSH: TIdSSHClient;
  vOutput: string;
begin
  oSSH := TIdSSHClient.Create(nil);
  Try
    // Connection
    oSSH.Host := 'production.example.com';
    oSSH.Port := 22;
    // Key-based authentication
    oSSH.Authentication.Username := 'deploy';
    oSSH.Authentication.PrivateKeyFile := 'C:\keys\deploy_ed25519';
    // Keep connection alive through firewalls
    oSSH.KeepAlive.Enabled := True;
    oSSH.KeepAlive.Interval := 30;
    // Events
    oSSH.OnSSHHostKey := OnHostKey;
    oSSH.OnSSHError := OnError;
    // Connect
    oSSH.Connect;
    // Run deployment commands
    vOutput := oSSH.Execute('cd /opt/app && git pull origin main');
    WriteLn(vOutput);
    vOutput := oSSH.Execute('systemctl restart myapp');
    WriteLn(vOutput);
    vOutput := oSSH.Execute('systemctl status myapp');
    WriteLn(vOutput);
    // Disconnect
    oSSH.Disconnect;
  Finally
    oSSH.Free;
  End;
end;