python使用paramiko实现ssh的功能详解


Posted in Python onMarch 06, 2020

个人认为python的paramiko模块是运维人员必学模块之一,其ssh登录功能是旅行居家必备工具。

安装paramiko很简单,pip install paramiko就搞定了,其依赖库会被一并安装。

paramiko的官方站点在这里:http://www.paramiko.org/。有需要深入研究的可以阅读官方文档。

paramiko模块提供了ssh及sft进行远程登录服务器执行命令和上传下载文件的功能。

一、基于用户名和密码的 sshclient 方式登录

# 建立一个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()

二、基于用户名和密码的 transport 方式登录

方法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()

三、 基于公钥密钥的 SSHClient 方式登录

# 指定本地的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的登陆密钥

四、 基于密钥的 Transport 方式登录

# 指定本地的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()

五、传文件 SFTP

# 实例化一个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。

七、上例支持tab自动补全

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服务端的实现

实现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内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python用来获得图片exif信息的库实例分析
Mar 16 Python
Python编程使用NLTK进行自然语言处理详解
Nov 16 Python
Django admin.py 在修改/添加表单界面显示额外字段的方法
Aug 22 Python
python使用python-pptx删除ppt某页实例
Feb 14 Python
python输入一个水仙花数(三位数) 输出百位十位个位实例
May 03 Python
Python求解排列中的逆序数个数实例
May 03 Python
Opencv求取连通区域重心实例
Jun 04 Python
python中tkinter窗口位置\坐标\大小等实现示例
Jul 09 Python
Python Pillow(PIL)库的用法详解
Sep 19 Python
python线程池 ThreadPoolExecutor 的用法示例
Oct 10 Python
Python 列表推导式需要注意的地方
Oct 23 Python
解决Tkinter中button按钮未按却主动执行command函数的问题
May 23 Python
python GUI库图形界面开发之PyQt5滚动条控件QScrollBar详细使用方法与实例
Mar 06 #Python
Python object类中的特殊方法代码讲解
Mar 06 #Python
python+Selenium自动化测试——输入,点击操作
Mar 06 #Python
使用 Python ssh 远程登陆服务器的最佳方案
Mar 06 #Python
使用python执行shell脚本 并动态传参 及subprocess的使用详解
Mar 06 #Python
python解析xml文件方式(解析、更新、写入)
Mar 05 #Python
如何使用pandas读取txt文件中指定的列(有无标题)
Mar 05 #Python
You might like
推荐一篇入门级的Class文章
2007/03/19 PHP
PHP 简单日历实现代码
2009/10/28 PHP
查找mysql字段中固定字符串并替换的几个方法
2012/09/23 PHP
mac下Apache + MySql + PHP搭建网站开发环境
2014/06/02 PHP
php简单分页类实现方法
2015/02/26 PHP
试用php中oci8扩展
2015/06/18 PHP
PHP读取CSV大文件导入数据库的实例
2017/07/24 PHP
使用jQuery实现的网页版的个人简历(可换肤)
2013/04/19 Javascript
js过滤特殊字符输入适合输入、粘贴、拖拽多种情况
2014/03/22 Javascript
JS 使用for循环遍历子节点查找元素
2014/09/06 Javascript
jQuery入门介绍之基础知识
2015/01/13 Javascript
JavaScript实现简单的数字倒计时
2015/05/15 Javascript
js实现仿qq消息的弹出窗效果
2016/01/06 Javascript
Node.js的Express框架使用上手指南
2016/03/12 Javascript
jQuery 判断是否包含在数组中Array[]的方法
2016/08/03 Javascript
使用mock.js随机数据和使用express输出json接口的实现方法
2018/01/07 Javascript
详解javascript设计模式三:代理模式
2019/03/25 Javascript
vue中使用极验验证码的方法(附demo)
2019/12/04 Javascript
[55:02]2014 DOTA2国际邀请赛中国区预选赛 HGT VS Orenda
2014/05/21 DOTA
[01:02:09]Liquid vs TNC 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21
2020/07/19 DOTA
[35:39]完美世界DOTA2联赛PWL S2 FTD.C vs Rebirth 第二场 11.22
2020/11/24 DOTA
Python高级用法总结
2018/05/26 Python
详解Django的CSRF认证实现
2018/10/09 Python
python字符串替换第一个字符串的方法
2019/06/26 Python
关于python中密码加盐的学习体会小结
2019/07/15 Python
Python 日期区间处理 (本周本月上周上月...)
2019/08/08 Python
python判断自身是否正在运行的方法
2019/08/08 Python
编写用C语言实现的求n阶阶乘问题的递归算法
2014/10/21 面试题
中专自我鉴定范文
2013/10/16 职场文书
早会主持词
2014/03/17 职场文书
保险公司演讲稿
2014/09/02 职场文书
简单通用的简历自我评价
2014/09/21 职场文书
工作作风建设心得体会
2014/10/22 职场文书
英文道歉信
2015/01/20 职场文书
红色电影观后感
2015/06/18 职场文书
《梅花魂》教学反思
2016/02/18 职场文书