热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

paramiko模块实现堡垒机

通过SSHClient执行命令通过用户名密码验证importparamiko#创建SSH对象sshparamiko.SSHClient()#自动添加

通过SSHClient 执行命令

"""通过用户名密码验证"""

import paramiko

# 创建 SSH 对象
ssh = paramiko.SSHClient()
# 自动添加key到 known_hosts
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='10.211.55.5', port=22, username='root', password='111111')
# 执行命令
stdin, stdout, stderr = ssh.exec_command('ls')
# 获取命令结果
result = stdout.readlines()
print(result)
# 关闭连接
ssh.close()
"""通过秘钥验证"""

import paramiko

private_key = paramiko.RSAKey.from_private_key_file('/Users/wenchong/.ssh/id_rsa')

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 使用秘钥连接
ssh.connect(hostname='10.211.55.5', port=22, username='root', pkey=private_key)
stdin, stdout, stderr = ssh.exec_command('ls')
result = stdout.readlines()
print(result)
ssh.close()
"""SSHClient 封装 Transport"""

import paramiko

transport = paramiko.Transport(('10.211.55.5', 22))
# 通过密码验证
# transport.connect(username='root', password='111111')

# 通过秘钥验证
private_key = paramiko.RSAKey.from_private_key_file('/Users/wenchong/.ssh/id_rsa')
transport.connect(username='root', pkey=private_key)

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command('ls')
result = stdout.readlines()
print(result)
transport.close()

通过 SFTPClient 上传下载文件

"""上传下载文件"""

import paramiko

transport = paramiko.Transport(('10.211.55.5', 22))
# 通过密码验证
# transport.connect(username='root', password='111111')

# 通过秘钥验证
private_key = paramiko.RSAKey.from_private_key_file('/Users/wenchong/.ssh/id_rsa')
transport.connect(username='root', pkey=private_key)

sftp = paramiko.SFTPClient.from_transport(transport)
# 将本地的 /tmp/local.py 上传到服务器,并重命名为 /tmp/remote.py
sftp.put('/tmp/local.py', '/tmp/remote.py')
# 从服务器的 /tmp/remote.py 下载文件到本地,并重命名为 /tmp/local.py
sftp.get('/tmp/remote.py', '/tmp/local.py')

transport.close()

堡垒机的实现

1、在所有的服务器上创建账号,用户通过堡垒机管理该服务器

2、用户使用用户名密码登陆到堡垒机,并根据登陆的用户信息,在数据库中查找用户可管理的主机列表

3、用户选择服务器,并自动登陆

4、用户操作,并记录操作日志

 

在用户的 .bashrc 文件的最后一行执行该脚本,并在执行完成后退出shell。

echo -e "python3.5 demo.py\nlogout" .bashrc

# /user/bin/env python
__author__ = 'wenchong'

"""demo.py"""

import getpass
import paramiko
import os
import sys
import socket
import logging

from paramiko.py3compat import u

# windows系统无 termios 模块
try:
    import termios
    import tty
    has_termios = True
except ImportError:
    has_termios = False


# 成功登陆的用户名
USERNAME = None


def log_write(msg):
    """记录日志"""
    fh = logging.FileHandler(filename='log', mode='a', encoding='utf-8')
    fmt = logging.Formatter(fmt='%(asctime)s - {} - %(name)s - %(message)s'.format(USERNAME))
    fh.setFormatter(fmt)
    logger = logging.Logger("Command", level=logging.DEBUG)
    logger.addHandler(fh)
    logger.info(msg)


def interactive_shell(channel):
    """启动shell"""
    if has_termios:
        posix_shell(channel)
    else:
        windows_shell(channel)


def login():
    """模拟登陆堡垒机"""
    while True:
        username = input("Username: ")
        password = getpass.getpass("Password: ")

        if (username == 'wen' and password == '123') or (username == 'chong' and password == '123'):
            global USERNAME
            USERNAME = username
            return username
        else:
            print("Username or Password is error. Please try again.")


