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


    paramiko模块

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

    一、下载安装

    1
    2
    3
    #pycrypto,由于 paramiko 模块内部依赖pycrypto,所以先下载安装pycrypto
    tomcat@node:~$ pip install pycrypto
    tomcat@node:~$ pip install paramiko

    二、模块使用

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

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

    -->第一种

    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  

    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)基于公钥密钥连接的两种方式:

    -->第一种  

    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  

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

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

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

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

    3、实例:通过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(' *** EOF ')
                    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(' *** EOF ')
                        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(' *** EOF ')
                            break
                        if flag:
                            if x.startswith(' '):
                                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 == ' ':
                        flag = True
                    else:
                        temp_list.append(x)
                    if == ' ':
                        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. ")
     
        def writeall(sock):
            while True:
                data = sock.recv(256)
                if not data:
                    sys.stdout.write(' *** EOF *** ')
                    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 

    Alex堡垒机:http://www.cnblogs.com/alex3714/articles/5286889.html 

  • 相关阅读:
    使用webstorm来创建并且运行vue项目详细教程
    Jmeter后置处理器之Json提取器
    Linux常用命令
    Linux安装Mysql
    Linux安装JDK
    redhat6.5安装yum
    Linux安装python
    Linux安装Tomcat
    搞懂Redis协议RESP
    1TB是多大?
  • 原文地址:https://www.cnblogs.com/xuaijun/p/7825881.html
Copyright © 2020-2023  润新知