一 堡垒机的架构

堡垒机的核心架构通常如下图所示:

基于python的堡垒机

 

二、堡垒机的一般执行流程

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

注:在linux中,通过配置用户的.brashrc文件,实现ssh登陆后自动执行脚本,如:/usr/bin/env python /home/jack/jump.py,完成业务操作后logout自动退出。

  另外,想要正确可靠的发挥堡垒机的作用,只靠堡垒机本身是不够的, 还需要对用户进行安全上的限制,堡垒机部署后,要确保你的系统达到以下条件:

  • 所有人包括运维、开发等任何需要访问业务系统的人员,只能通过堡垒机访问业务系统
    • 回收所有对业务系统的访问权限,做到除了堡垒机管理人员,没有人知道业务系统任何机器的登录密码
    • 网络上限制所有人员只能通过堡垒机的跳转才能访问业务系统 
  • 确保除了堡垒机管理员之外,所有其它人对堡垒机本身无任何操作权限,只有一个登录跳转功能
  • 确保用户的操作纪录不能被用户自己以任何方式获取到并篡改,达到安全审计的作用。  

三、python实现堡垒机

通过第三方模块paramiko,在python中可以很方便的实现堡垒机的基础功能,还可以通过django框架实现web管理和维护。

基本架构如下:

基于python的堡垒机

 

1. 简单的实现版本

  该版本较简单,只能输入一行命令,回车,然后接收主机返回的信息,并打印。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import paramiko
import sys
import os
import socket
import select
import getpass
from paramiko.py3compat import u  # python2.x中不需要这一行
 
 
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()
 
while True:
    # 监视用户输入和服务器返回数据
    # sys.stdin 处理用户输入
    # chan 是之前创建的通道,用于接收服务器返回信息
    # select模块是IO多路复用模块,功能强大,无处不在,你值得学习和记忆!
    readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1)
    if chan in readable:
        try:
            x = u(chan.recv(1024))  # python2.x中直接接收就可以,不要u
            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()
简单版本

相关文章: