원격 서버 관리, 자동화된 배포, 설정 관리, 인프라 모니터링 — 이 모든 것은 보안 셸 접근에 의존해요. 원격 호스트에서 단일 명령을 실행하거나 대화형 터미널 세션을 열거나 포트 포워딩 터널을 설정해야 할 때, SSH는 이를 가능하게 해주는 프로토콜이에요.
sgcIndy 패키지에는 TIdSSHClient가 포함돼 있어요 — 명령 실행, 대화형 셸, 의사 터미널 할당, 포트 포워딩, Keep-Alive 및 최신 암호화 알고리즘을 완벽히 지원하는 SSH-2 프로토콜을 구현한 네이티브 Delphi SSH 클라이언트 컴포넌트예요. 외부 SSH 실행 파일이나 DLL 래퍼 없이 — 이벤트 기반 API를 제공하는 순수 Delphi 컴포넌트 아키텍처예요.
이 글에서는 주요 기능을 살펴보고 가장 일반적인 SSH 사용 사례에 대한 Delphi 코드 예제를 제공해요.
주요 기능
|
명령 실행 원격 명령을 실행하고 stdout, stderr, 종료 코드를 캡처해요. 한 줄짜리 편의 메서드 또는 전체 채널 기반 제어를 사용할 수 있어요. |
대화형 셸 의사 터미널을 지원하는 대화형 셸 세션을 열 수 있어요. 명령을 보내고 비동기로 출력을 수신하며 터미널 크기 변경도 처리해요. |
포트 포워딩 직접 TCP/IP 터널과 역방향 포워딩을 설정해요. 암호화된 SSH 터널을 통해 원격 서비스에 접근할 수 있어요. |
|
최신 암호화 Curve25519, ECDH, AES-GCM, Ed25519 키를 지원해요. 별도 설정 없이 안전한 기본값으로 알고리즘 협상을 구성할 수 있어요. |
다양한 인증 방식 비밀번호, 공개 키(RSA, ECDSA, Ed25519), 키보드 대화형 인증을 지원해요. 이벤트 콜백을 통한 호스트 키 검증이 가능해요. |
멀티 채널 연결당 최대 10개의 동시 채널을 지원해요. 단일 SSH 세션을 통해 여러 명령, 셸 또는 터널을 동시에 실행할 수 있어요. |
빠른 시작 — 원격 명령 실행
가장 간단한 사용 사례예요. 연결하고, 명령을 실행하고, 출력을 받고, 연결을 해제하는 모든 작업을 몇 줄로 처리해요.
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;
한 줄 처리. Execute 메서드는 채널을 열고, 명령을 실행하고, 결과를 기다린 후, 출력을 문자열로 반환해요 — 스크립트 자동화에 안성맞춤이에요.
인증
세 가지 인증 방식이 지원돼요. 세 가지 모두 기본적으로 활성화되며 클라이언트는 서버와 자동으로 협상해요.
비밀번호
oSSH.Authentication.Username := 'admin';
oSSH.Authentication.Password := 'secret';
공개 키
oSSH.Authentication.Username := 'deploy';
oSSH.Authentication.PrivateKeyFile := 'C:\keys\id_ed25519';
oSSH.Authentication.PublicKeyFile := 'C:\keys\id_ed25519.pub';
oSSH.Authentication.Passphrase := 'keypassphrase';
키보드 대화형
OnSSHKeyboardInteractive 이벤트를 통해 다단계 인증 프롬프트(MFA, OTP, 보안 질문)를 처리해요.
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;
호스트 키 검증
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;
명령 실행
원격 명령을 실행하는 두 가지 방식이 있어요. 간단한 경우에는 편의 메서드인 Execute를, 입력, 출력, 종료 상태를 완전히 제어해야 할 때는 채널 기반 API를 사용해요.
간단한 방법: 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);
고급: 채널 기반 실행
stdout/stderr를 별도로 처리하고 종료 상태를 추적하는 비동기 실행에 사용해요.
// 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;
대화형 셸 세션
의사 터미널을 열고 원격 셸과 상호 작용해요 — SSH 터미널 에뮬레이터를 구축하거나 대화형 CLI 워크플로를 자동화하는 데 이상적이에요.
// 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;
터미널 크기 변경 및 시그널
// 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);
포트 포워딩 (SSH 터널)
원격 서비스에 마치 로컬인 것처럼 접근할 수 있는 암호화된 터널을 만들어요. 방화벽 뒤에 있는 데이터베이스, 관리자 패널 또는 내부 API에 안전하게 접근할 때 유용해요.
직접 TCP/IP 터널링 (로컬 포워딩)
// 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;
역방향 포워딩 (원격 포워딩)
// 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 및 연결 옵션
내장 Keep-Alive 메커니즘을 통해 유휴 연결이 방화벽이나 로드 밸런서에 의해 끊어지는 것을 방지해요.
// 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
암호화 알고리즘 설정
기본값은 안전하고 최신이에요. 컴플라이언스 정책이나 레거시 서버 호환성이 필요한 경우 알고리즘 협상을 사용자 정의할 수 있어요.
| 카테고리 | 지원 알고리즘 |
|---|---|
| 키 교환 | Curve25519, ECDH (P-256, P-384, P-521), DH Group14/16 |
| 호스트 키 | Ed25519, ECDSA (P-256, P-384, P-521), RSA (SHA2-256, SHA2-512) |
| 암호 | 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;
이벤트 레퍼런스
이 컴포넌트는 SSH 라이프사이클의 모든 단계에 대해 세밀한 이벤트 콜백을 제공해요.
| 이벤트 | 발생 시점 |
|---|---|
OnSSHConnect | SSH 연결이 설정됐을 때 |
OnSSHDisconnect | SSH 연결이 종료될 때 (이유 및 코드 포함) |
OnSSHError | SSH 오류가 발생했을 때 |
OnSSHAuthSuccess / OnSSHAuthFailure | 인증이 성공하거나 실패했을 때 |
OnSSHHostKey | 호스트 키 검증이 필요할 때 (수락/거부) |
OnSSHChannelData | 채널에서 데이터(stdout)를 수신했을 때 |
OnSSHChannelExtendedData | 채널에서 확장 데이터(stderr)를 수신했을 때 |
OnSSHChannelExitStatus | 원격 명령의 종료 코드를 수신했을 때 |
OnSSHChannelExitSignal | 원격 프로세스가 시그널로 종료됐을 때 (시그널 이름 포함) |
OnSSHKeyboardInteractive | 서버가 키보드 대화형 응답을 요청할 때 |
OnSSHAuthBanner | 서버가 인증 배너 메시지를 보낼 때 |
전체 예제: 자동화된 배포 스크립트
키 인증으로 연결하고, 배포 명령을 실행하고, 종료 상태를 캡처하는 완전히 설정된 SSH 클라이언트예요.
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;
