파이썬에서 SSH 클라이언트 사용

1. SSH (Secure Shell)

SSH는 다른 컴퓨터에 Secure한 방식으로 연결하여 명령을 수행할 수 있는 네트워트 기능으로 telnet을 대체하는 보다 안전한 방식의 터미널 기능이다. Telnet의 모든 데이타는 Clear Text로 통신되는 반면, SSH의 데이타는 Public Key Encryption을 사용하여 모두 암호화된다. SSH는 디폴트로 포트 22를 사용하고, Telnet은 디폴트로 포트 23을 사용한다.

2. SSH 파이썬 패키지

SSH는 클라이언트/서버 방식으로 통신하는데, SSH Client가 SSH Server에 연결하여 데이타를 주고 받는다. 파이썬에서 SSH를 사용하기 위해서는 paramiko, netmiko 등과 같은 파이썬 패키지를 사용할 수 있다. 여기서는 paramiko 패키지를 사용해 보는데, 아래는 pip을 사용하여 paramiko 패키지를 설치하는 명령이다.

pip install paramiko

3. SSH 클라이언트

paramiko 패키지에서 SSH 클라이언트를 사용하기 위해서는 기본적으로 다음과 같은 스텝을 밟는다.

  1. paramiko.SSHClient 클래스의 인스턴스를 만들고,
  2. SSHClient 인스턴스로부터 connect() 메서드를 호출하여 서버에 연결한 후,
  3. SSHClient 인스턴스로부터 명령을 보내고 결과를 리턴받는다.
  4. SSHClient 인스턴스로부터 close() 메서드를 호출하여 연결을 닫는다.

아래 예제는 SSH로 서버에 연결한 후 해당 로그인 계정의 홈 디렉토리의 파일 리스트를 출력해 보는 코드이다. 서버명, 로그인명, 암호 등은 프로그램 실행시 콘솔에 입력받도록 하였는데, 특히 암호는 입력되는 문자를 숨기기 위해 getpass() 함수를 사용하였다.

import paramiko
import getpass

cli = paramiko.SSHClient()
cli.set_missing_host_key_policy(paramiko.AutoAddPolicy)

server = input("Server: ")  # 호스트명이나 IP 주소
user = input("Username: ")  
pwd = getpass.getpass("Password: ") # 암호입력 숨김

cli.connect(server, port=22, username=user, password=pwd)
stdin, stdout, stderr = cli.exec_command("ls -la")
lines = stdout.readlines()
print(''.join(lines))

cli.close()

위 예제는 paramiko.SSHClient 클래스로부터 cli 라는 인스턴스를 생성한 후, cli.connect() 메서드를 사용하여 SSH 서버에 접속한다. connect() 메서드는 여러 가지 파라미터들을 받아들일 수 있는데, 기본적으로 호스트명과 사용자 및 암호 등을 지정하고, 추가적으로 포트번호, 타임아웃, 압축기능 등을 지정할 수 있다. SSH는 접속시 known_hosts에 등록된 호스트키를 체크하는데 만약 접속하는 서버의 호스트키가 없으면 접속을 거부하게 된다. 만약 이러한 보안 기능을 사용하지 않고, 자동으로 새 호스트키를 추가하도록 하기 위해서는 cli.set_missing_host_key_policy() 을 사용하여 AutoAddPolicy 를 지정하면 된다.

exec_command() 메서드는 SSH 서버에 어떤 명령을 실행하도록 할 때 사용된다. 예를 들어, 위의 예제에서는 "ls -la" 명령을 실행하여 그 실행 결과를 표준콘솔입력(stdin), 표준콘솔출력(stdout), 표준에러출력(stderr)에 리턴한다. 이어 표준출력으로 전달된 stdout으로부터 readlines()를 통해 출력 결과를 라인별로 읽어들이고, 이를 화면에 출력(print)한다.

마지막으로 SSHClient 인스턴스의 사용을 마친 후에는 close()를 메서드를 호출하여 연결을 종료해 주어야 한다.

또 다른 예제로서 아래는 exec_command() 대신 invoke_shell()을 사용한 방식으로 이 invoke_shell() 메서드는 서버에 새로운 interactive shell session 을 생성하고 채널을 리턴한다. 클라이언트는 이 채널을 통해 계속 명령을 송신하고 결과를 수신할 수 있다. invoke_shell() 메서드가 실행되면 새로운 쉘이 생성되어 화면에 표시된다.

import paramiko
import getpass
import time

cli = paramiko.SSHClient()
cli.set_missing_host_key_policy(paramiko.AutoAddPolicy)
cli.connect("test.com", username="user", password="pwd")

# 새로운 interactive shell session 생성
channel = cli.invoke_shell()

# 명령 송신
channel.send("ls -la\n")
time.sleep(1.0)
# 결과 수신
output = channel.recv(65535).decode("utf-8")
print(output)

cli.close()

채널에 명령을 보내기 위해 send() 메서드를 사용하며, 결과를 수신하기 위해 recv() 메서드를 사용한다. recv() 메서드의 파라미터인 65535는 수신받는 최대 바이트수를 가리키며, recv()가 바이트스트림을 리턴하므로 이를 적절히 디코딩할 필요가 있을 수 있다. 여기서는 decode()를 사용하여 UTF-8으로 디코딩하였다.

Python 프로그래밍 실습

본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.