Python 通过 Paramiko 访问 SSH 服务

2021-08-12 ssh linux security

Paramiko 实现了 SSH2 协议,用于与远程机器建立经过认证和加密后的安全连接,与 SSL 不同的是,SSH 不需要权威机构签署的分层证书,采用分布式的方式管理。

简介

通过如下命令安装。

pip3 install paramiko -i https://pypi.tuna.tsinghua.edu.cn/simple/

接着直接介绍比较常用的场景。

示例

登录主机

import paramiko

ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 登录主机
private = paramiko.RSAKey.from_private_key_file('/tmp/id_rsa')
ssh.connect(
    hostname='127.0.0.1', port=22, # 设置主机地址和端口
    username='foobar',             # 设置登录用户名
    password='passwd',             # 采用用户名+密码方式登录
    key=private,                   # 采用用户名+公钥方式登录
)

# 执行命令并获取结果
stdin, stdout, stderr = ssh.exec_command('ls')
result = stdout.read()
  
# 关闭连接
ssh.close()

另外,SSHClient() 里面有一个 transport 变量,用于设置连接,不过不建议使用。

import paramiko

transport = paramiko.Transport(('127.0.0.1', 22))
transport.connect(username='root', password='password')

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command('df')
print (str(stdout.read(),encoding='utf-8'))

transport.close()

还可以手动执行。

# 建立连接
trans = paramiko.Transport((ip, port))
trans.connect(username=username, password=password)

# 开启会话并设置超时时间
chan = trans.open_session()
chan.settimeout(session_timeout)

# 开启、激活远程Terminal
chan.get_pty()
chan.invoke_shell()

# 然后可以通过如下发送、接收
chan.send('command')
chan.recv(recv_buffer)

上传下载文件

import paramiko
  
transport = paramiko.Transport(('192.168.1.1', 22))
transport.connect(username='foobar', password='passwd')
  
sftp = paramiko.SFTPClient.from_transport(transport)

# 上传下载文件
sftp.put('/tmp/HelloWorld.py', '/tmp/HelloWorld.py')
sftp.get('/tmp/HelloWorld.py', '/tmp/HelloWorld.py')
  
transport.close()

执行命令 & 上传下载

有时需要同时执行命令和上传下载文件,那么可以只使用一个 SSHClient,通过 get_transport() 来创建 Transport 对象。

import paramiko
   
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect(hostname='127.0.0.1', port=22, username='foobar', password='passwd')
 
trans = ssh_client.get_transport()
sftp = paramiko.SFTPClient.from_transport(trans)
sftp.get_channel()
sftp.put('source','target')
sftp.get('source','target')

stdin, stdout, stderr = ssh.exec_command('ls')
result = stdout.read()
   
ssh.close()

常见问题

private key file is encrypted

完整报错 paramiko.ssh_exception.PasswordRequiredException: private key file is encrypted,如果密码没错误,可看下私钥文件,如果开头是 -----BEGIN OPENSSH PRIVATE KEY-----,会导致 paramiko 无法识别。

此时需要在执行 ssh-keygen 命令时增加 -m PEM 参数,指定生成 RSA 格式的密钥对,对应开头是 -----BEGIN RSA PRIVATE KEY----- 格式。