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 阅读(3409) 评论(0) 收藏 举报
浙公网安备 33010602011771号