python、golang开发堡垒机系统

jumpserver是个很受欢迎的开源堡垒机系统,功能丰富,开箱即用。最近公司有需求想要二次开发,调研过程中发现改造还是比较困难的,主要有以下几个问题:

  • 部署麻烦,有core、koko、lion、luna、lina等服务
  • 分别用了python、golang、nodejs语言开发
  • core服务使用了django-rest-framework库,以配置为主,修改逻辑比较困难
  • 部分前后端未分离
  • 核心的lion未开源
  • celery处理异步任务,很多任务都不是必要的
  • ansbile推送系统用户等,需要服务器和网络支持
  • 控制台权限管理不清晰

综上原因,改造比较困难,因此想自己开发一个。
虽然后来发现了更简单轻量的next-terminal,但本着学习的目的,还是自己造了轮子。

堡垒机系统的关键在于通过网页上连接服务器,因此在此记录下方案。
开始想用python实现后端,用过flask + paramiko + flask-socketio方案,尝试下来发现性能不行,ssh延迟比较大。
后来改成了fastapi + asyncssh,效果还行。
因为公司内用golang多些,最终用Gin框架来实现后端。
rdp协议连接用了Guacamole
前端用了vue + xterm + socketio

paramiko连接ssh部分代码:
import paramiko
import threading
import io

class SshClient:

    def __init__(self, ip, port, username, psd=None, pkey=None):
        self.ip = ip
        self.port = port
        self.username = username  # 用户
        self.psd = psd  #密码
        self.pkey = pkey  # 私钥内容
        self.channel = None

    def send(self, msg):
        '''
        websocket接收到网页发来的消息后,调用此函数发给ssh通道
        '''
        if self.channel:
            return self.channel.send(msg)

    def listening(self):
        while True:
            ret = self.channel.recv(10240)
            print('>>', ret)
            # 收到ssh通道返回的消息,通过websocket返回给网页

    def start(self):
        client = paramiko.SSHClient()
        client.load_system_host_keys()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        # 私钥登录
        if self.pkey: 
            pkey = paramiko.RSAKey.from_private_key(io.StringIO(self.pkey))
            client.connect(hostname=self.ip, port=self.port, username=self.username, pkey=pkey)
            self.channel = client.invoke_shell()
        # 密码登录
        else:  
            client.connect(hostname=self.ip, port=self.port, username=self.username, password=self.psd)
            self.channel = client.invoke_shell()

        threading._start_new_thread(self.listening, ())
asyncssh连接ssh部分代码:
import asyncio, asyncssh, sys
from fastapi import WebSocket


class MySSHClientSession(asyncssh.SSHClientSession):
    def __init__(self, consumer):
        self.consumer = consumer

    def data_received(self, data, datatype):
        asyncio.ensure_future(self.consumer.send(data))

    def connection_lost(self, exc):
        if exc:
            print('SSH session error: ' + str(exc), file=sys.stderr)


class MySSHClient(asyncssh.SSHClient):
    def connection_made(self, conn):
        print('Connection made to %s.' % conn.get_extra_info('peername')[0])

    def auth_completed(self):
        print('Authentication successful.')


class WsClient():

    def __init__(self, websocket: WebSocket, client_id=None):
        self.websocket = websocket
        self.client_id = client_id
        self.chan = None
        self.conn = None

    async def close(self):
        if self.conn:
            self.conn.close()
        if self.chan:
            self.chan.close()
        self.conn = None
        self.chan = None
        self.websocket = None

    async def send(self, text):
        await self.websocket.send_text(text)

    def write(self, text):
        if self.chan and self.chan._send_state == 'open':
            self.chan.write(text)
        else:
            print("no channel")

    async def run_client(self):
        self.conn, client = await asyncssh.create_connection(MySSHClient, '192.168.64.8', port=22, username='root', password=' ', known_hosts=None)
        self.chan, _ = await self.conn.create_session(lambda:MySSHClientSession(self), term_type='xterm')

前端部分截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用docker运行体验
docker run -itd -p 8080:80 qf0129/jumpman:latest  
github地址

https://github.com/qf0129/jumpman

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值