欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

11 Python编程:从入门到实践---paramiko模块详解

最编程 2024-02-10 10:05:48
...

paramiko

是基于Python实现的SSH2远程安全连接,支持认证及秘钥方式。可以实现远程命令执行、文件传输、中间SSH代理功能,相当于Pexpect,封装的层次更高,更贴近SSH协议的功能。

paramiko是第三方模块,需要进行安装后使用。

SSHClient类示例:

通过使用用户名,密码的方式,通过exec_commands()方法执行命令。

 1 #!/usr/bin/evn python
 2 # --*-- coding: utf-8 --*--
 3 # Auther : Liu WeiDong
 4 import paramiko
 5 
 6 hostname = '192.168.2.22'
 7 username = 'root'
 8 password = 'SKJh935yft#'
 9 paramiko.util.log_to_file('syslogin.log') #发送paramiko日志到syslogin.log文件
10 
11 ssh = paramiko.SSHClient()  #创建一个ssh客户端client对象
12 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())   #允许连接不在know_hosts文件中的主机
13 ssh.load_system_host_keys()  # 获取客户端host_keys,默认~/.ssh/know_hosts,非默认路径需要指定
14 
15 ssh.connect(hostname=hostname,username=username,password=password) #创建ssh连接
16 stdin,stdout,stderr = ssh.exec_command('free -m') #调用远程执行命令方法exec_command()
17 print(stdout.read())  #打印命令执行结果,得到python列表形式,可以使用stdout.readlines()
18 ssh.close()    #关闭ssh连接
View Code

SSHClient类方法讲解

connect方法

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

 参数说明:

  • hostname(str类型),连接目标主机IP地址或主机名
  • port(int类型),连接目标主机的端口,默认为22
  • username(str类型),校验的用户名(默认为当前的本地用户名)
  • password(str类型),密码用于身份校验或解锁私钥
  • pkey,私钥方式用于身份验证
  • key_filename(str or list(str)类型),一个文件名或文件名的列表,用于私钥的身份验证;
  • timeout(float类型),一个可选的超时时间(以秒为单位)的TCP连接
  • allow_agent(bool类型),设置为False时用于禁用连接到SSH代理
  • look_for_keys(bool类型),设置为False时用来禁用在~./ssh中搜索秘钥文件;
  • compress(bool类型),设置为True时打开压缩

exec_command方法

exec_command(command, bufsize=-1, timeout=None, get_pty=False, environment=None) 

  • command(str类型),执行的命令串
  • bufsize(int类型),文件缓冲区大小,默认为-1(不限制)

load_system_host_keys

load_system_host_keys(filename=None)

加载本地公钥校验文件,默认为~/.ssh/known_hosts,非默认路径需要收工指定

  • filename(str类型),指定远程主机公钥记录文件

set_missing_host_key_policy方法

set_missing_host_key_policy(policy)

设置连接远程主机没有本地主机秘钥或HostKeys对象时的策略,目前支持三种方式,分别是RejectPolicy(默认),AutoAddPolicy、WarningPolicy,仅限用于SSHClient类,分别代表如下含义

  • AutoAddPolicy,自动添加主机名及主机秘钥到本地HostKeys对象,并将其保存,不依赖load_system_host_keys,即使~/.ssh/known_hosts不存在也产业影响
  • RejectPolicy(默认),自动拒绝未知的主机名或秘钥,依赖load_system_host_keys()配置
  • WarningPolicy,用于记录一个未知的主机秘钥的Python警告,并接受它,功能上与AutoAddPolicy相似,但未知主机会有告警。

 SFTPClient类示例

 下面为SFTPClient类的一个完整示例,实现文件上传,下载,创建与删除目录等,需要注意的是put和get方法需要指定文件名,不能省略。

 1 #!/usr/bin/evn python
 2 # --*-- coding: utf-8 --*--
 3 # Auther : Liu WeiDong
 4 
 5 import paramiko
 6 
 7 username = "root"
 8 password = "KJSD8T34D"
 9 hostname = "192.168.1.22"
10 port = 22
11 
12 try:
13     t = paramiko.Transport((hostname,port))
14     t.connect(username=username,password=password)
15     sftp = paramiko.SFTPClient.from_transport(t)
16     sftp.put("/home/user/info.db","/data/user/info.db")  #上传文件
17     sftp.get("/data/user/info_1.db","/home/user/info_1.db")  #下载文件
18     sftp.mkdir("/home/userdir","0755")  #创建目录
19     sftp.rmdir("/home/userdir")  #删除目录
20     sftp.rename("/home/test.sh","/home/testfile.sh")   #文件重命名
21     print(sftp.stat("/home/testfile.sh"))  #打印文件信息
22     print(sftp.listdir("/home"))  #打印目录列表
23     t.close()
24 except Exception as e:
25     print(str(e))
View Code

 SFTPClient类方法讲解

