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的装饰器的运用
May 05 Python
对PyTorch torch.stack的实例讲解
Jul 30 Python
使用Py2Exe for Python3创建自己的exe程序示例
Oct 31 Python
python判断完全平方数的方法
Nov 13 Python
PyCharm鼠标右键不显示Run unittest的解决方法
Nov 30 Python
Python 处理文件的几种方式
Aug 23 Python
Python 操作mysql数据库查询之fetchone(), fetchmany(), fetchall()用法示例
Oct 17 Python
Django User 模块之 AbstractUser 扩展详解
Mar 11 Python
Python批量将图片灰度化的实现代码
Apr 11 Python
python opencv 实现读取、显示、写入图像的方法
Jun 08 Python
Python sorted对list和dict排序
Jun 09 Python
Python3获取cookie常用三种方案
Oct 05 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
深入探讨PHP中的内存管理问题
2011/08/31 PHP
示例详解Laravel重置密码代码重构
2016/08/10 PHP
JS应用之禁止抓屏、复制、打印
2008/02/21 Javascript
js实现的日期操作类DateTime函数代码
2010/03/16 Javascript
js 强制弹出窗口代码研究-又一款代码
2010/03/20 Javascript
Js sort排序使用方法
2011/10/17 Javascript
jQuery中hide()方法用法实例
2014/12/24 Javascript
JavaScript中的parse()方法使用简介
2015/06/12 Javascript
js图片卷帘门导航菜单特效代码分享
2015/09/10 Javascript
Javascript的表单验证-初识正则表达式
2016/03/18 Javascript
javascript使用闭包模拟对象的私有属性和方法
2016/10/05 Javascript
AngularJS实现DOM元素的显示与隐藏功能
2016/11/22 Javascript
详解JavaScript中this的指向问题
2017/01/20 Javascript
thinkphp标签实现bootsrtap轮播carousel实例代码
2017/02/19 Javascript
Vue.js 2.0 移动端拍照压缩图片上传预览功能
2017/03/06 Javascript
jQuery UI 实例讲解 - 日期选择器(Datepicker)
2017/09/18 jQuery
jQuery实现验证表单密码一致性及正则表达式验证邮箱、手机号的方法
2017/12/05 jQuery
微信小程序封装的HTTP请求示例【附升级版】
2019/05/11 Javascript
python虚拟环境 virtualenv的简单使用
2020/01/21 Javascript
Vue实现简单计算器
2021/01/20 Vue.js
[01:50]《我与DAC》之玩家:iG夺冠时的那面红旗
2018/03/29 DOTA
使用Python3制作TCP端口扫描器
2017/04/17 Python
简单了解什么是神经网络
2017/12/23 Python
用Python将一个列表分割成小列表的实例讲解
2018/07/02 Python
Django项目中使用JWT的实现代码
2019/11/04 Python
Django框架获取form表单数据方式总结
2020/04/22 Python
浅析Python 条件控制语句
2020/07/15 Python
Django中ORM的基本使用教程
2020/12/22 Python
canvas实现手机的手势解锁的步骤详细
2020/03/16 HTML / CSS
英国家庭和商业健身器材购物网站:Fitness Options
2018/07/05 全球购物
办公室内勤岗位职责范本
2013/12/09 职场文书
大学生求职信
2014/06/17 职场文书
在职员工证明书
2014/09/19 职场文书
python必学知识之文件操作(建议收藏)
2021/05/30 Python
JavaScript流程控制(循环)
2021/12/06 Javascript
MYSQL常用函数介绍
2022/05/05 MySQL