Python----Paramiko模块和堡垒机实战

paramiko模块

  paramiko是一个用于作远程控制的模块,使用该模块能够对远程服务器进行命令或文件操做,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。其实它的底层是对ssh的上层代码的一个封装node

1、下载安装python

1
2
3
#pycrypto,因为 paramiko 模块内部依赖pycrypto,因此先下载安装pycrypto
tomcat@node:~$ pip install pycrypto
tomcat@node:~$ pip install paramiko

2、模块使用linux

一、SSHClient 用于链接远程服务器并执行基本命令

(1)基于用户名密码链接两种方式:ios

-->第一种git

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import  paramiko
    
# 建立SSH对象
ssh  =  paramiko.SSHClient()
# 容许链接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 链接服务器
ssh.connect(hostname = '192.168.1.21' , port = 22 , username = 'root' , password = '123456' )
    
# 执行命令
stdin, stdout, stderr  =  ssh.exec_command( 'ls' )
# 获取命令结果
result  =  stdout.read()
    
# 关闭链接
ssh.close()

-->二种:SSHClient 封装 Transport  github

1
2
3
4
5
6
7
8
9
10
11
12
import  paramiko
 
transport  =  paramiko.Transport(( '192.168.1.21' 22 ))
transport.connect(username = 'root' , password = '123456' )
 
ssh  =  paramiko.SSHClient()
ssh._transport  =  transport
 
stdin, stdout, stderr  =  ssh.exec_command( 'df' )
print  stdout.read()
 
transport.close()

(2)基于公钥密钥链接的两种方式:shell

-->第一种  json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import  paramiko
   
private_key  =  paramiko.RSAKey.from_private_key_file( '/root/.ssh/id_rsa' )
   
# 建立SSH对象
ssh  =  paramiko.SSHClient()
# 容许链接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 链接服务器
ssh.connect(hostname = '192.168.1.21' , port = 22 , username = 'root' , key = private_key)
   
# 执行命令
stdin, stdout, stderr  =  ssh.exec_command( 'df' )
# 获取命令结果
result  =  stdout.read()
   
# 关闭链接
ssh.close()

-->第二种:SSHClient 封装 Transport  windows

1
2
3
4
5
6
7
8
9
10
11
12
13
import  paramiko
 
private_key  =  paramiko.RSAKey.from_private_key_file( '/root/.ssh/id_rsa' )
 
transport  =  paramiko.Transport(( '192.168.1.21' 22 ))
transport.connect(username = 'root' , pkey = private_key)
 
ssh  =  paramiko.SSHClient()
ssh._transport  =  transport
 
stdin, stdout, stderr  =  ssh.exec_command( 'df' )
 
transport.close()

二、SFTPClient用于链接远程服务器并执行上传下载

(1)基于用户名密码上传下载:tomcat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import  paramiko
   
transport  =  paramiko.Transport(( '192.168.1.21' , 22 ))
transport.connect(username = 'root' ,password = '123456' )
   
sftp  =  paramiko.SFTPClient.from_transport(transport)
 
# 将location.py 上传至服务器 /tmp/test.py
sftp.put( '/tmp/location.py' '/tmp/test.py' )
 
# 将remove_path 下载到本地 local_path
sftp.get( 'remove_path' 'local_path' )
   
transport.close()

(2)基于公钥密钥上传下载:  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import  paramiko
   
private_key  =  paramiko.RSAKey.from_private_key_file( '/root/.ssh/id_rsa' )
   
transport  =  paramiko.Transport(( '192.168.1.21' 22 ))
transport.connect(username = 'root' , pkey = private_key )
   
sftp  =  paramiko.SFTPClient.from_transport(transport)
 
# 将location.py 上传至服务器 /tmp/test.py
sftp.put( '/tmp/location.py' '/tmp/test.py' )
 
# 将remove_path 下载到本地 local_path
sftp.get( 'remove_path' 'local_path' )
   
transport.close()

三、实例:经过transport实现远程执行命令和上传文件  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import  paramiko
 
class  SSHConnection( object ):
 
     def  __init__( self , host = '192.168.1.21' , port = 22 , username = 'root' ,pwd = '123456' ):
         self .host  =  host
         self .port  =  port
         self .username  =  username
         self .pwd  =  pwd
         self .__k  =  None
 
     def  run( self ):
         self .connect()
         pass
         self .close()
 
     def  connect( self ):
         transport  =  paramiko.Transport(( self .host, self .port))
         transport.connect(username = self .username,password = self .pwd)
         self .__transport  =  transport
 
     def  close( self ):
         self .__transport.close()
 
     def  cmd( self , command):
         ssh  =  paramiko.SSHClient()
         ssh._transport  =  self .__transport
         # 执行命令
         stdin, stdout, stderr  =  ssh.exec_command(command)
         # 获取命令结果
         result  =  stdout.read()
         return  result
 
     def  upload( self ,local_path, target_path):
         # 链接,上传
         sftp  =  paramiko.SFTPClient.from_transport( self .__transport)
         # 将location.py 上传至服务器 /tmp/test.py
         sftp.put(local_path, target_path)
 
