Python33 paramiko模块

2020-01-07 14:54:31 浏览数 (1)

paramiko模块

ssh登录

需要打开cmd,通过 pip install paramiko 命令来安装paramiko模块。

代码语言:javascript复制
import paramiko

#创建SSH对象
ssh = paramiko.SSHClient()

#允许连接不在know_hosts文件中的主机
# ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

#连接服务器
ssh.connect(hostname='192.168.21.128',port=22,username='test',password='123qwe')

#执行命令
stdin,stdout,stderr = ssh.exec_command('df')
##stdin标准输入:你输入的命令,会返还给你
##stdout标准输出:你的命令执行结果
##stderr标准错误:在执行过程中出现的错误

#获取命令结果
result = stdout.read()  ##标准输出,只有在命令正确的情况下才会输出,否则返回的信息为空。
print (result.decode()) ##因为linux是utf-8的bytes格式所以要decode

#关闭连接
ssh.close()

执行结果:
Traceback (most recent call last):
  File "E:/python/代码练习/A1.py", line 11, in <module>
    ssh.connect(hostname='192.168.21.128',port=22,username='test',password='123qwe')
  File "D:python3.6.4libsite-packagesparamikoclient.py", line 402, in connect
    self, server_hostkey_name, server_key
  File "D:python3.6.4libsite-packagesparamikoclient.py", line 768, in missing_host_key
    'Server {!r} not found in known_hosts'.format(hostname)
paramiko.ssh_exception.SSHException: Server '192.168.21.128' not found in known_hosts

我们可以看到报错Server '192.168.21.128' not found in known_hosts

linux默认是没有.ssh文件的

第一次被ssh登录时,会弹出提示来做一个签名认证,有了这个签名认证才能正常登录,而之前用python代码去ssh登录linux时,报错就是因为找不到known_hosts这个文件,所以会报错。

通过ssh test@192.168.21.129 -P22 (只要通过ssh登录一次就会出现.ssh文件)

而在.ssh中有known_hosts文件

可以看到known_hosts中的内容是一些加密的算法,会将被登录认证的信息存储到该文件中。

注意在上面的代码中将其中一行代码给注释掉了, ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())。该代码就是当known_hosts文件中没有被登录设备信息时,就会自动将期添加进去。 所以将该代码取消注释就可以正常登录了。

这回看到可以正常执行代码了。

代码语言:javascript复制
import paramiko

#创建SSH对象
ssh = paramiko.SSHClient()

#允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

#连接服务器
ssh.connect(hostname='192.168.21.128',port=22,username='test',password='123qwe')

#执行命令
stdin,stdout,stderr = ssh.exec_command('abc')
## 这里使用abc这个无效命令

#获取命令结果
result = stdout.read()
print (result.decode())
#关闭连接
ssh.close()

执行结果:
D:python3.6.4python.exe E:/python/代码练习/A1.py

Process finished with exit code 0
##可以看到 执行结果为空,这说明stdout.read()只有当命令正常执行后,得到了返回结果才会输出,如果错误的话stdout.read就不会有任何输出结果。
代码语言:javascript复制
import paramiko

#创建SSH对象
ssh = paramiko.SSHClient()

#允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

#连接服务器
ssh.connect(hostname='192.168.21.128',port=22,username='test',password='123qwe')

#执行命令
stdin,stdout,stderr = ssh.exec_command('abc')
## 这里使用abc这个无效命令

#获取命令结果
res,err = stdout.read(),stderr.read()
result = res if res else err    ##这里我们使用三元运算
print (result.decode())
#关闭连接
ssh.close()

执行结果:
D:python3.6.4python.exe E:/python/代码练习/A1.py
bash: abc: 未找到命令

Process finished with exit code 0
#可以看到,我们这次得到了标准错误的结果。

ssh上传、下载

代码语言:javascript复制
ssh_sft:通过ssh上传文件

import paramiko

