赞
踩
Paramiko是Python编程语言的一个SSH客户端。它在Python中实现了SSHv2协议,支持使用加密和认证的方式登录SSH服务器、上传和下载文件,以及执行SSH命令等功能。本文记录实验:在python下调用paramiko实现ssh功能后,出错和恢复。
由于Paramiko的功能强大,易于使用,因此在自动化管理、配置管理和任务调度等方面得到了广泛的应用。
个人认为python的paramiko模块是运维人员必学模块之一,其ssh登录功能是旅行居家必备工具。
安装paramiko很简单,pip install paramiko就搞定了,其依赖库会被一并安装。
paramiko的官方站点在这里:http://www.paramiko.org/。有需要深入研究的可以阅读官方文档。
paramiko模块提供了ssh及sft进行远程登录服务器执行命令和上传下载文件的功能。
- # 建立一个sshclient对象
- ssh = paramiko.SSHClient()
- # 允许将信任的主机自动加入到host_allow 列表,此方法必须放在connect方法的前面
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- # 调用connect方法连接服务器
- ssh.connect(hostname='192.168.2.129', port=22, username='super', password='super')
- # 执行命令
- stdin, stdout, stderr = ssh.exec_command('df -hl')
- # 结果放到stdout中,如果有错误将放到stderr中
- print(stdout.read().decode())
- # 关闭连接
- ssh.close()
方法1是传统的连接服务器、执行命令、关闭的一个操作,有时候需要登录上服务器执行多个操作,比如执行命令、上传/下载文件,方法1则无法实现,可以通过如下方式来操作
- # 实例化一个transport对象
- trans = paramiko.Transport(('192.168.2.129', 22))
- # 建立连接
- trans.connect(username='super', password='super')
-
- # 将sshclient的对象的transport指定为以上的trans
- ssh = paramiko.SSHClient()
- ssh._transport = trans
- # 执行命令,和传统方法一样
- stdin, stdout, stderr = ssh.exec_command('df -hl')
- print(stdout.read().decode())
-
- # 关闭连接
- trans.close()
- # 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
- pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
- # 建立连接
- ssh = paramiko.SSHClient()
- ssh.connect(hostname='192.168.2.129',
- port=22,
- username='super',
- pkey=pkey)
- # 执行命令
- stdin, stdout, stderr = ssh.exec_command('df -hl')
- # 结果放到stdout中,如果有错误将放到stderr中
- print(stdout.read().decode())
- # 关闭连接
- ssh.close()
以上需要确保被访问的服务器对应用户.ssh目录下有authorized_keys文件,也就是将服务器上生成的公钥文件保存为authorized_keys。并将私钥文件作为paramiko的登陆密钥
- # 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
- pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
- # 建立连接
- trans = paramiko.Transport(('192.168.2.129', 22))
- trans.connect(username='super', pkey=pkey)
-
- # 将sshclient的对象的transport指定为以上的trans
- ssh = paramiko.SSHClient()
- ssh._transport = trans
-
- # 执行命令,和传统方法一样
- stdin, stdout, stderr = ssh.exec_command('df -hl')
- print(stdout.read().decode())
-
- # 关闭连接
- trans.close()
- # 实例化一个trans对象# 实例化一个transport对象
- trans = paramiko.Transport(('192.168.2.129', 22))
- # 建立连接
- trans.connect(username='super', password='super')
-
- # 实例化一个 sftp对象,指定连接的通道
- sftp = paramiko.SFTPClient.from_transport(trans)
- # 发送文件
- sftp.put(localpath='/tmp/11.txt', remotepath='/tmp/22.txt')
- # 下载文件
- # sftp.get(remotepath, localpath)
- trans.close()
以上操作都是基本的连接,如果我们想实现一个类似xshell工具的功能,登录以后可以输入命令回车后就返回结果:
- import paramiko
- import os
- import select
- import sys
-
- # 建立一个socket
- trans = paramiko.Transport(('192.168.2.129', 22))
- # 启动一个客户端
- trans.start_client()
-
- # 如果使用rsa密钥登录的话
- '''
- default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
- prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
- trans.auth_publickey(username='super', key=prikey)
- '''
- # 如果使用用户名和密码登录
- trans.auth_password(username='super', password='super')
- # 打开一个通道
- channel = trans.open_session()
- # 获取终端
- channel.get_pty()
- # 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
- channel.invoke_shell()
- # 下面就可以执行你所有的操作,用select实现
- # 对输入终端sys.stdin和 通道进行监控,
- # 当用户在终端输入命令后,将命令交给channel通道,这个时候sys.stdin就发生变化,select就可以感知
- # channel的发送命令、获取结果过程其实就是一个socket的发送和接受信息的过程
- while True:
- readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
- # 如果是用户输入命令了,sys.stdin发生变化
- if sys.stdin in readlist:
- # 获取输入的内容
- input_cmd = sys.stdin.read(1)
- # 将命令发送给服务器
- channel.sendall(input_cmd)
-
- # 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
- if channel in readlist:
- # 获取结果
- result = channel.recv(1024)
- # 断开连接后退出
- if len(result) == 0:
- print("\r\n**** EOF **** \r\n")
- break
- # 输出到屏幕
- sys.stdout.write(result.decode())
- sys.stdout.flush()
-
- # 关闭通道
- channel.close()
- # 关闭链接
- trans.close()
注意:在windows中,sys.stdin不是一个socket或者file-like对象,而是一个PseudoOutputFile对象,不能被select处理。所以上面的脚本不能在windows中运行,只能用于linux。
- import paramiko
- import os
- import select
- import sys
- import tty
- import termios
-
- '''
- 实现一个xshell登录系统的效果,登录到系统就不断输入命令同时返回结果
- 支持自动补全,直接调用服务器终端
- '''
- # 建立一个socket
- trans = paramiko.Transport(('192.168.2.129', 22))
- # 启动一个客户端
- trans.start_client()
-
- # 如果使用rsa密钥登录的话
- '''
- default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
- prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
- trans.auth_publickey(username='super', key=prikey)
- '''
- # 如果使用用户名和密码登录
- trans.auth_password(username='super', password='super')
- # 打开一个通道
- channel = trans.open_session()
- # 获取终端
- channel.get_pty()
- # 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
- channel.invoke_shell()
-
- # 获取原操作终端属性
- oldtty = termios.tcgetattr(sys.stdin)
- try:
- # 将现在的操作终端属性设置为服务器上的原生终端属性,可以支持tab了
- tty.setraw(sys.stdin)
- channel.settimeout(0)
-
- while True:
- readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
- # 如果是用户输入命令了,sys.stdin发生变化
- if sys.stdin in readlist:
- # 获取输入的内容,输入一个字符发送1个字符
- input_cmd = sys.stdin.read(1)
- # 将命令发送给服务器
- channel.sendall(input_cmd)
-
- # 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
- if channel in readlist:
- # 获取结果
- result = channel.recv(1024)
- # 断开连接后退出
- if len(result) == 0:
- print("\r\n**** EOF **** \r\n")
- break
- # 输出到屏幕
- sys.stdout.write(result.decode())
- sys.stdout.flush()
- finally:
- # 执行完后将现在的终端属性恢复为原操作终端属性
- termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
-
- # 关闭通道
- channel.close()
- # 关闭链接
- trans.close()
实现SSH服务端必须继承ServerInterface,并实现里面相应的方法。具体代码如下:
- import socket
- import sys
- import threading
- import paramiko
-
- host_key = paramiko.RSAKey(filename='private_key.key')
-
- class Server(paramiko.ServerInterface):
- def __init__(self):
- #执行start_server()方法首先会触发Event,如果返回成功,is_active返回True
- self.event = threading.Event()
-
- #当is_active返回True,进入到认证阶段
- def check_auth_password(self, username, password):
- if (username == 'root') and (password == '123456'):
- return paramiko.AUTH_SUCCESSFUL
- return paramiko.AUTH_FAILED
-
- #当认证成功,client会请求打开一个Channel
- def check_channel_request(self, kind, chanid):
- if kind == 'session':
- return paramiko.OPEN_SUCCEEDED
- #命令行接收ip与port
- server = sys.argv[1]
- ssh_port = int(sys.argv[2])
-
- #建立socket
- try:
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP socket
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.bind((server, ssh_port))
- sock.listen(100)
- print '[+] Listening for connection ...'
- client, addr = sock.accept()
- except Exception, e:
- print '[-] Listen failed: ' + str(e)
- sys.exit(1)
- print '[+] Got a connection!'
-
- try:
- #用sock.accept()返回的socket实例化Transport
- bhSession = paramiko.Transport(client)
- #添加一个RSA密钥加密会话
- bhSession.add_server_key(host_key)
- server = Server()
- try:
- #启动SSH服务端
- bhSession.start_server(server=server)
- except paramiko.SSHException, x:
- print '[-] SSH negotiation failed'
- chan = bhSession.accept(20)
- print '[+] Authenticated!'
- print chan.recv(1024)
- chan.send("Welcome to my ssh")
- while True:
- try:
- command = raw_input("Enter command:").strip("\n")
- if command != 'exit':
- chan.send(command)
- print chan.recv(1024) + '\n'
- else:
- chan.send('exit')
- print 'exiting'
- bhSession.close()
- raise Exception('exit')
- except KeyboardInterrupt:
- bhSession.close()
- except Exception, e:
- print '[-] Caught exception: ' + str(e)
- try:
- bhSession.close()
- except:
- pass
- sys.exit(1)
到此这篇关于python使用paramiko实现ssh的功能详解的文章就介绍到这了,更多相关python paramiko实现ssh内容请搜索ZaLou.Cn以前的文章或继续浏览下面的相关文章希望大家以后多多支持ZaLou.Cn!
- import paramiko
-
- ssh = paramiko.SSHClient()
- key = paramiko.AutoAddPolicy()
- ssh.set_missing_host_key_policy(key)
- ssh.connect('192.168.3.164', 22, 'huatec', 'huatec123' ,timeout=5)
-
- while(True):
- cmdline = input("command: ")
- stdin, stdout, stderr = ssh.exec_command( cmdline )
- for row in stdout.readlines():
- row = row.replace('\r', '').replace('\n', '').replace('\t', '')
- print( row )
远方服务器名称: 'huatec', 密码:'huatec123',IP地址:'192.168.3.164'
运行后,有时发生错误:
ModuleNotFoundError: No module named 'cryptography'
这是因为cryptography模块陈旧,恢复办法是:
- python -m pip uninstall cryptography
- python -m pip install cryptography
再次实验,OK了!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。