python paramiko
简介:
paramiko 是 python 下对 ssh(v2) 协议封装的一个库, 可以用于实现客户端或者服务器端的一些功能。本章节主要讲述如何实现客户端功能
安装:
pip install paramiko
常用组件:
Channel 实现 ssh 通道建立和维护功能
Client 实现 ssh 客户端功能
SFTP 实现 sftp 功能
Transport 实现 ssh 客户端和服务器端数据传输功能
Client:
Client 组件主要有以下几个 class: SSHClient 对 Transport 的高级封装, 实现了传输、通道、SFTP 等方法 以下几个 class 实现 ssh 新主机密钥管理策略: AutoAddPolicy 自动添加主机名和秘钥到 HostKeys 对象(默认为 known_hosts) RejectPolicy 缺省值, 自动拒绝未知的主机和秘钥 WarningPolicy 类似于 AutoAddPolicy 但会发出一个警告 paramiko.client.SSHClient 常用方法: load_system_host_keys() # 加载 known_hosts 文件默认为 ~/.ssh/known_hosts set_missing_host_key_policy() # 设置新主机和密码管理策略, 接受一个参数, 值可以是 AutoAddPolicy、RejectPolicy、WarningPolicy, 默认为 RejectPolicy connect() # 建立服务器和客户端之间的连接 参数: hostname # 远程主机的地址 port=22 # 远程主机 sshd 监听的端口, 默认 22 username=None # 要进行身份验证的用户名(默认为当前系统用户的用户名) password=None # 用户名对应的密码, 使用秘钥登录时如果 passphrase 没有给定值而 password 给定了值时, password 将作为 key 的解密密码 passphrase=None # ssh key 的解密密码 pkey=None # 指定 ssh 秘钥路径(如果该选项不为 None , 将启用 ssh 秘钥认证) key_filename=None # 尝试进行身份验证的可选秘钥文件或者文件列表 timeout=None # TCP 连接超时时间 allow_agent=True # 是否允许连接到 ssh 代理, 默认允许 look_for_keys=True # 是否允许 paramiko 在当前系统的 ~/.ssh/ 中搜索秘钥用于尝试认证, 默认允许 compress=False # 是否打开压缩 banner_timeout=None # 等待显示 ssh 标题的超时时间 auth_timeout=None # 等待身份认证的超时时间 exec_command() # 执行远程命令 参数: command # 执行指定的 shell 命令 timeout # 设置命令超时时间 environment # 设置 shell 环境变量, 字典类型 返回值: stdint # 标准输入 stdout # 标准输出 stderr # 标准错误 get_transport() # 获取底层的 transport 对象, 用于执行低级的任务 返回值: 返回 Transport 对象 invoke_shell() # 打开一个 ssh 交互式会话 参数: term # 模拟终端的类型 width # 终端窗口的宽度(以字符为单位) height # 终端窗口的高度(以字符为单位) width_pixels # 终端窗口的宽度(以像素为单位) height_pixels # 终端窗口的高度(以像素为单位) environment # 设置 shell 环境变量, 字典类型 open_sftp() # 向 ssh 服务器申请打开 sftp close() # 断开和服务器的连接 异常: BadHostKeyException 无法验证服务器的主机密钥 AuthenticationException 认证失败 SSHException 连接或建立 SSH 会话时出现任何其他错误 socket.error 连接时发生套接字错误
Client 示例:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : HuYuan # @File : paramiko_ssh_client.py import paramiko class UseSSHClient: def __init__(self, hostname, username, port=22, password=None, pkey=None, timeout=30, passphrase=None): self.hostname = hostname self.username = username self.port = port self.password = password self.pkey = pkey self.timeout = timeout self.passphrase = passphrase self._open_ssh() def get_key_obj(self, pkeyobj, pkey_file=None, pkey_obj=None, password=None): if pkey_file: with open(pkey_file) as fo: try: pkey = pkeyobj.from_private_key(fo, password=password) return pkey except: pass else: try: pkey = pkeyobj.from_private_key(pkey_obj, password=password) return pkey except: pkey_obj.seek(0) def _open_ssh(self): sshclient = paramiko.client.SSHClient() sshclient.set_missing_host_key_policy(paramiko.client.AutoAddPolicy) if self.password: sshclient.connect(hostname=self.hostname, username=self.username, port=self.port, password=self.password, timeout=self.timeout) else: # 解析 key pkey = get_key_obj(paramiko.RSAKey, pkey_file=self.pkey) or \ get_key_obj(paramiko.DSSKey, pkey_file=self.pkey) or \ get_key_obj(paramiko.ECDSAKey, pkey_file=self.pkey) or \ get_key_obj(paramiko.Ed25519Key, pkey_file=self.pkey) sshclient.connect(hostname=self.hostname, username=self.username, pkey=pkey, port=self.port, timeout=self.timeout) self.ssh = sshclient def exec_comd(self, cmd): result = self.ssh.exec_command(cmd) return result def sftp_get(self, server_path, local_path): sftp = self.ssh.open_sftp() sftp.get(server_path, local_path) def sftp_put(self, server_path, local_path): sftp = self.ssh.open_sftp() sftp.put(local_path, server_path) def close(self): self.ssh.close() if __name__ == '__main__': hostname = '192.168.1.100' username = 'root' password = '123.com' sshClient = UseSSHClient(hostname=hostname, username=username, password=password) sshClient.sftp_get('/etc/fstab', 'fstab') sshClient.sftp_put('/tmp/fstab', 'fstab') stdin, stdout, stderr = sshClient.exec_comd('ls /tmp/fstab') print(stdout.read()) sshClient.close()
pkey 对象:
paramiko 目前支持 4 总 key 认证, 分别为: RSAKey --> rsa 加密 --> 实现 class paramiko.rsakey.RSAKey DSSKey --> dsa 加密 --> 实现 class paramiko.dsskey.DSSKey ECDSAKey --> ecdsa 加密 --> 实现 class paramiko.ecdsakey.ECDSAKey Ed25519Key --> ed25519 加密 --> 实现 class paramiko.ed25519key.Ed25519Key 他们拥有相同的方法和属性: from_private_key() # 从文件(或类文件) 对象中读取私钥来创建密钥对象 参数: file_obj # 文件或类文件对象 password=None # 如果 password 不为 None, 则 password 值作为私钥的解密密码 返回值: 返回密钥对象, 传递给类似 connect() 的参数, 进行身份验证 from_private_key_file() # 从文件中读取私钥来创建密钥对象 参数: filename # 密钥文件 password=None # 如果 password 不为 None, 则 password 值作为私钥的解密密码 返回值: 返回密钥对象, 传递给类似 connect() 的参数, 进行身份验证 write_private_key() # 将私钥内容写入文件(或类文件)对象 参数: file_obj # 文件或类文件对象 password=None # 如果 password 不为 None, 则在写入之前使用 password 指定的密码对密钥进行加密 write_private_key_file() # 将私钥内容写入文件 参数: filename # 密钥文件 password=None # 如果 password 不为 None, 则在写入之前使用 password 指定的密码对密钥进行加密 get_name() # 获取密钥文件的名称 get_base64() # 获取密钥公共部分的 base64 字符串 get_bits() # 返回此键中的有效位数, 这对于判断密钥的相对安全性很有用 get_fingerprint() # 获取密钥公共部分的 MD5 指纹
SFTP:
组件: paramiko.sftp_client.SFTPClient 用于实现 sftp client 功能 paramiko.sftp_client.SFTP SFTPClient 用于向后兼容的别名 常用方法: from_transport() # 从 Transport 对象中打开 sftp 会话 put() # 上传文件 参数: remotepath # 远程路径 localpath # 本地路径 callback # 回掉函数,获取已接收的字节数和总字节数 confirm # 文件传输完成之后是否调用stat()函数 以确认文件大小,默认为True get() # 下载文件 参数: remotepath # 远程路径 localpath # 本地路径 callback # 回掉函数,获取已接收的字节数和总字节数 getfo() # 下载文件, 本地打开一个文件句柄用于写入远程服务的数据 参数: remotepath # 远程路径 fl # 本地文件句柄 callback putfo() # 上传文件, 参数类似于 getfo() getcwd() # 获取当前 sftp 会话所在目录 listdir() # 列出指定路径下的所有文件目录列表(包括以隐藏文件), 默认 sftp 会话所在目录 参数: path # 指定远程路径 listdir_attr() # 以类似于 ls -l 的格式列出指定路径下的所有文件目录列表(包括以隐藏文件), 默认 sftp 会话所在目录 参数: path # 指定远程路径 mkdir() # 在远程服务器上创建目录 参数: path # 要创建的目录路径和名称 mode # 目录权限, 数字格式, 默认为 o777 open() # 在远程服务器上打开文件, 参数和 python 的 open() 函数相同 readlink() # 返回符号链接的原始路径 参数: path # 指定符号链接 symlink() # 创建符号链接 参数: source # 符号链接的原始路径 dest # 符号链接的目标路径 remove() # 删除指定的文件(不能对目录进行删除) 参数: path # 指定需要删除的文件 rmdir() # 删除指定目录, 参数和 remove() 相同 rename() # 重命名文件或目录 参数: oldpath # 指定需要重命名的文件 newpath # 重命名之后的名称 stat() # 检查远程系统上的指定文件的信息 参数: path # 需要检查的文件 utime() # 修改文件的 atime 和 mtime 参数: path # 指定的文件 times # 修改后的时间元组, 格式 (atime, mtime)
Channel:
paramiko.channel.Channel 对 paramiko 的底层 class 之一, 实现通道建立和维护等功能 常用方法: exec_command() # 在远程服务器上执行命令 fileno() # 返回 OS 级文件描述符, 可用于轮询, 但不能用于读取或写入, 这主要是为了让 Python 的 select 模块能够工作(此方法将导致 Channel 读取效率降低) get_id() # 获取通道 ID set_name() # 设置通道名称 get_name() # 获取通道名称 get_pty() # 向服务器请求一个 pty 终端 参数: term="vt100" # 终端类型 width # 终端窗口的宽度(以字符为单位) height # 终端窗口的高度(以字符为单位) width_pixels # 终端窗口的宽度(以像素为单位) height_pixels # 终端窗口的高度(以像素为单位) get_transport() # 获取底层的 transport 对象, 用于执行低级的任务 getpeername() # 获取服务器地址 settimeout() # 设置通道超时时间 gettimeout() # 查看通道超时时间 invoke_shell() # 在此 channel 上请求交互式 shell 会话(通常会和 get_pty() 一起使用) invoke_subsystem() # 请求服务器上的子系统 参数: subsystem # 子系统的名称, 比如: sftp recv() # 接收远程服务器返回的数据 参数: nbytes # 设置一次获取的最大字节数 recv_exit_status() # 获取服务上进程返回的退出状态, 在使用 exec_command 执行命令获取返回值时有用 request_forward_agent() # 请求转发 ssh 代理 request_x11() # 请求 x11 会话 resize_pty() # 重新设置 pty 的大小, 用于更改 get_pty() 设置的大小 参数: width # 终端窗口的宽度(以字符为单位) height # 终端窗口的高度(以字符为单位) width_pixels # 终端窗口的宽度(以像素为单位) height_pixels # 终端窗口的高度(以像素为单位) send() # 向服务器发送数据, 检查数据是否发送完毕, 如果仅传输了部分数据, 则尝试传送剩余数据 参数: s # 要发送的数据 sendall() # 向服务器发送数据, 直到所有数据都已发送或发生错误 参数: s # 要发送的数据 set_environment_variable() # 设置环境变量 参数: name # 变量名 value # 变量值 update_environment() # 更新环境变量 参数: environment # 需要更新的环境变量的值, 类型为 dict setblocking() # 设置通道的阻塞模式: 参数: blocking # 如果 blocking 为 0, 则将通道设置为非阻塞模式; 否则设置为阻止模式, 默认为阻塞模式 settimeout() # 设置阻塞读写的超时时间, 如果 setblocking() 设置为 0, 那么相当于 settimeout(0) 参数: timeout # 超时时间 shutdown() # 关闭通道 how # 怎么样关闭通道, 0: 停止接收数据、1: 停止发送数据、2: 停止接收和发送数据 shutdown_read() # shutdown(0) 的简写 shutdown_write() # shutdown(1) 的简写 close() # 断开和服务器的连接
Transport:
paramiko.transport.Transport paramiko 的核心主件, 实现了一系列对 ssh 底层的操作 常用方法: connect() # 协商会话, 并可选的进行身份认证 参数: username="" # 要进行身份验证的用户名 password=None # 用户名对应的密码 pkey=None # 使用秘钥认证 # 如果 connect() 方法只是进行了会话协商而没有进行身份验证时, 则可以使用以下方法进行身份验证 auth_password() # 使用密码认证 参数: username # 进行身份验证的用户 password # 用户密码 auth_publickey() # 使用秘钥认证 参数: username # 进行身份验证的用户 key # 用户秘钥 auth_none() # 尝试使用空密码登录, 由于 Linux 的密码策略所以该方法几乎都是失败 参数: username # 用户名 close() # 断开和服务器的连接 get_username() # 获取登录用户的用户名 getpeername() # 获取服务器地址 is_active() # 如果当前会话处于活动状态则返回 True, 反之则返回 false is_authenticated() # 如果当前会话处于活动状态且已通过身份验证则返回 True, 反之则返回 false open_channel() # 向服务器请求打开新的 channel 参数: kind # 打开通道的类型(session, forwarded-tcpip, direct-tcpip, x11) dest_addr=None # 端口转发的目标地址(ip, port), 只有当通道类型为 forwarded-tcpip 和 direct-tcpip 时生效 src_addr=None # 端口转发的源地址, 只有当通道类型为 forwarded-tcpip、direct-tcpip 或 x11 时生效 window_size=None # 会话的窗口大小 max_packet_size=None # 此会话的最大数据包大小 timeout=None # 打开通道的超时时间, 默认问 1h open_forwarded_tcpip_channel() # open_channel() forwarded-tcpip 的简写 open_session() # open_channel() session 的简写 open_x11_channel() # open_channel() x11 的简写 open_sftp_client() # 打开 sftp 通道 set_keepalive() # 打开/关闭 keepalive 数据包(默认为关闭), 如果设置了此值, 在 interval 指定的时间内没有数据传输将发送 keepalive 数据包 参数: interval # 指定多长时间没有数据传输后开始发送 keepalive use_compression() # 打开或关闭压缩, 建议关闭, 因为它会对交互式会话产生负面影响 参数: compress # 是否打开压缩, true/false
Transport 示例:
import paramiko hostname = '192.168.1.100' username = 'root' password = '123.com' port = 22 transport = paramiko.transport.Transport(sock=(hostname, port)) transport.connect() transport.auth_password('root','123.com') sftp = transport.open_sftp_client() sftp.get('/etc/fstab', 'fstab-transport')
示例: 实现 ssh 客户端(只能在 Linux 下运行)
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : HuYuan # @File : python_shell.py import paramiko import sys import socket import termios import tty import select def posix_shell(chan): local_tty = termios.tcgetattr(sys.stdin) try: tty.setraw(sys.stdin.fileno()) tty.setcbreak(sys.stdin.fileno()) chan.settimeout(0.0) while True: read, write, error = select.select([chan, sys.stdin], [], []) if chan in read: try: recv = chan.recv(1024) if not len(recv): break sys.stdout.write(recv.decode()) sys.stdout.flush() except socket.timeout: pass if sys.stdin in read: content = sys.stdin.read(1) if not len(content): break chan.send(content) finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, local_tty) def open_ssh_client(): hostname = '192.168.1.100' username = 'root' password = '123.com' port = 22 try: ssh_client = paramiko.client.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy()) ssh_client.connect(hostname=hostname, username=username, password=password, port=port, timeout=10) tran = ssh_client.get_transport() chan = tran.open_session() chan.get_pty() chan.invoke_shell() posix_shell(chan) tran.close() except socket.timeout as e: print('连接超时', e) exit(10) except Exception as e: print(e) if __name__ == '__main__': open_ssh_client()
相关项目:
django + paramiko + websocket 实现 webssh: 项目地址: https://github.com/huyuan1999/django-webssh
posted on 2018-12-21 15:21 HuYuanBlog 阅读(3333) 评论(0) 编辑 收藏 举报