def select_host(username):
    """根据登陆的用户名列出主机并选择"""
    hosts = {
        'wen': [
                '10.211.55.5',
                '192.168.165.130',
            ],
        'chong': [
                '10.211.55.6',
                '10.211.55.7',
            ]
    }

    hosts_list = hosts.get(username)

    for index, host in enumerate(hosts_list, 1):
        print(index, host)

    while True:
        try:
            user_input = input("Please select: ")
            host = hosts_list[int(user_input) - 1]
            return host
        except KeyboardInterrupt as e:
            exit("\n")
        except Exception as e:
            continue


def posix_shell(channel):
    """启用 Linux shell"""
    import select

    # 获取之前的 tty
    fd = sys.stdin.fileno()
    oldtty = termios.tcgetattr(fd)

    try:
        tty.setraw(fd)
        tty.setcbreak(fd)

        channel.settimeout(0.0)

        command_list = []
        tab_flag = False

        while True:
            r_list, w_list, e_list = select.select([channel, sys.stdin], [], [], 1)
            if channel in r_list:
                try:
                    x = u(channel.recv(1024))
                    if len(x) == 0:
                        print("\r\n*** EOF\r\n")
                        break

                    # 输入 tab 后的返回值如果不换行则记录为命令[补全命令]
                    if tab_flag:
                        if not x.startswith("\r\n"):
                            command_list.append(x)
                        tab_flag = False

                    sys.stdout.write(x)
                    sys.stdout.flush()
                except socket.timeout:
                    pass

            if sys.stdin in r_list:
                x = sys.stdin.read(1)

                if len(x) == 0:
                    break

                # 用户输入 tab 键
                if x == "\t":
                    tab_flag = True
                else:
                    command_list.append(x)

                if x == '\r':
                    command = ''.join(command_list)
                    # 发送的命令为空,即只有回车时忽略记录日志
                    if command != '\r':
                        log_write(command)
                    command_list.clear()

                channel.sendall(x)

    finally:
        # 恢复之前的 tty
        termios.tcsetattr(fd, termios.TCSADRAIN, oldtty)


def windows_shell(channel):
    """windows shell, 未验证"""
    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=(channel,))
    writer.start()

    try:
        while True:
            d = sys.stdin.read(1)
            if not d:
                break
            channel.send(d)
    except EOFError:
        # user hit ^Z or F6
        pass


def login_server(host):
    """通过 key 认证登陆到远程服务器"""
    transport = paramiko.Transport((host, 22))
    transport.start_client()

    default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
    private_key = paramiko.RSAKey.from_private_key_file(default_path)
    transport.auth_publickey(username='root', key=private_key)

    # 打开一个通道
    channel = transport.open_session()
    # 获取一个终端
    channel.get_pty()
    # 激活器
    channel.invoke_shell()

    return channel


def main():
    username = login()
    if username:
        host = select_host(username)

        channel = login_server(host)

        interactive_shell(channel)


if __name__ == '__main__':

    main()
堡垒机脚本 demo.py

 


推荐阅读
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了Shell中for命令的基本格式和用法,通过提供一个值列表来迭代执行一系列命令。同时还介绍了如何读取列表中的值,并给出了for命令与其他命令的结合使用示例。 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 我正在尝试解析具有已知格式的文本文件,但是每一行都不是100%一致。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • 本文详细介绍了git常用命令及其操作方法,包括查看、添加、提交、删除、找回等操作,以及如何重置修改文件、抛弃工作区修改、将工作文件提交到本地暂存区、从版本库中删除文件等。同时还介绍了如何从暂存区恢复到工作文件、恢复最近一次提交过的状态,以及如何合并多个操作等。 ... [详细]
  • 本文介绍了解决vscode在mac下无法跳转到引用的问题的方法。具体问题表现为无法通过command + 点击module.js来跳转至该文件,同时import时也没有智能提示。文章提供了一些解决方法,如检查插件是否安装正确等。希望能帮助到遇到相同问题的朋友们。 ... [详细]
  • Postgresql备份和恢复的方法及命令行操作步骤
    本文介绍了使用Postgresql进行备份和恢复的方法及命令行操作步骤。通过使用pg_dump命令进行备份,pg_restore命令进行恢复,并设置-h localhost选项,可以完成数据的备份和恢复操作。此外,本文还提供了参考链接以获取更多详细信息。 ... [详细]
  • 从U ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
author-avatar
雨水-_-打湿我的脸_950
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有