博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
堡垒机系统
阅读量:5933 次
发布时间:2019-06-19

本文共 23730 字,大约阅读时间需要 79 分钟。

需求:

  所有的用户操作日志要保留在数据库中
  每个用户登录堡垒机后,只需要选择具体要访问的设置,就连接上了,不需要再输入目标机器的访问密码
  允许用户对不同的目标设备有不同的访问权限,例:
  对10.0.2.34 有mysql 用户的权限
  对192.168.3.22 有root用户的权限
  对172.33.24.55 没任何权限
  分组管理,即可以对设置进行分组,允许用户访问某组机器,但对组里的不同机器依然有不同的访问权限  
实现的需求:
  针对不同的用户使用有权限的账户进入到指定的服务器中,进行操作,并记录下操作的命令
  首先创建表数据
  python bin\start.py syncdb
  然后用yaml模块写入数据
       例如:python bin\start.py create_hosts -f share\example\new_hosts.yml
       数据导入完毕就开始连接远程系统
       python bin\start.py start_session
       输入堡垒机的用户名和密码:(alex,alex123)
       显示出分组信息
       选择需要进入的服务器信息(不用输入服务器的账号密码)
       进入系统
测试:在ubuntu16.04下 安装有mysql5.7.21 使用python3.5 远程系统centos6.5

目录结构

数据库数据构建

 

流程图

 

代码:

1 #_*_coding:utf-8_*_2 import os,sys3 4 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))5 sys.path.append(BASE_DIR)6 7 from modules.actions import excute_from_command_line8 if __name__=="__main__":9     excute_from_command_line(sys.argv)
bin\start
1 #_*_coding:utf-8_*_ 2 from modules import views 3  4 actions = { 5     "syncdb": views.syncdb, 6     "create_hosts":views.create_hosts, 7     "create_groups":views.create_groups, 8     "create_remoteusers":views.create_remoteusers, 9     "create_userprofiles":views.create_userprofiles,10     "create_bindhosts":views.create_bindhosts,11     "start_session":views.start_session,12 }
conf\action_registers
1 import os,sys2 3 BASE_DIR =os.path.dirname(os.path.dirname(os.path.abspath(__file__)))4 5 6 ConnParams="mysql+pymysql://root:alex1234@192.168.189.129/fortdb?charset=utf8"
conf\settings
1 from sqlalchemy import Integer, ForeignKey, String, Column,Table,UniqueConstraint,DateTime  2 from sqlalchemy.ext.declarative import declarative_base  3 from sqlalchemy.orm import relationship  4 from sqlalchemy_utils import ChoiceType,PasswordType  5   6   7   8   9 Base=declarative_base() #创建数据表结构 10  11 userprofile_m2m_bindhost = Table("userprofile_m2m_bindhost",Base.metadata, 12                             Column("userprofile_id",Integer,ForeignKey("user_profile.id")), 13                             Column("bindhost_id",Integer,ForeignKey("bind_host.id")), 14                             ) 15  16 hostgroup_m2m_bindhost = Table("hostgroup_m2m_bindhost",Base.metadata, 17                             Column("hostgroup_id",Integer,ForeignKey("host_group.id")), 18                             Column("bindhost_id",Integer,ForeignKey("bind_host.id")), 19                             ) 20  21 userprofile_m2m_hostgroup = Table("userprofile_m2m_hostgroup",Base.metadata, 22                             Column("userprofile_id",Integer,ForeignKey("user_profile.id")), 23                             Column("hostgroup_id",Integer,ForeignKey("host_group.id")), 24                             ) 25  26 class Host(Base):#主机 27     __tablename__="host" 28     id =Column(Integer,primary_key=True) 29     hostname=Column(String(64),unique=True) 30     ip = Column(String(64),unique=True) 31     port = Column(Integer,default=22) 32  33  34     def __repr__(self): 35         return self.hostname 36 class HostGroup(Base):#主机组 37     __tablename__="host_group" 38     id =Column(Integer,primary_key=True) 39     groupname=Column(String(64),unique=True) 40  41     bindhosts=relationship("BindHost",secondary="hostgroup_m2m_bindhost",backref="host_groups") 42  43     def __repr__(self): 44         return self.groupname 45 class RemoteUser(Base):#系统用户 46     __tablename__ = "remote_user" 47     __tableargs__ = UniqueConstraint("username","password","auth_type",name="user_passwd_uc")#联合唯一 48     AuthTypes = [ 49         ('ssh-passwd', 'SSH/Password'), 50         ('ssh-key', 'SSH/KEY'), 51     ] 52     id = Column(Integer, primary_key=True) 53     username = Column(String(64)) 54     password = Column(String(128)) 55     auth_type=Column(ChoiceType(AuthTypes)) 56  57  58     def __repr__(self): 59         return self.username 60 class UserProfile(Base):#堡垒机用户 61     __tablename__ = "user_profile" 62     id = Column(Integer, primary_key=True) 63     username = Column(String(64),unique=True) 64     password = Column(String(128)) 65     bind_hosts = relationship("BindHost",secondary="userprofile_m2m_bindhost",backref="user_profiles") 66     host_groups = relationship("HostGroup",secondary="userprofile_m2m_hostgroup",backref="user_profiles") 67     audit_logs = relationship('AuditLog') 68  69     def __repr__(self): 70         return self.username 71 class BindHost(Base): 72     """ 73     192.168.1.0  web 74     192.168.1.1  mysql 75     """ 76     __tablename__ = "bind_host" 77     __tableargs__=UniqueConstraint("host_id","remoteuser_id",name="host_remoteuser_uc") 78     id = Column(Integer, primary_key=True) 79     host_id = Column(Integer,ForeignKey("host.id")) 80     # group_id = Column(Integer,ForeignKey("host_group.id")) 81     remoteuser_id = Column(Integer,ForeignKey("remote_user.id")) 82     host=relationship("Host",backref="bind_hosts") 83     # group=relationship("HostGroup",backref="bind_hosts") 84     remoteuser=relationship("RemoteUser",backref="bind_hosts") 85     audit_logs = relationship('AuditLog') 86  87     def __repr__(self): 88         return "<%s --- %s>"%(self.host.ip,self.remoteuser.username) 89 class AuditLog(Base): 90     __tablename__ = 'audit_log' 91     id = Column(Integer,primary_key=True) 92     user_id = Column(Integer,ForeignKey('user_profile.id')) 93     bind_host_id = Column(Integer,ForeignKey('bind_host.id')) 94     action_choices= [ 95         ('cmd','CMD'), 96         ('login','Login'), 97         ('logout','Logout'), 98     ] 99     action_type = Column(ChoiceType(action_choices))100     cmd = Column(String(255))101     date = Column(DateTime)102     user_profile = relationship("UserProfile")103     bind_host = relationship("BindHost")104 105     # def __repr__(self):106     #     return "
" %(107 # self.user_profile.username,108 # self.bind_host.host.hostname,109 # self.action_type,110 # self.date)
models\models
1 #_*_coding:utf-8_*_ 2  3  4 from conf import settings 5 from conf import action_registers 6 from modules import utils 7  8  9 def help_msg():10     print("\033[31;1mAvailable commands:\033[0m")11     for key in action_registers.actions:12         print("\t",key)13 14 15 def excute_from_command_line(argvs):16     if len(argvs) <2:17         help_msg()18         exit()19     if argvs[1] not in action_registers.actions:20         utils.print_err("Command [%s] does not exist!" % argvs[1], quit=True)21     action_registers.actions[argvs[1]](argvs[1:])
modules\actions
1 #_*_coding:utf-8_*_ 2  3 from sqlalchemy import create_engine,Table 4 from sqlalchemy.orm import sessionmaker 5  6 from conf import settings 7  8  9 engine = create_engine(settings.ConnParams)10 11 12 Session = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例13 session = Session()
modules\db_conn
1 import socket  2 import sys  3 from paramiko.py3compat import u  4 from  models import models  5 import datetime  6   7 # windows does not have termios...  8 try:  9     import termios 10     import tty 11     has_termios = True 12 except ImportError: 13     has_termios = False 14  15  16 def interactive_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording): 17     if has_termios: 18         posix_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording) 19     else: 20         windows_shell(chan) 21  22  23 def posix_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording): 24     import select 25      26     oldtty = termios.tcgetattr(sys.stdin) 27     try: 28         tty.setraw(sys.stdin.fileno()) 29         tty.setcbreak(sys.stdin.fileno()) 30         chan.settimeout(0.0) 31         cmd = '' 32  33         tab_key = False 34         while True: 35             r, w, e = select.select([chan, sys.stdin], [], []) 36             if chan in r: 37                 try: 38                     x = u(chan.recv(1024)) 39                     if tab_key: 40                         if x not in ('\x07' , '\r\n'): 41                             #print('tab:',x) 42                             cmd += x 43                         tab_key = False 44                     if len(x) == 0: 45                         sys.stdout.write('\r\n*** EOF\r\n') 46                         break 47                     sys.stdout.write(x) 48                     sys.stdout.flush() 49                 except socket.timeout: 50                     pass 51             if sys.stdin in r: 52                 x = sys.stdin.read(1) 53                 if '\r' != x: 54                     cmd +=x 55                 else: 56  57                     print('cmd->:',cmd) 58                     log_item = models.AuditLog(user_id=user_obj.id, 59                                           bind_host_id=bind_host_obj.id, 60                                           action_type='cmd', 61                                           cmd=cmd , 62                                           date=datetime.datetime.now() 63                                           ) 64                     cmd_caches.append(log_item) 65                     cmd = '' 66  67                     if len(cmd_caches)>=10: 68                         log_recording(user_obj,bind_host_obj,cmd_caches) 69                         cmd_caches = [] 70                 if '\t' == x: 71                     tab_key = True 72                 if len(x) == 0: 73                     break 74                 chan.send(x) 75  76     finally: 77         termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) 78  79      80 # thanks to Mike Looijmans for this code 81 def windows_shell(chan): 82     import threading 83  84     sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n") 85          86     def writeall(sock): 87         while True: 88             data = sock.recv(256) 89             if not data: 90                 sys.stdout.write('\r\n*** EOF ***\r\n\r\n') 91                 sys.stdout.flush() 92                 break 93             sys.stdout.write(data.decode()) 94             sys.stdout.flush() 95          96     writer = threading.Thread(target=writeall, args=(chan,)) 97     writer.start() 98          99     try:100         while True:101             d = sys.stdin.read(1)102             if not d:103                 break104             chan.send(d)105     except EOFError:106         # user hit ^Z or F6107         pass
modules\interactive
1 #_*_coding:utf-8_*_ 2  3  4  5 import sys 6 import traceback 7 from  models import models 8 import datetime 9 10 import paramiko11 try:12     import interactive13 except ImportError:14     from . import interactive15 16 17 def ssh_login(user_obj,bind_host_obj,mysql_engine,log_recording):18     # now, connect and use paramiko Client to negotiate SSH2 across the connection19     try:20         client = paramiko.SSHClient()21         client.load_system_host_keys()22         client.set_missing_host_key_policy(paramiko.WarningPolicy())23         print('*** Connecting...')24         #client.connect(hostname, port, username, password)25         print(bind_host_obj)26         client.connect(bind_host_obj.host.ip,27                        bind_host_obj.host.port,28                        bind_host_obj.remoteuser.username,29                        bind_host_obj.remoteuser.password,30                        timeout=30)31 32         cmd_caches = []33         chan = client.invoke_shell()34         print(repr(client.get_transport()))35         print('*** Here we go!\n')36         cmd_caches.append(models.AuditLog(user_id=user_obj.id,37                                           bind_host_id=bind_host_obj.id,38                                           action_type='login',39                                           date=datetime.datetime.now()40                                           ))41         log_recording(user_obj,bind_host_obj,cmd_caches)42         interactive.interactive_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording)43         chan.close()44         client.close()45 46     except Exception as e:47         print('*** Caught exception: %s: %s' % (e.__class__, e))48         traceback.print_exc()49         try:50             client.close()51         except:52             pass53         sys.exit(1)
modules\ssh_login
1 #_*_coding:utf-8_*_ 2  3 from conf import settings 4 import yaml 5 try: 6     from yaml import CLoader as Loader, CDumper as Dumper 7 except ImportError: 8     from yaml import Loader, Dumper 9 10 def print_err(msg,quit=False):11     output = "\033[31;1mError: %s\033[0m" % msg12     if quit:13         exit(output)14     else:15         print(output)16 17 18 def yaml_parser(yml_filename):19     try:20         yaml_file = open(yml_filename,'r')21         data = yaml.load(yaml_file)22         return data23     except Exception as e:24         print_err(e)
modules\utils
1 #_*_coding:utf-8_*_  2   3 from models import models  4 from modules.db_conn import engine,session  5 from modules.utils import print_err,yaml_parser  6 # from modules import common_filters  7 from modules import ssh_login  8   9  10 def syncdb(argvs): 11     print("Syncing DB....") 12     models.Base.metadata.create_all(engine) #创建所有表结构 13  14 def create_hosts(argvs): 15     """ 16     创建主机数据host 17     :param argvs: 18     :return: 19     """ 20     if "-f" in argvs: 21         host_file = argvs[argvs.index("-f")+1] 22     else: 23         print_err("invalid usage, should be:\ncreate_hosts -f 
",quit=True) 24 source =yaml_parser(host_file) 25 if source: 26 for key,val in source.items(): 27 print(key,val) 28 obj=models.Host(hostname=key,ip=val.get("ip"),port=val.get("port") or 22) 29 session.add(obj) 30 session.commit() 31 def create_groups(argvs): 32 """ 33 创建主机组hostgroup 34 :param argvs: 35 :return: 36 """ 37 if "-f" in argvs: 38 hostgroups_file=argvs[argvs.index("-f")+1] 39 else: 40 print_err("invalid usage, should be:\ncreate_groups -f
",quit=True) 41 source = yaml_parser(hostgroups_file) 42 if source: 43 for key,val in source.items(): 44 print(key,val) 45 obj = models.HostGroup(groupname=key) 46 session.add(obj) 47 session.commit() 48 def create_remoteusers(argvs): 49 """ 50 创建系统用户remote_user 51 :param argvs: 52 :return: 53 """ 54 if "-f" in argvs: 55 remoteusers_file = argvs[argvs.index("-f")+1] 56 else: 57 print_err("invalid usage, should be:\ncreate_remoteusers -f
",quit=True) 58 source =yaml_parser(remoteusers_file) 59 if source: 60 for key,val in source.items(): 61 print(key,val) 62 obj=models.RemoteUser(username=val.get("username"),password=val.get("password"),auth_type=val.get("auth_type")) 63 session.add(obj) 64 session.commit() 65 def create_userprofiles(argvs): 66 """ 67 创建堡垒机用户user_profile 68 :param argvs: 69 :return: 70 """ 71 if "-f" in argvs: 72 userprofile=argvs[argvs.index("-f")+1] 73 else: 74 print_err("invalid usage,should be:\n create_userprofiles -f
",quit=True) 75 source = yaml_parser(userprofile) 76 if source: 77 for key,val in source.items(): 78 print(key,val) 79 obj = models.UserProfile(username=key,password=val.get("password")) 80 session.add(obj) 81 if val.get("groups"): 82 groups= session.query(models.HostGroup).filter\ 83 (models.HostGroup.groupname.in_(val.get("groups"))).all() 84 print(groups) 85 if not groups: 86 print_err("none of [%s] exist in groups tables"%val.get("groups"),quit=True) 87 obj.host_groups = groups 88 session.commit() 89 def create_bindhosts(argvs): 90 ''' 91 create bind hosts 92 :param argvs: 93 :return: 94 ''' 95 if '-f' in argvs: 96 bindhosts_file = argvs[argvs.index("-f") +1 ] 97 else: 98 print_err("invalid usage, should be:\ncreate_hosts -f
",quit=True) 99 source = yaml_parser(bindhosts_file)100 if source:101 for key,val in source.items():102 #print(key,val)103 host_obj = session.query(models.Host).filter(models.Host.hostname==val.get('hostname')).first()104 assert host_obj105 for item in val['remote_users']:106 print(item )107 assert item.get('auth_type')108 if item.get('auth_type') == 'ssh-passwd':109 remoteuser_obj = session.query(models.RemoteUser).filter(110 models.RemoteUser.username==item.get('username'),111 models.RemoteUser.password==item.get('password')112 ).first()113 else:114 remoteuser_obj = session.query(models.RemoteUser).filter(115 models.RemoteUser.username==item.get('username'),116 models.RemoteUser.auth_type==item.get('auth_type'),117 ).first()118 if not remoteuser_obj:119 print_err("RemoteUser obj %s does not exist." % item,quit=True )120 bindhost_obj = models.BindHost(host_id=host_obj.id,remoteuser_id=remoteuser_obj.id)121 session.add(bindhost_obj)122 #for groups this host binds to123 if source[key].get('groups'):124 group_objs = session.query(models.HostGroup).filter(models.HostGroup.groupname.in_(source[key].get('groups') )).all()125 assert group_objs126 print('groups:', group_objs)127 bindhost_obj.host_groups = group_objs128 #for user_profiles this host binds to129 if source[key].get('user_profiles'):130 userprofile_objs = session.query(models.UserProfile).filter(models.UserProfile.username.in_(131 source[key].get('user_profiles')132 )).all()133 assert userprofile_objs134 print("userprofiles:",userprofile_objs)135 bindhost_obj.user_profiles = userprofile_objs136 #print(bindhost_obj)137 session.commit()138 139 def auth():140 """user认证"""141 count = 0142 while count<3:143 username = input("Username:").strip()144 if len(username)==0: continue145 password = input("Password:").strip()146 if len(password) ==0:continue147 user_obj = session.query(models.UserProfile).filter(models.UserProfile.username==username,148 models.UserProfile.password==password).first()149 if user_obj:150 return user_obj151 else:152 print("wrong username or password,you have %s ore chances"%(3-count-1))153 count+=1154 else:155 print_err("too many attempts")156 def welcome(user):157 WELCOME="""\033[32;1m158 ------------- Welcome [%s] Fort Machine -------------159 \033[0m"""%user.username160 print(WELCOME)161 162 def log_recording(user_obj,bind_host_obj,logs):163 '''164 flush user operations on remote host into DB165 :param user_obj:166 :param bind_host_obj:167 :param logs: list format [logItem1,logItem2,...]168 :return:169 '''170 print("\033[41;1m--logs:\033[0m",logs)171 172 session.add_all(logs)173 session.commit()174 175 def start_session(argvs):176 print("going to start session")177 user=auth()178 if user:179 welcome(user)180 print(user.bind_hosts)181 print(user.host_groups)182 exit_flag = False183 while not exit_flag:184 if user.bind_hosts:185 print("ungroups host(%s)"%len(user.bind_hosts))186 for index,groups in enumerate(user.host_groups):187 print("%s.\t%s(%s)"%(index,groups.groupname,len(groups.bindhosts)))188 choice = input("[%s]:" % user.username).strip()189 if len(choice) == 0:continue190 if choice == "z":191 print("---Groups:ungroup hosts----")192 for index,bind_host in enumerate(user.bind_hosts):193 print("%s.\t%s@%s(%s)"%(index,194 bind_host.remoteuser.username,195 bind_host.host.hostname,196 bind_host.host.ip))197 print("-----END-----")198 elif choice.isdigit():199 choice = int(choice)200 if choice < len(user.host_groups):201 print("---Group:%s---"%user.host_groups[choice].groupname)202 for index,bind_host in enumerate(user.host_groups[choice].bindhosts):203 print("%s.\t%s@%s(%s)"%(index,204 bind_host.remoteuser.username,205 bind_host.host.hostname,206 bind_host.host.ip))207 print("-----END-----")208 209 while not exit_flag:210 user_option = input("[(b)back,(q)quit,select to host login]:").strip()211 if len(user_option) ==0:continue212 if user_option=="b":break213 if user_option =="q": exit_flag=True214 if user_option.isdigit():215 user_option=int(user_option)216 if user_option
modules\views
1 bind1: 2   hostname: ubuntu-test 3   remote_users: 4     - user1: 5       username: root 6       auth_type: ssh-key 7       #password: 123 8     - user2: 9       username: alex10       auth_type: ssh-passwd11       password: alex371412   groups:13     - beijing_group14   user_profiles:15     - alex16 17 bind2:18   hostname: centos-mysql19   remote_users:20     - user1:21       username: alex22       auth_type: ssh-passwd23       password: alex371424   groups:25     - beijing_group26     - shanghai_group27 28   user_profiles:29     - rain
share\examples\new_bindhost
beijing_group:#  bind_hosts:#    - h1#    - h2  user_profiles:    - alexshanghai_group:  user_profiles:    - jack    - alex    - rain
share\examples\new_groups
1 ubuntu-test: 2   ip: 192.168.3.22 3   port: 22 4  5 redhat: 6   ip: 172.33.24.55 7   port: 3000 8  9 centos-mysql:10   ip: 10.0.2.34
share\examples\new_hosts
1 user0: 2   auth_type:  ssh-passwd 3   username: root 4   password: abc!23 5  6 user1: 7   auth_type:  ssh-passwd 8   username: root 9   password: alex!34321df10 11 user2:12   auth_type:  ssh-key13   username: root14   #password: abc!2315 16 user3:17   auth_type:  ssh-passwd18   username: alex19   password: alex3714
share\examples\new_remoteusers
1 alex: 2   password: alex123 3   groups: 4     - beijing_group 5  6   #bind_hosts: 7   #  - h1 8   #  - h2 9   #  - h310 11 jack:12   password: jack12313   groups:14     - shanghai_group15 16 rain:17   password: rain12318   #bind_hosts:19   #  - h120   #  - h3
share\examples\new_userprofiles

 

转载于:https://www.cnblogs.com/garrett0220/articles/8532178.html

你可能感兴趣的文章
排列组合【转】
查看>>
C#获取xml指定节点的值(包括子节点)
查看>>
OFFICE 2007 序列号
查看>>
android网络编程
查看>>
cf #308 div2
查看>>
Ajax_数据格式_XML
查看>>
php中mysqli 处理查询结果集的几个方法
查看>>
英文操作系统 Myeclipse Console 乱码问题
查看>>
ubuntu12.04启动错误:Checking Battery State 。。。
查看>>
非常可乐
查看>>
angular源码分析3-$provide
查看>>
vuecli结合eslint静态检查
查看>>
面向对象程序设计-设计模式的一些简单概念
查看>>
JavaScript性能优化大家多多评论谢谢
查看>>
Linq高级查询
查看>>
JQuery 遮罩层弹窗
查看>>
Python学习(20)python操作mysql数据库_安装
查看>>
序列化和反序列化
查看>>
HBase篇--搭建HBase完全分布式集群
查看>>
结对项目 sport club(二)
查看>>