from_transport方法

创建一个已连通的SFTP客户端通道,方法定义:

from_transport(cls,t)

参数说明:

t(Transport),一个已通过验证的传输对象。

例子说明:

t = paramiko.Transport((hostname,port))

t.connect(username=username,password=password)

    sftp = paramiko.SFTPClient.from_transport(t)

put方法

上传本地文件到远程SFTP服务器

  get方法

从远程SFTP服务端下载文件到本地

其他方法

  • mkdir,在SFTP服务器端创建目录
  • remove,删除SFTP服务器端制定目录
  • rename,重命名SFTP服务器端文件或目录
  • stat,获取远程SFTP服务器端制定文件信息
  • listdir,获取远程SFTP服务器端指定目录列表

paramiko应用示例

实现秘钥方式登录远程主机

 实现自动秘钥登录方式,第一步需要配置与目标设备的秘钥认证支持(即主机间ssh互信),私钥文件可以存放在默认路径“~/.ssh/id_rsa”,也可以自定义路径,通过paramiko.RSAKey.from_private_key_file()方法引用,代码详解如下:

 1 #!/usr/bin/evn python
 2 # --*-- coding: utf-8 --*--
 3 # Auther : Liu WeiDong
 4 
 5 import paramiko
 6 import os
 7 
 8 hostname = '192.168.1.22'
 9 username = 'root'
10 paramiko.util.log_to_file('syslogin.log')
11 
12 ssh = paramiko.SSHClient()
13 ssh.load_system_host_keys()
14 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
15 privatekey = os.path.expanduser('/home/key/id_rsa')
16 key = paramiko.RSAKey.from_private_key_file(privatekey)
17 
18 ssh.connect(hostname=hostname,username=username,pkey=key)
19 stdin,stdout,stderr = ssh.exec_command('free -m')
20 print(stdout.read())
21 ssh.close()
View Code

 实现堡垒机模式下的远程命令执行

堡垒机环境在一定程度上提升了运营安全级别,但同时也提高了日常运营成本,作为管理的中转设备,任何针对业务服务器的请求都需要经过此节点,比如ssh协议。首先运维人员在办公电脑通过ssh登录堡垒机,在由堡垒机SSH跳转到所有业务服务器进行维护操作。

 

 我们通过paramiko的invoke_shell方法来实现通过堡垒机登录服务器操作,原理是SSHClient.connect到堡垒机后开启一个新的SSH会话,通过新的会话运行“ssh user@IP”去实现远程命令执行操作,代码如下

 1 #!/usr/bin/evn python
 2 # --*-- coding: utf-8 --*--
 3 # Auther : Liu WeiDong
 4 
 5 import paramiko
 6 import os,sys,time
 7 
 8 #定义堡垒机信息
 9 blip = "192.168.1.23"
10 bluser = "root"
11 blpasswd = "Kd03dfd"
12 
13 #定义通过堡垒机连接的业务主机信息
14 hostname = "192.168.1.22"
15 username = "root"
16 password = "OD908k"
17 port = 22
18 
19 #输入服务器登录前输入密码提示
20 passinfo = "\'s password: "
21 paramiko.util.log_to_file("syslogin.log")
22 
23 #登录堡垒机
24 ssh = paramiko.SSHClient()
25 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
26 ssh.connect(hostname=blip,username=bluser,password=blpasswd)
27 
28 #创建会话,开启命令调用
29 channel = ssh.invoke_shell()
30 #定义命令执行超时时间,单位为秒
31 channel.settimeout(10)
32 
33 buff = ""
34 resp = ""
35 #执行ssh登录业务主机
36 channel.send("ssh "+username+"@"+hostname+"\n")
37 
38 #ssh登录的提示信息判断,输出字符串尾含有's password: 若是以password结尾,则进入循环,否则不进入循环
39 while not buff.endswith(passinfo):
40     try:
41         resp = channel.recv(9999)
42     except Exception as e:
43         print("Error info:%S connection time." % (str(e)))
44         channel.close()
45         ssh.close()
46         sys.exit()
47     buff += resp
48     # 判断输出字符串结尾如果含有“yes/no”时发送“yes”并回车
49     if not buff.find("yes/no") == -1:   #find方法,发现子字符串包含在字符串内,则返回字符串索引值,否则返回-1
50         channel.send("yes\n")
51         buff = ""
52 #发送业务主机密码并回车
53 channel.send(password+"\n")
54 
55 buff = ""
56 #输出的字符串为“#”号,说明校验通过不进入循环
57 while not buff.endswith("# "):
58     resp = channel.recv(9999)
59     # 输出字符串含有“password”,说明密码不正确,要求重新输入
60     if not resp.find(passinfo) == -1:
61         print("Error info: Authentication failed.")
62         channel.close()
63         ssh.close()
64         sys.exit()
65     buff += resp
66 
67 # 认证通过后发送ifconfig命令查看结果
68 channel.send("ifconfig\n")
69 
70 buff = ""
71 try:
72     while buff.find("# ") == -1:
73         resp = channel.recv(9999)
74         buff += resp
75 except Exception as e:
76     print("error info:" + str(e))
77 
78 print(buff)
79 channel.close()
80 ssh.close()
View Code

 实现堡垒机模式下的远程文件上传