# 创建连接
transport = paramiko.Transport(('192.168.21.128',22))
# 连接服务器
transport.connect(username='test',password='123qwe')
##根据创建的连接 用户名密码来连接服务器

sftp = paramiko.SFTPClient.from_transport(transport)
##将transport当做参数交给paramiko.SFTPClient.from_transport
##接下来真正的传输协议是在SFTPClient中定义的(实际交互是通过SFTPClient实现的)

# 将location.py上传至服务器 /tmp/test.py
sftp.put('test.txt','/home/test/test_new.txt')

# 将remove_path 下载到本地 local_path
# sftp.get('remove_path','local_path')

transport.close()

可以看到,文件成功的被传入到linux中了。

代码语言:javascript复制
ssh_sft:通过ssh下载文件

import paramiko

# 创建连接
transport = paramiko.Transport(('192.168.21.128',22))
# 连接服务器
transport.connect(username='test',password='123qwe')

sftp = paramiko.SFTPClient.from_transport(transport)

# 将location.py上传至服务器 /tmp/test.py
# sftp.put('test.txt','/home/test/test_new.txt')

# 将remove_path 下载到本地 local_path
sftp.get('/home/test/aaaa.txt','from_linux.txt')

transport.close()

成功将linux中的文件下载到本地

ssh认证

之前的代码,我们通过用户名和密码来登录linux,但是我们使用的是明文,这种情况容易被非法获取。

那么接下来我们可以通过密钥的方式来实现ssh登录。

代码语言:javascript复制
在 192.168.21.128 linux中生成一堆密钥(私钥和公钥)

