admin 管理员组文章数量: 1086019
[python] paramiko实现SSH和SFTP
目录
1.SSHClient
2.SSHClient 封装 Transport
3.基于公钥密钥连接
3.1 基于公钥密钥连接(SSHClient)
3.2 基于公钥密钥连接(SSHClient 封装 Transport)
4.基于私钥字符串进行连接
5.SFTPClient
5.1 基于用户名密码上传下载
5.2 基于公钥密钥上传下载
6.一个ssh和sftp工具脚本
API文档 /
环境准备
CentOS7, Python3.9 非封闭环境 使用pip安装下载包记录
[root@k8s-node2 ~]# pip3 install paramiko
Collecting paramikoDownloading paramiko-2.11.0-py2.py3-none-any.whl (212 kB)
……
Collecting pynacl>=1.0.1Downloading PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.1 MB)
……
Collecting sixDownloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting bcrypt>=3.1.3Downloading bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (61 kB)
……
Collecting cryptography>=2.5Downloading cryptography-37.0.4-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.2 MB)
……
Collecting cffi>=1.1Downloading cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (441 kB)
……
Collecting pycparserDownloading pycparser-2.21-py2.py3-none-any.whl (118 kB)
……
Installing collected packages: pycparser, cffi, six, pynacl, cryptography, bcrypt, paramiko
Successfully installed bcrypt-3.2.2 cffi-1.15.1 cryptography-37.0.4 paramiko-2.11.0 pycparser-2.21 pynacl-1.5.0 six-1.16.0
……
使用方法
1.SSHClient
用于连接远程服务器并执行基本命令
基于用户名密码连接:
>>> import paramiko
# 创建SSH对象
>>> ssh = paramiko.SSHClient()
>>> ssh
<paramiko.client.SSHClient object at 0x7f59f9a8cfd0>
(接下来是对这个SSH对象的操作)
# 允许连接不在know_hosts文件中的主机
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
>>> ssh.connect(hostname='192.168.183.122', port=22, username='test', password='test')
# 执行命令
>>> stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
>>> result = stdout.read()
>>> print(result.decode('utf-8'))
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 915780 0 915780 0% /dev
tmpfs 931512 0 931512 0% /dev/shm
tmpfs 931512 10536 920976 2% /run
tmpfs 931512 0 931512 0% /sys/fs/cgroup
/dev/sda3 18555904 8269368 10286536 45% /
/dev/sda1 303780 166724 137056 55% /boot
tmpfs 186304 12 186292 1% /run/user/42
tmpfs 186304 0 186304 0% /run/user/0
tmpfs 186304 0 186304 0% /run/user/1000>>>
# 关闭连接
>>> ssh.close()
# 关闭之后就不能ssh到对端了
>>> ssh
<paramiko.client.SSHClient object at 0x7f59f9a8cfd0>
>>>
>>> ssh.exec_command('df')
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/python3/lib/python3.9/site-packages/paramiko/client.py", line 510, in exec_commandchan = self._transport.open_session(timeout=timeout)
AttributeError: 'NoneType' object has no attribute 'open_session'
>>>
2.SSHClient 封装 Transport
>>> import paramiko
>>> transport = paramiko.Transport(('192.168.183.122', 22))
>>> transport.connect(username='test', password='test')
>>>
>>> ssh = paramiko.SSHClient()
>>> ssh._transport = transport
>>>
>>> stdin, stdout, stderr = ssh.exec_command('df -h')
>>> res=stdout.read()
>>> print(res.decode('utf-8'))
Filesystem Size Used Avail Use% Mounted on
devtmpfs 895M 0 895M 0% /dev
tmpfs 910M 0 910M 0% /dev/shm
tmpfs 910M 22M 888M 3% /run
tmpfs 910M 0 910M 0% /sys/fs/cgroup
/dev/sda3 18G 7.9G 9.9G 45% /
/dev/sda1 297M 163M 134M 55% /boot
tmpfs 182M 12K 182M 1% /run/user/42
tmpfs 182M 0 182M 0% /run/user/0
tmpfs 182M 0 182M 0% /run/user/1000>>>
>>> transport.close()
>>>
3.基于公钥密钥连接
private_key = paramiko.RSAKey.from_private_key_file('/somepath/id_rsa')
3.1 基于公钥密钥连接(SSHClient)
本端/客户端 node2 用户root
对端/服务端 node1 用户test
前提条件:
(1)客户端需要生成自己的私钥(客户端用户执行ssh-keygen命令),例如:/root/.ssh/id_rsa
(2)服务端需要有文件authorized_keys,且其中有客户端用户的公钥(客户端执行ssh-copy-id命令),即客户端能够免密登录服务端
[root@k8s-node2 .ssh]# ssh-copy-id -i id_rsa.pub test@192.168.183.122
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
test@192.168.183.122's password:Number of key(s) added: 1Now try logging into the machine, with: "ssh 'test@192.168.183.122'"
and check to make sure that only the key(s) you wanted were added.[root@k8s-node2 .ssh]#
[root@k8s-node2 .ssh]# ssh test@192.168.183.122
Last login: Fri Jul 22 19:53:46 2022 from 192.168.183.123
[test@k8s-node1 ~]$ exit
logout
Connection to 192.168.183.122 closed.
[root@k8s-node2 .ssh]#
参考:ssh首次登录避免输入yes、两台服务器间免密钥登录,3.方法二
【例3-1】
>>> import paramiko
>>> ssh = paramiko.SSHClient() #创建SSH对象
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #允许连接不在know_hosts文件中的主机
# 实例化一个私钥对象
说明:这里试了其实不传这个私钥也行,不过看网上的其它帖子都带着pkey,help查看其默认值None,所以还是带着比较好,例3-2详细说明
>>> private_key = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')
# 连接服务器
>>> ssh.connect(hostname='192.168.183.122', port=22, username='test', pkey=private_key)
# 执行命令
>>> stdin, stdout, stderr = ssh.exec_command('hostname')
# 获取命令结果、关闭连接
>>> result = stdout.read()
>>> print(result.decode('utf-8'))
k8s-node1>>> ssh.close()
>>>
例3-2和例3-3是自己的尝试,查阅资料一般都会指定pkey
【例3-2】如果pkey放置在默认位置,即 用户家目录/.ssh,连接服务器时可以不传入该参数
>>> import paramiko
>>> ssh = paramiko.SSHClient()
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>> ssh.connect(hostname='192.168.183.122', port=22, username='test') #pkey取默认路径的私钥
>>> stdin, stdout, stderr = ssh.exec_command('hostname')
>>>
>>> result = stdout.read()
>>> print(result.decode('utf-8'))
k8s-node1>>>
【例3-3】如果pkey从默认位置移除了,必须指定其路径
[root@k8s-node2 .ssh]# mv id_rsa /root/pydir/----------------------------------------------------
...
>>> ssh.connect(hostname='192.168.183.122', port=22, username='test')
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/python3/lib/python3.9/site-packages/paramiko/client.py", line 435, in connectself._auth(File "/usr/local/python3/lib/python3.9/site-packages/paramiko/client.py", line 767, in _authraise SSHException("No authentication methods available")
paramiko.ssh_exception.SSHException: No authentication methods available
>>>----------------------------------------------------
...
>>> private_key1 = paramiko.RSAKey.from_private_key_file('/root/pydir/id_rsa')
>>> ssh.connect(hostname='192.168.183.122', port=22, username='test', pkey=private_key1)
>>>
3.2 基于公钥密钥连接(SSHClient 封装 Transport)
>>> import paramiko
>>>
>>> private_key = paramiko.RSAKey.from_private_key_file('/root/pydir/id_rsa')
>>>
>>> transport = paramiko.Transport(('192.168.183.122', 22))
>>> transport.connect(username='test', pkey=private_key)
>>>
>>> ssh = paramiko.SSHClient()
>>> ssh._transport = transport
>>> stdin, stdout, stderr = ssh.exec_command('hostname')
>>> result=stdout.read()
>>> print(result.decode('utf-8'))
k8s-node1>>> transport.close()
>>>
说明:transport.connect不传入pkey会报错 Oops, unhandled type 3 ('unimplemented')
>>> stdin, stdout, stderr = ssh.exec_command('hostname')
Oops, unhandled type 3 ('unimplemented')Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/python3/lib/python3.9/site-packages/paramiko/client.py", line 510, in exec_commandchan = self._transport.open_session(timeout=timeout)File "/usr/local/python3/lib/python3.9/site-packages/paramiko/transport.py", line 920, in open_sessionreturn self.open_channel(File "/usr/local/python3/lib/python3.9/site-packages/paramiko/transport.py", line 1046, in open_channelevent.wait(0.1)File "/usr/local/python3/lib/python3.9/threading.py", line 574, in waitsignaled = self._cond.wait(timeout)File "/usr/local/python3/lib/python3.9/threading.py", line 316, in waitgotit = waiter.acquire(True, timeout)
KeyboardInterrupt
>>>
>>>
>>> stdin, stdout, stderr = ssh.exec_command('hostname',timeout=5)
Oops, unhandled type 3 ('unimplemented')
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/python3/lib/python3.9/site-packages/paramiko/client.py", line 510, in exec_commandchan = self._transport.open_session(timeout=timeout)File "/usr/local/python3/lib/python3.9/site-packages/paramiko/transport.py", line 920, in open_sessionreturn self.open_channel(File "/usr/local/python3/lib/python3.9/site-packages/paramiko/transport.py", line 1055, in open_channelraise SSHException("Timeout opening channel.")
paramiko.ssh_exception.SSHException: Timeout opening channel.
>>>
查看help,SSHClient和Transport的connect方法pkey默认值都是None,不知为什么上一节SSHClient尝试不传pkey(在默认路径)可以连上
>>> help(transport)
……
connect(self, hostkey=None, username='', password=None, pkey=None, gss_host=None, gss_auth=False, gss_kex=False, gss_deleg_creds=True, gss_trust_dns=True)>>> help(paramiko)
……
connect(self, hostname, port=22, username=None, password=None, pkey=None, key_filename=None, timeout=None, allow_agent=True, look_for_keys=True, compress=False, sock=None, gss_auth=False, gss_kex=False, gss_deleg_creds=True, gss_host=None, banner_timeout=None, auth_timeout=None, gss_trust_dns=True, passphrase=None, disabled_algorithms=None)
4.基于私钥字符串进行连接
key_str = """some content"""
private_key = paramiko.RSAKey(file_obj=StringIO(key_str))
和上一节差不多,只是读取private_key的方式变了
>>> import paramiko
>>> from io import StringIO
>>> key_str = """-----BEGIN RSA PRIVATE KEY-----
... MIIEowIBAAKCAQEAwPFheM/5KrPzfltEtehOAHRNlOcLjA0dO7x88C4YowrIll+r
......
... 62chR6A59nDlCjVbemRalq9x3TQriTqDxV0/cd3MPow21fsl7rc/6nL+Yo6YIS4U
... TI+jFuQbM7K8DD0xuG7pPMEn5r1MOy3iSp4bScBFxpKBgOlo/hh8
... -----END RSA PRIVATE KEY-----"""
>>> private_key = paramiko.RSAKey(file_obj=StringIO(key_str))
>>> transport = paramiko.Transport(('192.168.183.122', 22))
>>> transport.connect(username='test', pkey=private_key)
>>>
>>> ssh = paramiko.SSHClient()
>>> ssh._transport = transport
>>> stdin, stdout, stderr = ssh.exec_command('df')
>>> result = stdout.read()
>>> print(result.decode('utf-8'))
k8s-node1>>> ssh.close()
>>>
5.SFTPClient
用于连接远程服务器并执行上传下载
5.1 基于用户名密码上传下载
>>> import paramiko
>>> transport = paramiko.Transport(('192.168.183.122',22))
>>> transport.connect(username='test',password='test')
>>>
>>> sftp = paramiko.SFTPClient.from_transport(transport)
(1)上传 sftp.put('srcpath', 'destpath')
注意:目标路径要写到文件名,只写到文件夹会报错
>>> sftp.put('/root/pydir/testfile', '/home/test')
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/python3/lib/python3.9/site-packages/paramiko/sftp_client.py", line 759, in putreturn self.putfo(fl, remotepath, file_size, callback, confirm)File "/usr/local/python3/lib/python3.9/site-packages/paramiko/sftp_client.py", line 714, in putfowith self.file(remotepath, "wb") as fr:File "/usr/local/python3/lib/python3.9/site-packages/paramiko/sftp_client.py", line 372, in opent, msg = self._request(CMD_OPEN, filename, imode, attrblock)File "/usr/local/python3/lib/python3.9/site-packages/paramiko/sftp_client.py", line 822, in _requestreturn self._read_response(num)File "/usr/local/python3/lib/python3.9/site-packages/paramiko/sftp_client.py", line 874, in _read_responseself._convert_status(msg)File "/usr/local/python3/lib/python3.9/site-packages/paramiko/sftp_client.py", line 907, in _convert_statusraise IOError(text)
OSError: Failure
>>>
将本端文件/root/pydir/testfile 上传至对端路径/home/test并命名为testfile2
>>> sftp.put('/root/pydir/testfile', '/home/test/testfile2')
<SFTPAttributes: [ size=0 uid=1000 gid=1000 mode=0o100664 atime=1658566650 mtime=1658566650 ]>
>>>
查看对端/home/test
[test@k8s-node1 ~]$ pwd
/home/test
[test@k8s-node1 ~]$ ll
total 0
-rw-rw-r-- 1 test test 0 Jul 23 01:57 testfile2
[test@k8s-node1 ~]$
(2)下载 sftp.get('srcpath', 'destpath')
注意:目标路径要写到文件名,只写到文件夹会报错
>>> sftp.get('/home/test/testfile2', '/tmp')
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/python3/lib/python3.9/site-packages/paramiko/sftp_client.py", line 810, in getwith open(localpath, "wb") as fl:
IsADirectoryError: [Errno 21] Is a directory: '/tmp'
>>>
将对端/home/test/testfile2下载到本端/tmp并重命名为testfile
>>> sftp.get('/home/test/testfile2', '/tmp/testfile')
>>>
>>> transport.close()
>>>
------------------------------------------------------
[root@k8s-node2 ~]# ls -l /tmp/testfile
-rw-r--r-- 1 root root 0 Jul 23 17:28 /tmp/testfile
[root@k8s-node2 ~]#
5.2 基于公钥密钥上传下载
>>> import paramiko
>>> private_key = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')
>>>
>>> ssh_client = paramiko.SSHClient()
>>> ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>>
>>> sftp_client = ssh_client.open_sftp()
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/python3/lib/python3.9/site-packages/paramiko/client.py", line 558, in open_sftpreturn self._transport.open_sftp_client()
AttributeError: 'NoneType' object has no attribute 'open_sftp_client'
>>>
>>>
>>> ssh_client.connect(hostname='192.168.183.122', port=22, username='test')
>>> sftp_client = ssh_client.open_sftp()
>>>
(1)上传 sftp_client.put('srcpath', 'destpath')
>>> sftp_client.put('/root/pydir/infofile','/home/test/infofile')
<SFTPAttributes: [ size=190 uid=1000 gid=1000 mode=0o100664 atime=1658570348 mtime=1658570348 ]>
>>>
(2)下载 sftp_client.get('srcpath', 'destpath')
>>> sftp_client.get('/home/test/infofile','/tmp/infofile_from_node1')---------------------------------------------------------------------
[root@k8s-node2 pydir]# ls -l /tmp/infofile_from_node1
-rw-r--r-- 1 root root 190 Jul 23 17:59 /tmp/infofile_from_node1
[root@k8s-node2 pydir]#
6.一个ssh和sftp工具脚本
把上述方法写到一个脚本 sshSftpTool.py
#!/usr/bin/env python
import paramikodef ssh_connect(host, username, password, port = 22):try:ssh_client = paramiko.SSHClient()ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh_client.connect(host, port, username, password)except Exception as e:print("ssh " + host + " failed!")print(e)sys.exit()return ssh_clientdef ssh_exec(ssh_client, cmd):stdin, stdout, stderr = ssh_client.exec_command(cmd)result = stdout.read()print("Exec cmd:\n",cmd,"\nResult:\n",result.decode('utf-8'))def ssh_close(ssh_client):return ssh_client.close()def sftp_open(ssh_client):return ssh_client.open_sftp()def sftp_put(sftp_client, srcFile, destFile):return sftp_client.put(srcFile, destFile)def sftp_get(sftp_client, srcFile, destFile):return sftp_client.get(srcFile, destFile)def sftp_close(sftp_client):return sftp_client.close()
测试如下
>>> from sshSftpTool import *
>>> ssh_cli = ssh_connect('192.168.183.122', 'test', 'test')
>>> ssh_exec(ssh_cli,"cd;touch newfile")
Exec cmd:cd;touch newfile
Result:>>> ssh_exec(ssh_cli,"ls -l newfile")
Exec cmd:ls -l newfile
Result:-rw-rw-r-- 1 test test 0 Jul 23 04:29 newfile>>> sftp_cli = sftp_open(ssh_cli)
>>> sftp_cli.get('/home/test/newfile','/tmp/newfile_from_node1')
>>> sftp_cli.close()
>>> ssh_cli.close()
>>>
----------------------------------------------------------------
[test@k8s-node1 ~]$ pwd
/home/test
[test@k8s-node1 ~]$ ll
total 0
-rw-rw-r-- 1 test test 0 Jul 23 01:57 testfile2
[test@k8s-node1 ~]$
参考资料:
paramiko模块
本文标签: python paramiko实现SSH和SFTP
版权声明:本文标题:[python] paramiko实现SSH和SFTP 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1686732474a30574.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论