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()