Python 13:程序:堡垒机开发
Posted 水无
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 13:程序:堡垒机开发相关的知识,希望对你有一定的参考价值。
Python 13:程序:堡垒机开发
1、需求
2、表结构
3、readme
4、目录结构
5、代码
6、测试样图
一、需求
功能需求:
1、所有的用户操作日志要保留在数据库中(先存到redis中防止数据断线丢失)
2、每个用户登录堡垒机后,只需要选择具体要访问的设置,就连接上了,不需要再输入目标机器的访问密码
3、允许用户对不同的目标设备有不同的访问权限,例:
1、对192.168.1.113有mysql 用户的权限
2、对192.168.1.105有root用户的权限
3、对192.168.1.100没任何权限
4、分组管理,即可以对设置进行分组,允许用户访问某组机器,但对组里的不同机器依然有不同的访问权限
二、表结构
三、readme
1 作者:zz 2 版本: 堡垒机 示例版本 v0.1 3 开发环境: python3.6 4 5 程序介绍 6 1、所有的用户操作日志要保留在数据库中(先存到redis中防止数据断线丢失) 7 2、每个用户登录堡垒机后,只需要选择具体要访问的设置,就连接上了,不需要再输入目标机器的访问密码 8 3、允许用户对不同的目标设备有不同的访问权限,例: 9 1、对192.168.1.113有mysql 用户的权限 10 2、对192.168.1.105有root用户的权限 11 3、对192.168.1.100没任何权限 12 4、分组管理,即可以对设置进行分组,允许用户访问某组机器,但对组里的不同机器依然有不同的访问权限 13 14 使用说明 15 python3 bin/run.py start_session #启动 16 python3 bin/run.py syncdb #创建表结构 17 python3 bin/run.py create_users -f share/examples/new_user.yml #创建堡垒机账户 18 python3 bin/run.py create_groups -f share/examples/new_groups.yml #创建用户组 19 python3 bin/run.py create_hosts -f share/examples/new_hosts.yml #创建远程主机 20 python3 bin/run.py create_bindhosts -f share/examples/new_bindhosts.yml #创建绑定主机 21 python3 bin/run.py create_remoteusers -f share/examples/new_remoteusers.yml #创建远程主机登录方式 22 python3 bin/run.py view_user_record # 审计用户操作命令
四、目录结构
五、代码
1、bin
1 import os,sys 2 3 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 4 print(BASE_DIR) 5 sys.path.append(BASE_DIR) 6 7 if __name__ == \'__main__\': 8 from modules.actions import excute_from_command_line 9 excute_from_command_line(sys.argv)
2、conf
1 from modules import views 2 3 actions = { 4 \'start_session\': views.start_session, #启动s 5 \'syncdb\': views.syncdb, #创建表结构 6 \'create_users\': views.create_users, #创建堡垒机账户 7 \'create_groups\': views.create_groups, #创建用户组 8 \'create_hosts\': views.create_hosts, #创建远程主机 9 \'create_bindhosts\': views.create_bindhosts, #创建绑定主机 10 \'create_remoteusers\': views.create_remoteusers, #创建远程主机登录方式 11 \'view_user_record\': views.user_record_cmd # 审计用户操作命令 12 }
1 import os,sys 2 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 3 DB_CONN ="mysql+pymysql://root:123456@192.168.1.113:3306/bljdb?charset=utf8"
3、modules
1 from conf import settings 2 from conf import action_registers 3 from modules import utils 4 5 def help_msg(): 6 \'\'\'help\'\'\' 7 print("\\033[31;1mAvailable commands:\\033[0m") 8 for key in action_registers.actions: 9 print("\\t",key) 10 11 def excute_from_command_line(argvs): 12 if len(argvs) < 2: 13 help_msg() 14 exit() 15 if argvs[1] not in action_registers.actions: 16 utils.print_err("Command [%s] does not exist!" % argvs[1], quit=True) 17 action_registers.actions[argvs[1]](argvs[1:])
1 from modules import models 2 from modules.db_conn import engine,session 3 from modules.utils import print_err 4 5 def bind_hosts_filter(vals): 6 print(\'**>\',vals.get(\'bind_hosts\') ) #打印绑定主机信息 7 bind_hosts = session.query(models.BindHost).filter(models.Host.hostname.in_(vals.get(\'bind_hosts\'))).all() #从数据库中查询对应绑定主机信息 8 if not bind_hosts: #如果不存在相应信息 9 print_err("none of [%s] exist in bind_host table." % vals.get(\'bind_hosts\'),quit=True) #打印报错 10 return bind_hosts #返回对应bind_hosts信息 11 12 def user_profiles_filter(vals): 13 user_profiles = session.query(models.UserProfile).filter(models.UserProfile.username.in_(vals.get(\'user_profiles\'))).all() #从数据库中查询堡垒机用户信息 14 if not user_profiles: #如果不存在相应信息 15 print_err("none of [%s] exist in user_profile table." % vals.get(\'user_profiles\'),quit=True) #打印报错 16 return user_profiles #返回对应用户信息
1 from sqlalchemy import create_engine,Table 2 from sqlalchemy.orm import sessionmaker 3 from conf import settings 4 engine = create_engine(settings.DB_CONN) 5 # engine = create_engine(settings.DB_CONN,echo=True) 6 SessionCls = sessionmaker(bind=engine) #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例 7 session = SessionCls()
1 #!/usr/bin/env python 2 3 # Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com> 4 # 5 # This file is part of paramiko. 6 # 7 # Paramiko is free software; you can redistribute it and/or modify it under the 8 # terms of the GNU Lesser General Public License as published by the Free 9 # Software Foundation; either version 2.1 of the License, or (at your option) 10 # any later version. 11 # 12 # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY 13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 14 # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 # details. 16 # 17 # You should have received a copy of the GNU Lesser General Public License 18 # along with Paramiko; if not, write to the Free Software Foundation, Inc., 19 # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 21 import base64 22 import getpass 23 import os 24 import socket 25 import sys 26 import traceback 27 from paramiko.py3compat import input 28 import paramiko 29 try: 30 import interactive 31 except ImportError: 32 from . import interactive 33 # now, connect and use paramiko Client to negotiate SSH2 across the connection 34 try: 35 client = paramiko.SSHClient() 36 client.load_system_host_keys() 37 client.set_missing_host_key_policy(paramiko.WarningPolicy()) 38 print(\'*** Connecting...\') 39 client.connect(hostname, port, username, password) 40 chan = client.invoke_shell() 41 print(repr(client.get_transport())) 42 print(\'*** Here we go!\\n\') 43 interactive.interactive_shell(chan) 44 chan.close() 45 client.close() 46 47 except Exception as e: 48 print(\'*** Caught exception: %s: %s\' % (e.__class__, e)) 49 traceback.print_exc() 50 try: 51 client.close() 52 except: 53 pass 54 sys.exit(1)
1 # Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com> 2 # 3 # This file is part of paramiko. 4 # 5 # Paramiko is free software; you can redistribute it and/or modify it under the 6 # terms of the GNU Lesser General Public License as published by the Free 7 # Software Foundation; either version 2.1 of the License, or (at your option) 8 # any later version. 9 # 10 # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY 11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 12 # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 # details. 14 # 15 # You should have received a copy of the GNU Lesser General Public License 16 # along with Paramiko; if not, write to the Free Software Foundation, Inc., 17 # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 18 19 20 import socket 21 import sys 22 from paramiko.py3compat import u 23 from modules import models 24 import datetime,time 25 import redis 26 # windows does not have termios... 27 try: 28 import termios 29 import tty 30 has_termios = True 31 except ImportError: 32 has_termios = False 33 def interactive_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording): 34 \'\'\' 35 :param chan: 36 :param user_obj: 37 :param bind_host_obj: 主机 38 :param cmd_caches: 命令列表 39 :param log_recording: 日志记录 40 :return: 41 \'\'\' 42 # 判断是否是windows shell 43 if has_termios: 44 posix_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording) 45 else: 46 windows_shell(chan) 47 def posix_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording): 48 \'\'\' 49 :param chan: 50 :param user_obj: 51 :param bind_host_obj: 52 :param cmd_caches: 53 :param log_recording: 54 :return: 55 \'\'\' 56 import select 57 oldtty = termios.tcgetattr(sys.stdin) 58 try: 59 tty.setraw(sys.stdin.fileno()) 60 tty.setcbreak(sys.stdin.fileno()) 61 chan.settimeout(0.0) 62 cmd = \'\' 63 tab_key = False 64 while True: 65 r, w, e = select.select([chan, sys.stdin], [], []) 66 if chan in r: 67 try: 68 x = u(chan.recv(1024)) 69 if tab_key: 70 if x not in (\'\\x07\' , \'\\r\\n\'): 71 #print(\'tab:\',x) 72 cmd += x 73 tab_key = False 74 if len(x) == 0: 75 sys.stdout.write(\'\\r\\n*** EOF\\r\\n\') 76 # test for redis to mysql 77 break 78 sys.stdout.write(x) 79 sys.stdout.flush() 80 except socket.timeout: 81 pass 82 if sys.stdin in r: 83 x = sys.stdin.read(1) 84 if \'\\r\' != x: 85 cmd +=x 86 else: 87 print(\'cmd->:\',cmd) 88 user_record_cmd = user_obj.username + \'cmd\' 89 pool = redis.ConnectionPool(host=\'192.168.1.100\', port=6379) 90 user_record = [user_obj.id, bind_host_obj.id, \'cmd\', cmd, 91 time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())] 92 r = redis.Redis(connection_pool=pool) 93 r.lpush(user_record_cmd, user_record) 94 cmd = \'\' #清空cmd 95 if \'\\t\' == x: 96 tab_key = True 97 if len(x) == 0: 98 break 99 chan.send(x) 100 finally: 101 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) 102 103 # thanks to Mike Looijmans for this code 104 def windows_shell(chan): 105 import threading 106 sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\\r\\n\\r\\n") 107 def writeall(sock): 108 while True: 109 data = sock.recv(256) 110 if not data: 111 sys.stdout.write(\'\\r\\n*** EOF ***\\r\\n\\r\\n\') 112 sys.stdout.flush() 113 break 114 sys.stdout.write(data.decode()) 115 sys.stdout.flush() 116 writer = threading.Thread(target=writeall, args=(chan,)) 117 writer.start() 118 try: 119 while True: 120 d = sys.stdin.read(1) 121 if not d: 122 break 123 chan.send(d) 124 except EOFError: 125 # user hit ^Z or F6 126 pass
1 from sqlalchemy import create_engine,Table 2 from sqlalchemy.ext.declarative import declarative_base 3 from sqlalchemy import Column, Integer, String,ForeignKey,UniqueConstraint,UnicodeText,DateTime 4 from sqlalchemy.orm import relationship 5 from sqlalchemy import or_,and_ 6 from sqlalchemy import func 7 from sqlalchemy_utils import ChoiceType,PasswordType 8 9 Base = declarative_base() #生成一个ORM 基类 10 11 #多对多关联 12 #多对多关联:绑定主机和用户组 13 BindHost2Group = Table(\'bindhost_2_group\',Base.metadata, 14 Column(\'bindhost_id\',ForeignKey(\'bind_host.id\'),primary_key=True), 15 Column(\'group_id\',ForeignKey(\'groups.id\'),primary_key=True), 16 ) 17 #多对多关联:绑定主机和堡垒机用户 18 BindHost2UserProfile = Table(\'bindhost_2_userprofile\',Base.metadata, 19 Column(\'bindhost_id\',ForeignKey(\'bind_host.id\'),primary_key=True), 20 Column(\'uerprofile_id\',ForeignKey(\'user_profile.id\'),primary_key=True), 21 ) 22 #多对多关联:用户组和堡垒机用户 23 Group2UserProfile = Table(\'group_2_userprofile\',Base.metadata, 24 Column(\'userprofile_id\',ForeignKey(\'user_profile.id\'),primary_key=True), 25 Column(\'group_id\',ForeignKey(\'groups.id\'),primary_key=True), 26 ) 27 28 class BindHost(Base): 29 \'\'\'绑定主机(IP和用户联合唯一), 30 192.168.1.1 mysql 31 10.5.1.6 root\'\'\' 32 __tablename__ = \'bind_host\' #表名 33 id = Column(Integer,primary_key=True,autoincrement=True) 34 host_id = Column(Integer,ForeignKey(\'host.id\')) #外键关联host.id 35 remoteuser_id = Column(Integer,ForeignKey(\'remote_user.id\')) #外键关联remote_user.id 36 37 host = relationship("Host") #通过host字段查询host表中相关数据 38 remoteuser = relationship("RemoteUser") #Python之路,Day13 - 堡垒机