• 堡垒机之paramiko模块


    一、paramiko简单介绍

    场景预设:

    很多运维人员平时进行维护linux/unix主机时候,无非通过ssh到相应主机操作,那么一旦主机有成千上百台,那该如何应对,这时候我们需要批处理工具,基于python的工具有ansible、salt,而ansible的核心则是基于paramiko。

    安装:

    pip install paramiko或 easy_install paramiko

    paramiko依赖第三方的Crypto,Ecdsa和pyhton-devel

    核心组件:

    SSHclient类
    方法:

    connect():远程ssh连接并作校验

    参数:

    • hostname 连接的目标主机
    • port=SSH_PORT 指定端口
    • username=None 验证的用户名
    • password=None 验证的用户密码
    • pkey=None 私钥方式用于身份验证
    • key_filename=None 一个文件名或文件名列表,指定私钥文件
    • timeout=None 可选的tcp连接超时时间
    • allow_agent=True 是否允许连接到ssh代理,默认为True 允许
    • look_for_keys=True 是否在~/.ssh中搜索私钥文件,默认为True 允许
    • compress=False 是否打开压缩
    • sock=None
    • gss_auth=False
    • gss_kex=False
    • gss_deleg_creds=True
    • gss_host=None
    • banner_timeout=None

    exec_command():用于远程执行命令,该命令的输入与输出流为标准输入、标出输出、标准错误输出

    参数:

    • command 执行的命令
    • bufsize=-1 文件缓冲区大小
    • timeout=None 设置超时时间
    • get_pty=False

    load_system_host_key():装载系统公钥,默认为~/.ssh/known_hosts

    参数:

    • filename=None 指定本地公钥文件

    set_missing_host_key_policy():设置连接的远程主机没有本地主机密钥或HostKeys对象时的策略,目前支持三种,也就是参数只有三个。

    参数:

    • AutoAddPolicy 自动添加主机名及主机密钥到本地的known_hosts,不依赖load_system_host_key的配置。即新建立ssh连接时不需要再输入yes或no进行确认
    • WarningPolicy 用于记录一个未知的主机密钥的python警告。并接受,功能上和AutoAddPolicy类似,但是会提示是新连接
    • RejectPolicy 自动拒绝未知的主机名和密钥,依赖load_system_host_key的配置。此为默认选项

      用法:
      set_missing_host_key_policy(paramiko.AutoAddPolicy())

    SFTPClient类

    SFTPCLient作为一个sftp的客户端对象,根据ssh传输协议的sftp会话,实现远程文件操作,如上传、下载。

    方法:

    • from_transport(cls,t) 创建一个已连通的SFTP客户端通道
    • put(localpath, remotepath, callback=None, confirm=True) 将本地文件上传到服务器 参数confirm:是否调用stat()方法检查文件状态,返回ls -l的结果
    • get(remotepath, localpath, callback=None) 从服务器下载文件到本地
    • mkdir() 在服务器上创建目录
    • remove() 在服务器上删除目录
    • rename() 在服务器上重命名目录
    • stat() 查看服务器文件状态
    • listdir() 列出服务器目录下的文件
    二、使用paramiko远程执行命令

    1.使用用户名、密码直接远程登陆demo:

    #!/usr/bin/env python3
    #_*_ coding:utf-8 _*_
    #Author:wd
    import paramiko
    host='10.0.0.241'
    username='root'
    passwd='1234qwer'
    ssh=paramiko.SSHClient()#创建SSH对象
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())#设置自动添加known_host
    ssh.connect(hostname=host,username=username,password=passwd,)#连接主机
    paramiko.util.log_to_file('tran.log')#设置登陆数据传输日志
    stdin,stdout,stderr=ssh.exec_command('ifconfig',timeout=10)#执行命令设置超时时间
    stdout,stderr=stdout.read(),stderr.read()
    res=stdout if stdout else stderr
    print(res.decode())
    ssh.close()#关闭连接

    2.使用公钥私钥远程连接

    demo:

    #!/usr/bin/env python3
    #_*_ coding:utf-8 _*_
    #Author:wd
    host='172.16.11.35'
    username='root'
    
    import paramiko
    ssh=paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())#设置自动添加known_hosts,一定要在connection之前
    ssh.connect(username=username,hostname=host,pkey=paramiko.RSAKey.from_private_key_file('/Users/fangchaoliu/.ssh/id_rsa'))
    stdin,stdout,stderr=ssh.exec_command('ifconfig')
    stdout,stderr=stdout.read(),stderr.read()
    res=stdout if stdout else stderr
    print(res.decode())

    3.使用SSHclient封装transport

    #!/usr/bin/env python3
    #_*_ coding:utf-8 _*_
    #Author:wd
    host=('172.16.11.35',22)
    user='root'
    passwd='1234qwer'
    import paramiko
    tran=paramiko.Transport(host)#host是一个tuple,分别是主机和port
    tran.connect(username=user,password=passwd)
    ssh=paramiko.SSHClient()
    ssh._transport=tran
    stdin,stdout,stderr=ssh.exec_command('df -h')
    stdout,stderr=stdout.read(),stderr.read()
    res=stdout if stdout else stderr
    print(res.decode())
    tran.close()

    私钥是字符串:

    import paramiko
    from io import StringIO
    
    key_str = """-----BEGIN RSA PRIVATE KEY-----
    MIIEpQIBAAKCAQEAq7gLsqYArAFco02/55IgNg0r7NXOtEM3qXpb/dabJ5Uyky/8
    NEHhFiQ7deHIRIuTW5Zb0kD6h6EBbVlUMBmwJrC2oSzySLU1w+ZNfH0PE6W6fans
    H80whhuc/YgP+fjiO+VR/gFcqib8Rll5UfYzf5H8uuOnDeIXGCVgyHQSmt8if1+e
    7hn1MVO1Lrm9Fco8ABI7dyv8/ZEwoSfh2C9rGYgA58LT1FkBRkOePbHD43xNfAYC
    tfLvz6LErMnwdOW4sNMEWWAWv1fsTB35PAm5CazfKzmam9n5IQXhmUNcNvmaZtvP
    c4f4g59mdsaWNtNaY96UjOfx83Om86gmdkKcnwIDAQABAoIBAQCnDBGFJuv8aA7A
    ZkBLe+GN815JtOyye7lIS1n2I7En3oImoUWNaJEYwwJ8+LmjxMwDCtAkR0XwbvY+
    c+nsKPEtkjb3sAu6I148RmwWsGncSRqUaJrljOypaW9dS+GO4Ujjz3/lw1lrxSUh
    IqVc0E7kyRW8kP3QCaNBwArYteHreZFFp6XmtKMtXaEA3saJYILxaaXlYkoRi4k8
    S2/K8aw3ZMR4tDCOfB4o47JaeiA/e185RK3A+mLn9xTDhTdZqTQpv17/YRPcgmwz
    zu30fhVXQT/SuI0sO+bzCO4YGoEwoBX718AWhdLJFoFq1B7k2ZEzXTAtjEXQEWm6
    01ndU/jhAasdfasdasdfasdfa3eraszxqwefasdfadasdffsFIfAsjQb4HdkmHuC
    OeJrJOd+CYvdEeqJJNnF6AbHyYHIECkj0Qq1kEfLOEsqzd5nDbtkKBte6M1trbjl
    HtJ2Yb8w6o/q/6Sbj7wf/cW3LIYEdeVCjScozVcQ9R83ea05J+QOAr4nAoGBAMaq
    UzLJfLNWZ5Qosmir2oHStFlZpxspax/ln7DlWLW4wPB4YJalSVovF2Buo8hr8X65
    lnPiE41M+G0Z7icEXiFyDBFDCtzx0x/RmaBokLathrFtI81UCx4gQPLaSVNMlvQA
    539GsubSrO4LpHRNGg/weZ6EqQOXvHvkUkm2bDDJAoGATytFNxen6GtC0ZT3SRQM
    WYfasdf3xbtuykmnluiofasd2sfmjnljkt7khghmghdasSDFGQfgaFoKfaawoYeH
    C2XasVUsVviBn8kPSLSVBPX4JUfQmA6h8HsajeVahxN1U9e0nYJ0sYDQFUMTS2t8
    RT57+WK/0ONwTWHdu+KnaJECgYEAid/ta8LQC3p82iNAZkpWlGDSD2yb/8rH8NQg
    9tjEryFwrbMtfX9qn+8srx06B796U3OjifstjJQNmVI0qNlsJpQK8fPwVxRxbJS/
    pMbNICrf3sUa4sZgDOFfkeuSlgACh4cVIozDXlR59Z8Y3CoiW0uObEgvMDIfenAj
    98pl3ZkCgYEAj/UCSni0dwX4pnKNPm6LUgiS7QvIgM3H9piyt8aipQuzBi5LUKWw
    DlQC4Zb73nHgdREtQYYXTu7p27Bl0Gizz1sW2eSgxFU8eTh+ucfVwOXKAXKU5SeI
    +MbuBfUYQ4if2N/BXn47+/ecf3A4KgB37Le5SbLDddwCNxGlBzbpBa0=
    -----END RSA PRIVATE KEY-----"""
    
    private_key = paramiko.RSAKey(file_obj=StringIO(key_str))
    transport = paramiko.Transport(('10.0.1.40', 22))
    transport.connect(username='wupeiqi', pkey=private_key)
    
    ssh = paramiko.SSHClient()
    ssh._transport = transport
    
    stdin, stdout, stderr = ssh.exec_command('df')
    result = stdout.read()
    
    transport.close()
    
    print(result)
    三、使用paramiko上传、下载文件

     下载上传,使用SSHclient封装的Transport,注意(连接建立完成以后需要关闭通道tran.close())

    通过用户名密码demo:

    #!/usr/bin/env python3
    #_*_ coding:utf-8 _*_
    #Author:wd
    host=('172.16.11.35',22)
    user='root'
    passwd='1234qwer'
    import paramiko
    tran=paramiko.Transport(host)#host是一个tuple,分别是主机和port
    tran.connect(username=user,password=passwd)
    sftp=paramiko.SFTPClient.from_transport(tran)
    status=sftp.put('socket_client.py','/usr/local/socket_client.py')#上传文件
    sftp.get('/root/skip.sh','skip.sh')#下载文件
    print(status)#打印传输状态
    tran.close()#关闭连接

    通过公钥私钥方式demo:

    #!/usr/bin/env python3
    #_*_ coding:utf-8 _*_
    #Author:wd
    import paramiko
    host=('172.16.11.35',22)
    user='root'
    private_key=paramiko.RSAKey.from_private_key_file('/Users/fangchaoliu/.ssh/id_rsa')
    tran=paramiko.Transport(host)#host是一个tuple,分别是主机和port
    tran.connect(username=user,pkey=private_key)
    sftp=paramiko.SFTPClient.from_transport(tran)
    status=sftp.put('socket_client.py','/usr/local/socket_client.py')#上传文件
    sftp.get('/root/skip.sh','skip.sh')#下载文件
    print(status)#打印传输状态
    tran.close()#关闭连接

    简单跳板机实现:

    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:
                        x = 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:
                    x = sys.stdin.read(1)
                    import json
    
                    if len(x) == 0:
                        break
    
                    if x == '	':
                        flag = True
                    else:
                        temp_list.append(x)
                    if x == '
    ':
                        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:
                d = 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()
    demo

     带密钥方式:

    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:
                        x = 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:
                    x = sys.stdin.read(1)
                    import json
    
                    if len(x) == 0:
                        break
    
                    if x == '	':
                        flag = True
                    else:
                        temp_list.append(x)
                    if x == '
    ':
                        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:
                d = 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()
    demo
  • 相关阅读:
    poj1811
    linux系统nginx如何部署vue项目(附详细步骤)
    vue中设置input输入框的值为正整数,不能为负数和小数
    nginx(windows)如何部署vue项目
    vue多个表单验证(Promise.all)
    vue 路由传递参数,刷新页面 数据变成 [Object object]
    vue中解决父组件给子组件传值,子组件拿不到值
    vue项目封装axios请求的get、post、put、delect请求
    vue代码格式化-eslint
    vue后台管理项目PC端页面自适应
  • 原文地址:https://www.cnblogs.com/wdliu/p/6858918.html
Copyright © 2020-2023  润新知