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 |
|---|---|
OnSSHConnect | se establece la conexión SSH |
OnSSHDisconnect | la conexión SSH se cierra (con motivo y código) |
OnSSHError | ocurre un error de SSH |
OnSSHAuthSuccess / OnSSHAuthFailure | la autenticación tiene éxito o falla |
OnSSHHostKey | la clave del host necesita verificación (aceptar/rechazar) |
OnSSHChannelData | se reciben datos (stdout) en un canal |
OnSSHChannelExtendedData | se reciben datos extendidos (stderr) en un canal |
OnSSHChannelExitStatus | se recibe el código de salida del comando remoto |
OnSSHChannelExitSignal | el proceso remoto se termina por una señal (con el nombre de la señal) |
OnSSHKeyboardInteractive | el servidor solicita respuestas keyboard-interactive |
OnSSHAuthBanner | el 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;