test@test-virtual-machine:~$ 
test@test-virtual-machine:~$ ssh-keygen ##通过该命令生成
Generating public/private rsa key pair.
Enter file in which to save the key (/home/test/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/test/.ssh/id_rsa.
##私钥存储的位置(私钥不可以给任何人,只能自己存储好)
Your public key has been saved in /home/test/.ssh/id_rsa.pub.
##公钥存储的位置
The key fingerprint is:
SHA256:u9dlYPkYxpc4DjIVvVRNZdx7Tq1/7eRADP1lcvsXnpM test@test-virtual-machine
The key's randomart image is:
 ---[RSA 2048]---- 
|          .o .. *|
|          . o. . |
|         . o. o.*|
|        o . @oo**|
|        So = Bo*o|
|         .  o.* *|
|        .  . o.E=|
|         .. .   *|
|        ..     . |
 ----[SHA256]----- 
test@test-virtual-machine:~$ 
代码语言:javascript复制
在 192.168.21.128 linux中查看公钥

test@test-virtual-machine:~$ more .ssh/id_rsa.pub 

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCh7LDTrqAO7p9J0UgRaNkHJX8lua4hamfnLZ07Ugg2
E/nGR5pX CWGmVelNZZVdUyRl2Riu28tbyG3mMBZ9aFZFVhPCD3aY2Y2oTQIK/t62IzBpMT9TL7GwRCF
a S6wzx2oDU gp2VkYOxdBEYBDD1Gj0LH6qT7QIc4Xb6XufZdFV T8XTRqrQ/KcWJp3fNbnaHWBWaERe
 v6RZtlPW5ermK/nfgzB2Ccq/tUQNlFUOFOI6ddNazS1bIuKOTS21FeFuBda3wLbeoe785e2XFZA2FQp
AVKtvjExsSS6PCeMbvb01JOienVm/tUPIQ21v9vup09tc/bbfS6wxkQVtc8P test@test-virtual-m
achine

## 上面我们可以看到我们复制了一整段密钥,但是确是有好几个换行符,密钥中是不能有换行符的,否则就不是原来的密钥了,也就无效了(我们直接按照下图解决存在多余换行符问题)。

test@test-virtual-machine:~$
#我们将该公钥内容copy到其他设备上,其他设备就可以使用该公钥了。

我们直接将公钥复制到pycharm中,可以看到有好几个换行符,那么我们就需要往前删除将其变成一行。

这回密钥都在一行了,就不存在多余的换行符了,然后复制当前公钥即可。

代码语言:javascript复制
在192.168.21.129这台linux上
    通过su命令进入root模式
    通过adduser zhangsan来添加新用户
    通过su - zhangsan命令 进入zhangsan这个用户的家目录下
    注销当前用户,使用zhangsan用户登录linux,然后在/home/zhangsan下创建'.ssh'目录,然后在'.ssh'目录下创建authorized_keys文档
    将192.168.21.128生成的公钥内容copy到authorized_keys文档中,注意copy公钥后的文档中不能有换行,否则就不是原有的公钥内容了。

    zhangsan@test-virtual-machine:~$ ll .ssh/authorized_keys 
-rw-rw-r-- 1 zhangsan zhangsan 412 2月  27 15:10 .ssh/authorized_keys
## 查看该文档当前权限是-rw-rw-r--;一共可以设置三组权限(三组rwx),第一组表示属主,第二组表示属组,第三组表示others。
r是读,w是写,x是执行;r是4,w是2,x是1。

    我们可以需要修改authorized_keys文档权限,通过 'shmod 777 authorized_keys' 来修改,4 2 1(r w x)=7,所以是修改该文档为三个7。

zhangsan@test-virtual-machine:~/.ssh$ chmod 777 authorized_keys 
zhangsan@test-virtual-machine:~/.ssh$ ll authorized_keys 
-rwxrwxrwx 1 zhangsan zhangsan 412 2月  27 15:10 authorized_keys*
## 此时我们可以看到该文档已经拥有最高操作权限。可以访问、修改、执行。

    但是我们只要求只有当前用户可以访问、修改、所以就要修改权限为 600。

zhangsan@test-virtual-machine:~/.ssh$ chmod 600 authorized_keys 
zhangsan@test-virtual-machine:~/.ssh$ ll authorized_keys 
-rw------- 1 zhangsan zhangsan 412 2月  27 15:10 authorized_keys
##目前只有zhangsan这个用户可以读、写了。

此时我们在192.168.21.128这个linux上
    test@test-virtual-machine:~$ ssh test@192.168.21.129 -P22
    test@192.168.21.129's password:
    可以看到我们ssh  test这个用户时,依然需要密码
    ## 这是因为我们只将公钥copy到了zhangsan下的.ssh/authorized_keys文件中,并没有copy到test用户下

    test@test-virtual-machine:~$ ssh zhangsan@192.168.21.129 -P22
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-21-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

687 个可升级软件包。
355 个安全更新。

Last login: Tue Feb 27 16:23:32 2018 from 192.168.21.128
zhangsan@test-virtual-machine:~$ 
## 我们ssh  zhangsan可以看到此时就不需要通过密码来登录了。
## 这里注意,如果依然提示密码登录的话,请先关闭192.168.21.128 linux端的cmd终端,重新打开再重新试一下。
代码语言:javascript复制
之前我们通过粘贴的方式将公钥给另一台linux,粘贴的过程中出现了一些问题,那么我们下面通过其他方式来传递公钥。

在 192.168.21.129 的linux上
    zhangsan@test-virtual-machine:~$ vi .ssh/authorized_keys 
    zhangsan@test-virtual-machine:~$ rm .ssh/authorized_keys 
    zhangsan@test-virtual-machine:~$ rm -d .ssh/
    ## 我们将之前创建的文件和目录都删掉

在 192.168.21.128 的linux上
    ssh-copy-id -i /home/test/.ssh/id_rsa.pub zhangsan@192.168.21.129
    ## 直接将公钥传递给192.168.21.129

test@test-virtual-machine:~$ ssh-copy-id -i /home/test/.ssh/id_rsa.pub zhangsan@192.168.21.129
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/test/.ssh/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
zhangsan@192.168.21.129's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'zhangsan@192.168.21.129'"
and check to make sure that only the key(s) you wanted were added.
## 已经成功,提示要求到192.168.21.129上检查一下。

在 192.168.21.129 的linux上:
    zhangsan@test-virtual-machine:~$ ls -a
.              .cache   .gnupg         .sogouinput       公共的  下载
..             .config  .ICEauthority  .ssh              模板    音乐
.bash_history  .dbus    .local         .Xauthority       视频    桌面
.bash_logout   .dmrc    .presage       .xinputrc         图片
.bashrc        .gconf   .profile       .xsession-errors  文档
zhangsan@test-virtual-machine:~$ 
##我们可以看到 已经存在了.ssh目录

在 192.168.21.128 的linux上:
    test@test-virtual-machine:~$ ssh zhangsan@192.168.129 -p22

^C
test@test-virtual-machine:~$ ssh zhangsan@192.168.21.129 -p22
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-21-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

687 个可升级软件包。
355 个安全更新。

Last login: Tue Feb 27 16:23:51 2018 from 192.168.21.128
zhangsan@test-virtual-machine:~$ 
##可以看到 已经实现了 免密码登录。

代码语言:javascript复制
通过Python实现RSA秘钥认证

我们直接利用Linux中的秘钥,需要私钥拷贝到Windows中

在Windows下,通过xshell  ssh连接Linux,在Linux中通过sz ~/.ssh/id_rsa将私钥保存到Windows

我们将id_rsa重新命名为id_rsa_win,然后剪切到当前代码目录中

代码语言:javascript复制
在 192.168.202.128 Linux中:
    cd .ssh ##进入.ssh目录
    cat id_rsa.pub >> authorized_keys
    ## 需要将公钥的内容copy到authorized_keys中(authorized_keys之前不存在,通过该命令会新建并将公钥内容拷贝到authorized_keys文档中);  认证时会通过authorized_keys中的公钥来认证,而不是id_rsa.pub。

如此便完成了公钥的安装。有些时候,可能会有一些权限问题,可以执行如下:
chmod 600 authorized_keys
chmod 700 ~/.ssh

python RSA认证参考网址:http://50vip.com/article/84

代码语言:javascript复制
通过Python实现RSA秘钥认证

import paramiko

#指定私钥在哪里
private_key = paramiko.RSAKey.from_private_key_file('id_rsa_win')
## 因为在当前目录,所以直接指定文件名即可;如果在其他目录,就需要加上路径了
##这里要注意id_rsa_win是私钥、私钥、私钥(重要的事所三遍),私钥认证,公钥解密。

# 创建SSH对象
ssh = paramiko.SSHClient()

#允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 链接服务器
ssh.connect(hostname='192.168.202.128', port=22, username='test', pkey=private_key)
## 这里注意,如果使用RSA认证,那么最后面就不是password了,而是pkey=private_key
## pkey 表示是private key

# 执行命令
stdin,stdout,stderr = ssh.exec_command('df')

# 获取命令结果
res,err = stdout.read(),stderr.read()
result = res if res else err
print (result.decode())

# 关闭连接
ssh.close()

执行结果:
文件系统          1K-块    已用     可用 已用% 挂载点
udev             991244       0   991244    0% /dev
tmpfs            203072    6428   196644    4% /run
/dev/sda1      19478204 5577000 12888724   31% /
tmpfs           1015344     112  1015232    1% /dev/shm
tmpfs              5120       0     5120    0% /run/lock
tmpfs           1015344       0  1015344    0% /sys/fs/cgroup
tmpfs            203072      48   203024    1% /run/user/1000
代码语言:javascript复制
通过RSA认证上传下载

import paramiko

private_key = paramiko.RSAKey.from_private_key_file('id_rsa_win')

transport = paramiko.Transport(('192.168.202.128',22))
transport.connect(username='test',pkey=private_key)

sftp = paramiko.SFTPClient.from_transport(transport)

# 将xxx.py上传到服务器 /tmp/test.py
sftp.put('test.txt','/home/test/test_new.txt')

# 将xxx.txt下载到本地
sftp.get('/home/test/aaaa.txt','aaaa_new.txt')

transport.close()

0 人点赞