ssh  =  SSHConnection()
ssh.connect()
r1  =  ssh.cmd( 'df' )
print (r1.decode())
#ssh.upload('test.py', "/root/test.py")
ssh.upload( 's13_par.py' "/root/s7.py" )
ssh.close()
复制代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import paramiko
import uuid

class SSHConnection(object):

    def __init__(self, host='172.16.103.191', port=22, username='wupeiqi',pwd='123'):
        self.host = host
        self.port = port
        self.username = username
        self.pwd = pwd
        self.__k = None

    def create_file(self):
        file_name = str(uuid.uuid4())
        with open(file_name,'w') as f:
            f.write('sb')
        return file_name

    def run(self):
        self.connect()
        self.upload('/home/wupeiqi/tttttttttttt.py')
        self.rename('/home/wupeiqi/tttttttttttt.py', '/home/wupeiqi/ooooooooo.py)
        self.close()

    def connect(self):
        transport = paramiko.Transport((self.host,self.port))
        transport.connect(username=self.username,password=self.pwd)
        self.__transport = transport

    def close(self):

        self.__transport.close()

    def upload(self,target_path):
        # 链接,上传
        file_name = self.create_file()

        sftp = paramiko.SFTPClient.from_transport(self.__transport)
        # 将location.py 上传至服务器 /tmp/test.py
        sftp.put(file_name, target_path)

    def rename(self, old_path, new_path):

        ssh = paramiko.SSHClient()
        ssh._transport = self.__transport
        # 执行命令
        cmd = "mv %s %s" % (old_path, new_path,)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        # 获取命令结果
        result = stdout.read()

    def cmd(self, command):
        ssh = paramiko.SSHClient()
        ssh._transport = self.__transport
        # 执行命令
        stdin, stdout, stderr = ssh.exec_command(command)
        # 获取命令结果
        result = stdout.read()
        return result
        


ha = SSHConnection()
ha.run()
复制代码
1
2
3
4
5
6
# 对于更多限制命令,须要在系统中设置
/ etc / sudoers
   
Defaults    requiretty
Defaults:cmdb    !requiretty
  Demo
堡垒机

堡垒机执行流程:

  1. 管理员为用户在服务器上建立帐号(将公钥放置服务器,或者使用用户名密码)
  2. 用户登录堡垒机,输入堡垒机用户名密码,现实当前用户管理的服务器列表
  3. 用户选择服务器,并自动登录
  4. 执行操做并同时将用户操做记录

注:配置.brashrc实现ssh登录后自动执行脚本,如:/usr/bin/python /home/wupeiqi/menu.py

实现过程(前戏)

# 利用sys.stdin,肆意妄为执行操做
# 用户在终端输入内容,并将内容发送至远程服务器
# 远程服务器执行命令,并将结果返回
# 用户终端显示内容

版本一:能连上远程服务器在终端任意输入命令,但没法作到tab键补全命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import  paramiko
import  sys
import  os
import  socket
import  select
import  getpass
from  paramiko.py3compat  import  u
  
tran  =  paramiko.Transport(( '192.168.1.21' 22 ,))
tran.start_client()
tran.auth_password( 'root' '123456' )
  
# 打开一个通道
chan  =  tran.open_session()
# 获取一个终端
chan.get_pty()
# 激活器
chan.invoke_shell()
  
while  True :
     # 监视用户输入和服务器返回数据
     # sys.stdin 处理用户输入
     # chan 是以前建立的通道,用于接收服务器返回信息
     readable, writeable, error  =  select.select([chan, sys.stdin, ],[],[], 1 )
     if  chan  in  readable:
         try :
             =  u(chan.recv( 1024 ))
             if  len (x)  = =  0 :
                 print ( '\r\n*** EOF\r\n' )
                 break
             sys.stdout.write(x)
             sys.stdout.flush()
         except  socket.timeout:
             pass
     if  sys.stdin  in  readable:
         inp  =  sys.stdin.readline()
         chan.sendall(inp)
  
chan.close()
tran.close()

版本二:在版本一上增长了命令补全功能和命令记录 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import  paramiko
import  sys
import  os
import  socket
import  select
import  getpass
import  termios
import  tty
from  paramiko.py3compat  import  u
  
tran  =  paramiko.Transport(( '192.168.1.21' 22 ,))
tran.start_client()
tran.auth_password( 'root' '123456' )
  
# 打开一个通道
chan  =  tran.open_session()
# 获取一个终端
chan.get_pty()
# 激活器
chan.invoke_shell()
  
  
# 获取原tty属性
oldtty  =  termios.tcgetattr(sys.stdin)
try :
     # 为tty设置新属性
     # 默认当前tty设备属性:
     #   输入一行回车,执行
     #   CTRL+C 进程退出,遇到特殊字符,特殊处理。
  
     # 这是为原始模式,不认识全部特殊符号
     # 放置特殊字符应用在当前终端,如此设置,将全部的用户输入均发送到远程服务器
     tty.setraw(sys.stdin.fileno())
     chan.settimeout( 0.0 )
  
     while  True :
         # 监视 用户输入 和 远程服务器返回数据(socket)
         # 阻塞,直到句柄可读
         r, w, e  =  select.select([chan, sys.stdin], [], [],  1 )
         if  chan  in  r:
             try :
                 =  u(chan.recv( 1024 ))
                 if  len (x)  = =  0 :
                     print ( '\r\n*** EOF\r\n' )
                     break
                 sys.stdout.write(x)
                 sys.stdout.flush()
             except  socket.timeout:
                 pass
         if  sys.stdin  in  r:
             =  sys.stdin.read( 1 )
             if  len (x)  = =  0 :
                 break
             chan.send(x)
  
finally :
     # 从新设置终端属性
     termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
  
  
chan.close()
tran.close()

版本三:windows、linux通用版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import  paramiko
import  sys
import  os
import  socket
import  getpass
 
from  paramiko.py3compat  import  u
 
# windows does not have termios...
try :
     import  termios
     import  tty
     has_termios  =  True
except  ImportError:
     has_termios  =  False
 
 
def  interactive_shell(chan):
     if  has_termios:
         posix_shell(chan)
     else :
         windows_shell(chan)
 
 
def  posix_shell(chan):
     import  select
 
     oldtty  =  termios.tcgetattr(sys.stdin)
     try :
         tty.setraw(sys.stdin.fileno())
         tty.setcbreak(sys.stdin.fileno())
         chan.settimeout( 0.0 )
         log  =  open ( 'handle.log' 'a+' , encoding = 'utf-8' )
         flag  =  False
         temp_list  =  []
         while  True :
             r, w, e  =  select.select([chan, sys.stdin], [], [])
             if  chan  in  r:
                 try :
                     =  u(chan.recv( 1024 ))
                     if  len (x)  = =  0 :
                         sys.stdout.write( '\r\n*** EOF\r\n' )
                         break
                     if  flag:
                         if  x.startswith( '\r\n' ):
                             pass
                         else :
                             temp_list.append(x)
                         flag  =  False
                     sys.stdout.write(x)
                     sys.stdout.flush()
                 except  socket.timeout:
                     pass
             if  sys.stdin  in  r:
                 =  sys.stdin.read( 1 )
                 import  json
 
                 if  len (x)  = =  0 :
                     break
 
                 if  = =  '\t' :
                     flag  =  True
                 else :
                     temp_list.append(x)
                 if  = =  '\r' :
                     log.write(''.join(temp_list))
                     log.flush()
                     temp_list.clear()
                 chan.send(x)
 
     finally :
         termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
 
 
def  windows_shell(chan):
     import  threading
 
     sys.stdout.write( "Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n" )
 
     def  writeall(sock):
         while  True :
             data  =  sock.recv( 256 )
             if  not  data:
                 sys.stdout.write( '\r\n*** EOF ***\r\n\r\n' )
                 sys.stdout.flush()
                 break
             sys.stdout.write(data)
             sys.stdout.flush()
 
     writer  =  threading.Thread(target = writeall, args = (chan,))
     writer.start()
 
     try :
         while  True :
             =  sys.stdin.read( 1 )
             if  not  d:
                 break
             chan.send(d)
     except  EOFError:
         # user hit ^Z or F6
         pass
 
 
def  run():
     default_username  =  getpass.getuser()
     username  =  input ( 'Username [%s]: '  %  default_username)
     if  len (username)  = =  0 :
         username  =  default_username
 
 
     hostname  =  input ( 'Hostname: ' )
     if  len (hostname)  = =  0 :
         print ( '*** Hostname required.' )
         sys.exit( 1 )
 
     tran  =  paramiko.Transport((hostname,  22 ,))
     tran.start_client()
 
     default_auth  =  "p"
     auth  =  input ( 'Auth by (p)assword or (r)sa key[%s] '  %  default_auth)
     if  len (auth)  = =  0 :
         auth  =  default_auth
 
     if  auth  = =  'r' :
         default_path  =  os.path.join(os.environ[ 'HOME' ],  '.ssh' 'id_rsa' )
         path  =  input ( 'RSA key [%s]: '  %  default_path)
         if  len (path)  = =  0 :
             path  =  default_path
         try :
             key  =  paramiko.RSAKey.from_private_key_file(path)
         except  paramiko.PasswordRequiredException:
             password  =  getpass.getpass( 'RSA key password: ' )
             key  =  paramiko.RSAKey.from_private_key_file(path, password)
         tran.auth_publickey(username, key)
     else :
         pw  =  getpass.getpass( 'Password for %s@%s: '  %  (username, hostname))
         tran.auth_password(username, pw)
 
     # 打开一个通道
     chan  =  tran.open_session()
     # 获取一个终端
     chan.get_pty()
     # 激活器
     chan.invoke_shell()
 
     interactive_shell(chan)
 
     chan.close()
     tran.close()
 
 
if  __name__  = =  '__main__' :
     run()

更多参见:paramoko源码 https://github.com/paramiko/paramiko 

相关文章
相关标签/搜索