实现堡垒机模式下文件上传,原理是通过paramiko的SFTPClient将文件从办公设备上传至堡垒机制定临时目录,如/tmp,在通过SSHClient的invoke_shell方法开启ssh会话,执行scp命令,将/tmp下指定文件复制到目录业务主机上

 

 本示例具体使用sftp.put()方法上传文件至堡垒机临时目录,在通过send()方法执行scp命令,将堡垒机临时目录下文件复制到目标主机,具体代码如下:

 1 #!/usr/bin/evn python
 2 # --*-- coding: utf-8 --*--
 3 # Auther : Liu WeiDong
 4 
 5 import paramiko
 6 import os,sys,time
 7 
 8 #定义堡垒机信息
 9 blip = "192.168.1.23"
10 bluser = "root"
11 blpasswd = "Kd03dfd"
12 
13 #定义通过堡垒机连接的业务主机信息
14 hostname = "192.168.1.22"
15 username = "root"
16 password = "OD908k"
17 port = 22
18 
19 tmpdir = "/tmp"
20 remotedir = "data"
21 #本地源文件路径
22 localpath = "/home/nginx_access.tar.gz"
23 #堡垒机临时路径
24 tmppath = tmpdir + "/nginx_access.tar.gz"
25 #业务主机目标路径
26 remotepath = remotedir + "/nginx_access_hd.tar.gz"
27 #输入服务器登录前输入密码提示
28 passinfo = "\'s password: "
29 paramiko.util.log_to_file("syslogin.log")
30 
31 t = paramiko.Transport((blip,port))
32 t.connect(username=bluser,password=blpasswd)
33 sftp = paramiko.SFTPClient.from_transport(t)
34 #上传本地源文件到堡垒机临时目录
35 sftp.put(localpath,tmppath)
36 sftp.close()
37 
38 ssh = paramiko.SSHClient()
39 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
40 ssh.connect(hostname=blip,username=bluser,password=blpasswd)
41 
42 channel = ssh.invoke_shell()
43 channel.settimeout(10)
44 
45 buff = ""
46 resp = ""
47 #scp中传目录文件到目标主机
48 channel.send("scp " + tmppath + " " + username + "@" + hostname + ":" +remotepath + "\n" )
49 
50 #ssh登录的提示信息判断,输出字符串尾含有's password: 若是以password结尾,则进入循环,否则不进入循环
51 while not buff.endswith(passinfo):
52     try:
53         resp = channel.recv(9999)
54     except Exception as e:
55         print("Error info:%S connection time." % (str(e)))
56         channel.close()
57         ssh.close()
58         sys.exit()
59     buff += resp
60     # 判断输出字符串结尾如果含有“yes/no”时发送“yes”并回车
61     if not buff.find("yes/no") == -1:   #find方法,发现子字符串包含在字符串内,则返回字符串索引值,否则返回-1
62         channel.send("yes\n")
63         buff = ""
64 #发送业务主机密码并回车
65 channel.send(password+"\n")
66 
67 buff = ""
68 #输出的字符串为“#”号,说明校验通过不进入循环
69 while not buff.endswith("# "):
70     resp = channel.recv(9999)
71     # 输出字符串含有“password”,说明密码不正确,要求重新输入
72     if not resp.find(passinfo) == -1:
73         print("Error info: Authentication failed.")
74         channel.close()
75         ssh.close()
76         sys.exit()
77     buff += resp
78 
79 print(buff)
80 channel.close()
81 ssh.close()
View Code